Skip to main content

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):
    1. Create new version.
    2. Run validation.
    3. If Valid: Publish immediately (set as active) if the user has the required capability (e.g., questions.write).
    4. 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.read or questions.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:
    1. Clones parent evaluations to new versions pointing to the new question.
    2. Updates scheduled (not started) assignments to point to the new evaluation version.
    3. Audit: Emits an audit_logs event 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 usage check returns completed_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.