Skip to content

0021 — Admin & Ministry Portal ​

Status: Accepted (2026-06-18 — owner accepted during ADR review); amended 2026-06-22 — see §"Amendment: Member Manage screen and Minister Oversight view" below

Date: 2026-06-18

ADO work item: AB#3074

Deciders: Kristopher Turner (platform owner)


Context ​

The platform is a closed, minister-approved community (ADR 0007). Leadership — Community Leaders (admin) and Ministry Leaders — must actively manage that closure: reviewing membership requests, moderating content before publication, maintaining the member directory, overseeing family groups, and reading audit records. None of these actions can be self-service for ordinary members; all require elevated roles that the server enforces (ADR 0006).

ADR 0007 explicitly anticipates "a minister dashboard" as the surface where approval queue items land. ADR 0008 establishes that every surface is a thin client of the platform API — the admin portal is no exception. What is missing is a decision recording the scope and boundaries of that surface: which capabilities it owns, which roles it admits, and what it explicitly excludes.

Three boundary questions need answering before the platform build (AB#3074) proceeds:

  1. Does the admin portal live inside the existing monorepo platform, or does it become its own app or repo?
  2. What capabilities does it own, and in what order do they need to be built?
  3. Where does infrastructure administration live, and is a custom UI required for it?

Deferring these questions risks feature Epics implementing ad-hoc admin flows that conflict with the platform's API-first, server-side-authz contract, or worse, exposing admin surfaces without proper RBAC gating.

Decision ​

We will build the Admin & Ministry Portal as an admin-gated route surface within the existing apps/web shell and apps/mobile client, consuming the platform API exclusively through api-client. It is not a separate application or repository. All authorization is enforced server-side against the admin and ministry_leader roles (ADR 0006). The portal owns six capability areas: (1) the approval queue, (2) member management, (3) family group oversight, (4) content moderation via the approval queue, (5) member directory administration, and (6) the activity/audit view. Infrastructure administration has no custom UI — it is handled entirely through Azure, Entra, GitHub, and ADO native consoles (ADR 0006, Plane 1).

Capability areas ​

1. Approval queue ​

The ApprovalWorkflow table (ADR 0007) is the single queue for all gated events. The portal surfaces every pending item — member-join, spouse-add, child-add, and content-publish — in one list. Each item shows its type, submitting user, timestamp, and current status. An admin or ministry leader can approve or deny an item; the API writes the outcome and triggers the appropriate downstream action (e.g., flipping Users.status, publishing an Announcement).

The approval queue is also the content-moderation mechanism. Because Announcements are one-way broadcast with no reply threads (ADR 0007), every piece of community-facing content passes through the content-publish workflow type before it reaches members. There is no separate moderation system; the queue handles it.

2. Member management ​

Admins can view all members, search by name or role, suspend or reactivate accounts, and assign or revoke Plane-2 RBAC roles within the five-role canonical model (admin, ministry_leader, group_leader, member, visitor — ADR 0006). Role changes are admin-only API operations; no endpoint permits a member to modify their own role.

3. Family group oversight ​

Admins can view the list of all FamilyGroups, inspect the members of each group, and see the relationship type (primary | spouse | child) for each member. This view is read-oriented; structural changes to family composition still route through the approval queue (spouse-add, child-add workflows).

4. Content moderation ​

Content moderation is fully handled by the approval queue (content-publish workflow type — ADR 0007). The portal does not add a separate moderation UI. Pending Announcements appear as approval items; an admin or ministry leader approves or rejects; the API sets published_at or discards. No additional tooling is required.

5. Member directory administration ​

Admins can manage the member directory — correcting profile data, toggling directory visibility for individual members, and confirming that directory entries are accurate after a role or status change. Ordinary members may update their own profile fields; admin-level directory controls (visibility overrides, data corrections on behalf of a member) require the admin role.

6. Activity / audit view ​

Admins can read the AuditLog table (ADR 0005, Layer 1) — login/logout events, session durations, approval actions, and content publish events — to exercise ministerial oversight of the closed community. This view is read-only for portal users; the AuditLog itself is written only by the API, never by client code.

Role gating ​

All admin portal routes and API endpoints are gated to admin or ministry_leader roles, enforced server-side. The client may hide navigation items from lower-privileged users as a UX convenience, but the API re-checks the role on every request regardless. Role assignments themselves are admin-only.

Platform boundary: no infrastructure admin UI ​

Plane-1 RBAC (Azure RBAC, Entra, GitHub, ADO) is managed through those providers' native consoles (ADR 0006). There is no custom infrastructure-admin page to build, no Azure resource browser, and no CI/CD control panel in the application. Building one would duplicate native tooling, introduce a second authorization surface for infra, and violate the two-plane separation. Any future operator-facing operational need (e.g., a deployment trigger) belongs in a GitHub Actions workflow, not in the application portal.

Surface delivery ​

The admin portal is available on both web and mobile — a minister can approve a join request or moderate content from either surface. The API-first design (ADR 0008) means the same endpoints serve both; no capability is web-only or mobile-only. Mobile screens are priority-sorted toward the approval queue and member management as the highest-frequency admin tasks in the field.

Alternatives considered ​

OptionProsConsWhy not chosen
Admin surface within apps/web + apps/mobile, API-first (chosen)Consistent with ADR 0008; no new app/repo; server-side authz; available on web and mobileRequires disciplined route gating; admin and member paths share the same shell— chosen
No portal — manage via database scripts or direct DB accessNothing to build for adminMinistry staff cannot use database tooling; destroys the closed-community guarantee; approval workflow has no UICompletely unusable by non-technical leadership; rejected
Separate admin app or repositoryStrong separation; independent deployDuplicates the API-client/shared-types dependency; violates API-first composition; doubles the surface count; fragments the monorepo without gainThe platform is the boundary, not a separate repo; rejected
Building an infrastructure admin UI (Azure resource browser, deployment panel)Single pane of glassRe-implements Azure Portal, GitHub Actions, and ADO Boards; introduces a second Plane-1 auth surface; violates two-plane RBAC separation (ADR 0006)Azure, GitHub, and ADO native consoles already do this; rejected

Consequences ​

Positive ​

  • A minister can action every approval — member join, spouse, child, content — from one queue view on web or mobile, without opening a database console or contacting a developer.
  • Authorization is enforced in one place (the API), consistent with every other platform surface. A compromised admin client cannot escalate privileges or bypass the role check.
  • Content moderation requires no additional tooling — the existing ApprovalWorkflow table and queue UI handle it. The one-way Announcements model (ADR 0007) removes the need for a separate moderation pipeline.
  • The AuditLog view gives leadership a direct, auditable record of community activity — required for a closed community that includes minors.
  • Building inside the existing apps rather than a new repo avoids duplicating the api-client, shared-types, and ui package dependencies.

Negative / trade-offs ​

  • Admin routes and member routes share the same apps/web shell and apps/mobile app. This requires careful route-gating implementation; a misconfiguration could expose admin views to non-admin users. Mitigation: route guards read the server-issued role, not a locally cached one; the API re-authorizes every request.
  • The approval queue is a central bottleneck for all gated events. If the minister is unavailable, all pending joins and content items wait. This is a deliberate property of the closed-community model, not a defect, but leadership must understand the operational implication.
  • Mobile admin screens need careful information hierarchy — the full directory or audit log is difficult to use on a small screen. Mitigation: prioritize approval queue and member management for mobile; direct heavy read views (full audit log, full directory) to the web surface.

Risks ​

  • Route-guard bypass — if a client-side route guard is the only protection on an admin view, a member with a manipulated token could reach the UI. Mitigation: every API endpoint called from admin views performs a server-side role check; client guards are UX-only.
  • Role assignment abuse — an admin role can assign admin to another user. Mitigation: log all role changes to AuditLog; limit admin creation to a bootstrap process or require dual approval in a future ADR.
  • Approval queue backlog — a high volume of pending items with only one active admin creates a single point of failure. Mitigation: the ministry_leader role also has approval authority; the platform should support multiple concurrent approvers from the initial build.
  • Audit log data retention — the AuditLog view is only as useful as the data retained (ADR 0005 notes a 90-day limit on the free Application Insights tier). Mitigation: document retention policy for the closed community; export if compliance requires longer retention.

Amendment: member Manage screen and Minister Oversight view (2026-06-22) ​

ADR 0032 was revised to use a Manage-button model: admin and ministry_leader viewing a member's detail screen see a "Manage" button that navigates to a separate management screen (/app/members/:id/manage). This changes the member management surface from inline detail-screen fields to a dedicated page.

Capability area 2 (member management) and capability area 5 (member directory administration) are updated accordingly:

  • Admin management screen (MemberManagePage at /app/members/:id/manage, admin role): edit profile fields, change account status (suspend/reactivate), change role (links to Role Assignment page), view audit log for that member.
  • Minister management screen (same route, ministry_leader role): pastoral oversight scope — family context, pastoral notes, initiate approval-queue actions where applicable. Minister has no write access to profile fields, status, or role.

ADR 0033 — Platform Foundation UI & View Inventory adds a Minister Oversight view (MN2 — /app/minister/oversight) as a portal-level pastoral overview, distinct from the per-member management screen.

Mockups: screens/member-manage-admin.html (new) and screens/member-manage-minister.html (new) replace the prior member-detail-admin-view.html and member-detail-minister-view.html for management capabilities. The detail screen mockups are now member-detail-adult.html (shared view for all roles) and member-detail-kid.html.

References ​

Heritage Community Hub — Internal. Access restricted via Cloudflare Access + Entra ID.