Skip to content

feat(publishers): make adding a ministry-school student a first-class flow #212

Description

@mindsers

Problem

There is no logical, easy way for an admin to add a ministry-school student (a current Member of the congregation who attends but isn't yet a declared publisher). Today:

  1. /publishers/new is the only entry point on the Publishers screen. The form's schema (app/features/publishers/schemas/publisher.schema.ts) has no isPublisher field, and createMember hardcodes isPublisher: true in app/features/publishers/server/member.aggregate.ts (the write path moved to the aggregate — the file/line referenced by the original body no longer applies). No toggle on the form.
  2. The only way to end up with a non-publisher Member is to create them as a publisher, then demote them via a POST /publishers/:memberId/make-student action. That route exists but has no visible button on the publisher detail page. The lifecycle cluster on the detail page now surfaces the inverse /make-publisher action (a UserCheck button shown when isPublisher === false), so an admin who lands on an already-demoted profile can promote them — but the demote path stays hidden.
  3. The one place that exposes a clear isPublisher checkbox in the UI is app/features/settings/routes/users/add-to-congregation.tsx, which only fires when a UserAccount exists but isn't yet linked to a Member — a niche admin flow (e.g. a circuit overseer login becoming a local member), not the common case.

Underlying mismatch: the domain has two independent axes — Type (publisher / student) and Lifecycle (present / inactive / left / anonymized) — but the UI presents one axis. The list is also labelled "Publishers" even though it already contains both publishers and ministry-school students (see docs/product/publishers.md).

Idea (not decided — needs more design work)

The shape of the redesign we've been kicking around:

  • Rename the section "Membres" / "Members" to match what the list already contains. Keep the /publishers URL for now to avoid link/test churn.
  • Single "Ajouter un membre" CTA, with a segmented control inside the form (Publisher / Ministry-school student, defaulting to Publisher). The choice would hide baptism date, anointed, the elder/servant nomination card, and the publisher type select for students; the group selector would stay visible.
  • Move publisher ↔ student switching out of the lifecycle icon cluster into a dedicated "Status" card on the publisher view, with a single labelled action ("Convertir en étudiant" / "Déclarer proclamateur"). The lifecycle cluster would keep only inactive / mark-as-left / mark-as-returned — cleaner separation between "type of member" and "lifecycle state".
  • createMember (in member.aggregate.ts) would accept isPublisher: boolean and force-zero baptism-gated flags when the kind is student, so DB CHECK constraints (servant/elder/anointed → baptism + male) can't be violated by construction.

Estimate

~2–3 days once the design is settled. The write-side change is a one-parameter addition on createMember in member.aggregate.ts; most of the effort is UI (segmented control, "Status" card on the detail page, section rename) and confirm-dialog copy.

Out of scope (current thinking)

  • Renaming the /publishers URL — link rot, e2e tests, deep-links from territories. Sidebar/in-page copy rename only.
  • Per-kind limits (students vs publishers). The existing members limit already covers both.
  • Renaming audit actions (PublisherCreated, PublisherStatusChanged). Historical analytics rely on them.
  • A list-row "convert" shortcut. Forcing the admin into the profile first is the right friction.

Status

Not decided. The above is one direction, not a committed design. Open questions before this is ready to implement:

  • Is "segmented control inside the form" the right entry-point shape, or is a split button / two CTAs / a separate route preferable?
  • Should the section actually be renamed, or should the label stay "Publishers" and the IA be fixed elsewhere?
  • Where exactly does the publisher↔student action live on the profile (dedicated card vs. a settings-style menu vs. somewhere else)?
  • Confirm-dialog copy (FR + EN) needs review before it ships.
  • Are there flows we're forgetting — e.g. bulk import, archive restore — that would also need a "kind" field?

More design work needed before opening a PR. Feedback welcome.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions