Communication and Engagement - FreeUKGen/MyopicVicar GitHub Wiki

Communication & Engagement

This domain covers how the public and logged-in users get in touch with the site, and how coordinators respond. It's five resources that look similar on the surface (all have "submit a form, coordinator reviews it" energy) but split into two real groups:

Pages

  • Contact-System — the public "Contact Us" form, with a full submission-to-reply flowchart
  • Feedback-System — general site feedback / bug reports, Contact's structural twin
  • Message-System — the shared reply/thread substrate behind Contact and Feedback, plus internal coordinator messaging
  • Donate-Cta-Feedback — donate call-to-action feedback (write-once, no reply workflow)
  • Reminder-To-Donate — "remind me later" lead capture (write-once, no reply workflow)

Architecture at a glance

flowchart TD
    A[Public visitor] --> C[Contact: contacts#create]
    B[Logged-in user] --> F[Feedback: feedbacks#create]

    C --> C1[Routed by contact_type / role]
    F --> F1[Routed by feedback_type / role]

    C1 --> U[UseridDetail coordinator lookup<br/>with fallback chain]
    F1 --> U

    U --> C2[UserMailer.contact_action_request]
    U --> F2[UserMailer feedback equivalent]

    C2 --> M[Coordinator replies via Message<br/>nature: 'contact' / 'feedback'<br/>source_*_id set]
    F2 --> M

    M --> M2[Message can itself be replied to<br/>source_message_id - self-referential thread]

    D[Public visitor] --> DCF[DonateCtaFeedback: write-once,<br/>emails and stops, no Message thread]
    R[Public visitor] --> RTD[ReminderToDonate: write-once,<br/>emails and stops, no Message thread]
Loading

DonateCtaFeedback and ReminderToDonate sit outside the main reply chain: they're standalone forms that just email someone and stop. No Message thread, no archive/keep, no coordinator routing table.

Known technical debt (cross-cutting)

  • The 12-level nested cascade. archive, restore, update_keep, and update_unkeep on Contact, Feedback, and Message are all implemented as an identical, manually-unrolled 12-level-deep each block walking reply-of-reply-of-reply chains (Contact.message_replies(id).each do |r1| ... Contact.message_replies(r1.id).each do |r2| ... twelve levels deep). It's clearly meant to recurse through an arbitrarily deep thread but is hardcoded to exactly 12 levels — a reply thread deeper than that won't be fully archived/restored/kept. Copy-pasted across all three models rather than shared. A real recursive method (or a shared Threaded/Archivable concern) would fix this properly and is a good first refactor if you're looking for one.
  • Button-label-driven control flow. MessagesController#create dispatches on the literal text of the submit button (params[:commit]). Renaming a button in a view silently breaks its handler.
  • String-parsed recipient identity. Message#extract_coordinators/extract_others parse structured data back out of a human-readable label string rather than carrying id and label separately.
  • Session-driven redirects. Several return_after_* methods across these controllers branch on session state (session[:message_base], session[:archived_contacts]) rather than request params, which can cause navigation to land somewhere unexpected if the session is stale.
  • Naming/param mismatches: DonateCtaFeedbackController uses params.require(:feedback); ReminderToDonateController#index sets @feedbacks. Neither is a bug per se, but both are traps if you go looking for the "obviously right" variable/param name.
⚠️ **GitHub.com Fallback** ⚠️