ADR-0009: SMB-First Unified UX & Safe Immutability
Status
Proposed
Context
Evalium targets SMB users who often perform multiple roles (Author, Proctor, Admin) simultaneously.
- Problem 1: Enterprise "Workspace Switchers" create high friction for users wearing multiple hats.
- Problem 2: Our backend enforces strict immutable versioning. Exposing raw version management (Draft → v1 → v2 → Publish) is too complex for SMBs who just want to "fix a typo."
- Problem 3: "Quick Fixes" carry a risk of unintended consequences (e.g., changing an exam that is currently live).
Decisions
1. Unified Admin with Contextual Bridges
We will NOT implement a hard "Workspace Switcher."
- Operational Inbox: The home screen MUST be an aggregated dashboard of tasks across all roles (e.g., "Needs Marking", "Live Sessions").
- Peek Navigation: Atomic entities (Users, Questions) MUST open in Slide-over Panels (Peeks) to preserve context. Composite entities (Evaluations, Assignments) use full-page navigation.
2. The "Save" Abstraction (The "Shopify" Rule)
The UI MUST hide versioning complexity for standard editing flows, but safely.
- Button Label: Use "Save Changes" or "Update."
- Backend Behaviour (Auto-Publish):
- Create new version.
- Run validation.
- If Valid: Publish immediately (set as active) if the user has the required capability (e.g.,
questions.write). - If Invalid: Save as Draft and prompt user to fix errors.
- Version Visibility: Version numbers (v1, v2) MUST be hidden in a "History" tab, not shown on the main dashboard.
3. Backend-Driven Impact Checks
The Frontend MUST NOT calculate impact. It must query the Backend.
- API Pattern: Before saving, the UI calls
GET /questions/\{id\}/usage. This is a new endpoint surface requiring read access (e.g.,questions.readorquestions.write). - Response: Backend returns usage counts for:
published_evaluations(Safe to ripple update)scheduled_assignments(Safe to ripple update with audit)active_sessions(UNSAFE - Cannot be updated)completed_submissions(UNSAFE - Cannot be updated)
- Definition of "Active Session": Any session created for an assignment that is not terminal (submitted/expired). These sessions are strictly bound to a frozen evaluation snapshot and cannot be mutated.
4. Cascading Updates ("Ripple Effect")
If the Impact Check reveals usage in Published Evaluations or Scheduled Assignments:
- The Prompt: The UI MUST prompt: "Update future runs & unstarted assignments?" (Avoid implying active sessions will change).
- The Action: The backend executes a transactional Ripple Update:
- Clones parent evaluations to new versions pointing to the new question.
- Updates
scheduled(not started) assignments to point to the new evaluation version. - Audit: Emits an
audit_logsevent for every assignment updated.
- Security: This command MUST be gated by capabilities for both content writing (e.g.,
questions.write) AND assignment management. - Constraint: This MUST NEVER mutate in-progress sessions or snapshots.
5. Remediation vs. Editing
We strictly separate "Fixing the Content" from "Fixing the Score."
- Editing: Applies to future attempts and unstarted assignments only.
- Remediation: If the
usagecheck returnscompleted_submissions > 0, the UI MUST explicitly display a link to the Results Remediation tool. - Invariant: We never retroactively mutate snapshots for past or active sessions.
Consequences
- Safety: "Impact" is determined by the Source of Truth (Database), not the client.
- Data Integrity: In-progress candidates are protected by the Snapshot isolation rule.
- UX: Users feel they are "fixing the typo everywhere," but the system maintains strict version history.