Skip to content

feat(admin): form approval workflow before publishing #1975

@cdcore09

Description

@cdcore09

Summary

Require an explicit admin approval step before a form built in the admin UI becomes available for public submission. Authors compose drafts, designated approvers review and publish (or send back with comments), and an audit trail captures every state transition.

Requirements

  • Form lifecycle states: `draft` → `in_review` → `published` (+ `changes_requested`, `archived`)
  • Submit-for-review action available to form authors
  • Approval queue view in the admin (`/forms/queue` or similar) listing forms awaiting review
  • Approve / request-changes actions, both gated by a new policy (e.g., `canApproveForms` — likely super_admin only)
  • Reviewers can leave a comment when requesting changes; comment surfaces to the author
  • Each state transition writes to `audit_log` with actor, before-state, after-state, and any comment
  • Author cannot approve their own form (self-promotion guard analogous to PATCH role)
  • Published forms cannot be edited in place — editing creates a new draft revision that must be re-approved

Context

Form misconfiguration (wrong required fields, leaky PII collection, broken submit URL) is a real failure mode once forms drive event registration and surveys. A required-approval gate gives the leadership team a check before anything lands on the public site.

This depends on #1974 (the form builder integration) being in place so there's something to approve in the first place.

Implementation Notes

  • The state machine can live on the `forms` table as a status enum + a small `form_reviews` table for the comment/transition history.
  • The audit_log entries pattern follows the existing merge / unmerge / role-change conventions on `/admin/users/*`.
  • Consider whether "approve" requires two approvers (review by one, publish by another) — probably overkill for v1; single approver per form.
  • Edit-after-publish creates a draft revision — model this as a new row pointing back to the published form via `parent_form_id`, or as a versioned `form_revisions` table; pick whichever fits the builder library's schema model best.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions