# Contact Edit Approval System — Design ## Goal Allow registered users to suggest corrections to any contact's core fields. Edits enter an admin approval queue with field-by-field diff view. Users receive email notification when their edit is approved or rejected. ## Data Model New `contact_edits` table: | Field | Type | Purpose | |-------|------|---------| | id | binary_id | PK | | contact_id | references contacts | Target contact | | user_id | references users | Submitter | | proposed_changes | :map (JSONB) | Only changed fields, e.g. `%{"grid1" => "EM13kk"}` | | status | Ecto.Enum (:pending, :approved, :rejected) | Review state | | admin_note | :string | Optional admin explanation | | reviewed_by_id | references users | Admin who acted | | reviewed_at | :utc_datetime | When reviewed | | timestamps | | inserted_at = submission time | Schema: `ContactEdit` in `lib/microwaveprop/radio/contact_edit.ex`. ## Editable Fields station1, station2, grid1, grid2, band, mode, qso_timestamp. Not editable: pos1/pos2, distance_km, enrichment statuses (computed fields). ## User Flow - Contact detail page (`/contacts/:id`): logged-in users see "Suggest Edit" button. - Clicking opens inline form pre-filled with current values. - On submit: backend diffs against current contact, stores only changed fields. - Validation: same rules as submission_changeset (callsign format, grid format, valid band/mode). - Reject if nothing changed. - Flash confirmation on success. Badge shows "pending edit" if user has one. ## Admin Flow - `/admin/contact-edits`: pending edits, newest first. - Columns: contact link, submitter callsign, submitted at, fields changed. - Review view: field-by-field diff table (current vs proposed), only changed fields. - Optional note textarea, Approve/Reject buttons. - Approve: update contact fields, re-enqueue enrichment if grid1/grid2/band changed. - Reject: no contact changes. - Nav badge shows pending count. ## Multiple Edits Independent queue — multiple edits per contact allowed. Admin reviews each separately. ## Email Notifications Plain text via Swoosh (existing mailer). Sent on approve or reject. Includes: - Contact identifier (station1 <-> station2, band, date) - What was proposed - Decision (approved/rejected) - Admin note if provided ## Re-enrichment On approve, if any of grid1/grid2/band changed: recalculate pos1/pos2 from grids, clear distance_km (will be recomputed), re-enqueue weather/HRRR/terrain/IEMRE jobs.