Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@ What the app is and how to run it: [`README.md`](README.md). UI rules: [`docs/de
`src/start.ts` validates the configured Origin on all state-changing requests. There is no Better Auth proxy.
- **Server functions** attach `adminMiddleware` for reads, and their exact permission middleware for mutations:
grants, Telegram groups, WhatsApp groups, labels, website content, reports, People (write, appoint, link, team), and
Microsoft 365 member creation and member-number changes.
Soci (`soci:write`: admit, register, edit, change number). Soci reads use `sociReadMiddleware` (`soci:read`).
The backend independently checks every procedure. `context.backend` forwards a bearer token, never cookies.
- **Features** (`src/features/<area>/`): pages, dialogs, validation and `*.functions.ts` server functions.
- **Microsoft 365**: read the member directory with `azure:members:read` and create with `azure:members:create` through
the backend's fixed new-member workflow, choosing a standard or custom address; a welcome email to a PoliNetwork
address asks for confirmation. Change a member's ID with `azure:members:write`, after a confirmation, optionally
emailing them; the backend refuses IDs already assigned and accepts this call only with a user token, so it fails in
`AGENT_MODE`. List groups and their members, read-only, with `azure:groups:read`. Group membership is never
edited from the dashboard: the backend's create workflow adds only the new user to Soci, from which the IdP derives
the Socio role, so adding or removing anyone in a group would grant or revoke IdP roles. Nothing else about users or
groups can be edited from the dashboard.
- **Microsoft 365**: read the member directory with `azure:members:read`, and list groups and their members with
`azure:groups:read`, both read-only. Group membership is never edited from the dashboard: admitting a socio (People ›
Soci) adds only the new user to Soci, from which the IdP derives the Socio role, so adding or removing anyone in a group
would grant or revoke IdP roles. Nothing else about users or groups can be edited from Microsoft 365's pages.
- **People** (`src/features/people/`): every page reads and writes through `peopleApi(context)`, which parses the
backend's `people.*` responses with `people.contract.ts` (a copy of the backend's) and, in agent mode, uses the
in-memory fake (`AGENT_PERMISSIONS`, `AGENT_PERSON` pick the viewer). A person's roles are assignments (Admin, Capo
Expand All @@ -32,9 +28,14 @@ What the app is and how to run it: [`README.md`](README.md). UI rules: [`docs/de
permissions yet can accept one (`peopleInviteMiddleware`: signed in, the token is the proof); the old
`/dashboard/account/me?peopleInvite=` links redirect there. `/dashboard` admits `people:self` without
`admin:access`; Capo Admin and Team Lead come from the person's own record (`peopleRoles` in the route context) and
only open their sections. Member register, Receipts, Census and My area's fee card are unconnected mockups (#138):
static sample data from `mockup-data.ts`, no server functions, disabled actions and a `MockupBanner`, gated by
`people:read`, to be rebuilt in Phase 2 (#144) and Phase 3 (#145). Handoff notes, decisions and the plan: `docs/people/`.
only open their sections. Receipts, Census and My area's fee card are unconnected mockups (#138): static sample data
from `mockup-data.ts`, no server functions, disabled actions and a `MockupBanner`, gated by `people:read`, to be rebuilt
in Phase 2 (#144) and Phase 3 (#145). Handoff notes, decisions and the plan: `docs/people/`.
- **Soci** (`src/features/soci/`, People's Soci group): the Libro Soci, through `sociApi(context)`, which parses the
backend's `soci.*` responses with `soci.contract.ts` (a copy of the backend's) and serves `soci.fake.server.ts` in agent
mode. `soci:read` opens Register and the socio pages, `soci:write` admits (a new Microsoft 365 account in Soci, then the
record), registers an account already in Soci, edits and changes member numbers, which moved here from Microsoft 365 ›
Members. Design: `docs/people/soci.md`.
- **Shared UI**: `src/components/shell`, `src/components/primitives`, `src/components/ui`.

## Conventions
Expand Down
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
# PoliNetwork Admin

The dashboard manages Telegram and WhatsApp groups, labels, Telegram users and grants, website content and reports.
Microsoft 365 supports a member directory, creating a new association member through the backend's fixed workflow
(with a standard `firstname.lastname` or custom address), changing a member's ID with an optional email to them, and a
read-only list of groups. Directory access requires `azure:members:read`; creation independently requires
`azure:members:create`, and changing member IDs `azure:members:write`. Groups require `azure:groups:read`. Group
membership is never edited: creating a member adds only that new user to Soci, which gives them the Socio role.
Microsoft 365 has a read-only member directory (`azure:members:read`) and a read-only list of groups
(`azure:groups:read`). Group membership is never edited from Microsoft 365's pages: admitting a socio in People › Soci
adds only that new user to Soci, which gives them the Socio role.

**People** keeps one record per volunteer (Overview, Admins, Teams, Linking), plus Telegram › Capo Admin and Account ›
My area for volunteers themselves. The dashboard talks to a typed `people.*` contract
(`src/features/people/people.contract.ts`, documented in `docs/people/contract.md`); agent mode serves sample data from
`people.fake.server.ts`. Member register, Receipts and Census are unconnected UI mockups with static sample data, to be
rebuilt in Phase 2 (#144) and Phase 3 (#145). Permissions: `people:read` (which also opens the mockups),
`people:write`, `people:appoint`, and `people:self`, which alone admits non-admins to My area and, by the role on their
record, Capo Admin or their team. See `docs/people/README.md`.
My area for volunteers themselves, and the Libro Soci (Soci › Register). The dashboard talks to typed `people.*` and
`soci.*` contracts (`src/features/people/people.contract.ts`, documented in `docs/people/contract.md`, and
`src/features/soci/soci.contract.ts`); agent mode serves sample data from `people.fake.server.ts` and
`soci.fake.server.ts`. Receipts and Census are unconnected UI mockups with static sample data, to be rebuilt in Phase 2
(#144) and Phase 3 (#145). Permissions: `people:read` (which also opens the mockups), `people:write`, `people:appoint`,
`people:self`, which alone admits non-admins to My area and, by the role on their record, Capo Admin or their team, and
`soci:read` and `soci:write` for the register. See `docs/people/README.md` and `docs/people/soci.md`.

Built with TanStack Start (React 19), Vite+, Nitro, Tailwind CSS v4 and shadcn/Base UI. The server is an OIDC BFF:
only it holds the IdP access/refresh/ID tokens. Browsers hold an opaque, HttpOnly session cookie; sessions live in a
Expand Down
16 changes: 10 additions & 6 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ else its first. Theme toggle and the account avatar (the same active fill and in
the Account page.

**Panel** (240px, 200px below 1100px). Rendered only for services with two or more sections (Telegram, Microsoft 365,
Web, Reports); WhatsApp, Overview and Account have none. A 64px header with the service icon and title, then 38px items:
Web, Reports); WhatsApp, Overview and Account have none. A service may group its sections (`group` on `Section`): the
panel draws each group's title, 11px uppercase and subtle, above its first visible section, and the mobile pills only
keep the order. People groups Volunteers (Overview, Admins, Teams, Census, Linking) and Soci (Register, and the Receipts
mockup until Fees replaces it; Deletion pending). A 64px header with the service icon and title, then 38px items:
the current one has a muted fill, an accent icon and a 3px accent bar; on deep pages the parent section keeps the fill
and accent icon without the bar (`data-ancestor`). The only counts are the open reports next to Reports › Open and the documents to sign next to Signatures › To sign, each as a
small accent pill.
Expand Down Expand Up @@ -587,14 +590,15 @@ Rules that the templates above don't imply.
request.".
- **Account**: permissions are grouped by area (Dashboard, Telegram, WhatsApp, group labels, Microsoft 365, Web) with
the service icon.
- **People**: one record per person whether or not they have an account; Overview, Member register, Admins, Teams,
Census and Linking all open the same record (`/dashboard/people/$personId`). Account status always shows a badge,
- **People**: one record per person whether or not they have an account; Overview, Admins, Teams, Census and
Linking all open the same record (`/dashboard/people/$personId`). Account status always shows a badge,
Not linked included. Mobile list cards replace unlabelled column values with one line of role chips or status
badges in the name cell. Dialogs that need fields and are destructive (End admin role, End membership, I'm leaving)
use `FormDialog` with `tone="danger"`; plain confirmations stay `ConfirmDialog`.
- **Member register**: status segments scope the table; Number leads on desktop, the name on mobile. Add member from a
record opens the register's dialog via `?add=P-…`. Export confirms before downloading. Without `people:read`,
register/receipt rows have no full-record links; the register loads its own restricted projection.
- **Soci › Register** (`docs/people/soci.md`): the Libro Soci, one record per admission. Status segments (Active /
Ended / All) scope the table; Number leads on desktop, the name on mobile. Alerts above the table list the Soci
group's accounts without a record (with Register) and each kind of mismatch. Rows open the socio page
(`/dashboard/people/soci/$number`), a deep page with Edit and Change number.
- **Fees and receipts** (`docs/people/fees.md`): the register's first row action follows the fee (Review receipt,
Send reminder, or an empty slot); its header keeps one outline action (Send reminders), with Export register as a boxed
icon. People › Receipts is a queue with the pipeline as segments and the officer's to-sign count in the panel.
Expand Down
4 changes: 2 additions & 2 deletions docs/people/fees.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# People area: fees and receipts

> [!IMPORTANT]
> **This describes an unconnected mockup.** Since #138, People › Member register, People › Receipts and My area's
> fee card render static sample data, make no backend call and disable every action. The procedures, permissions
> **This describes an unconnected mockup.** Since #138, People › Receipts and My area's fee card render static
> sample data (the Member register mockup was replaced by Soci › Register in #155), make no backend call and disable every action. The procedures, permissions
> (`people:fees:write`, `people:receipts:sign`) and the eSign receipt bridge below are removed. Soci, fees and receipts
> will be rebuilt from scratch on Microsoft 365 members in Phase 2 (#144); this file stays as the design reference.
>
Expand Down
20 changes: 11 additions & 9 deletions docs/people/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ Only My area, an active Capo Admin's scope and a Team Lead's own teams work with
count only once PoliNetwork Auth holds them (the record is linked and the role applied). “Team member” means a volunteer in a team. `people:members:read`,
`people:members:write`, `people:fees:write` and `people:receipts:sign` were removed in #138.

| Viewer / extra permissions | Pages | Actions |
| ---------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Volunteer: `people:self`, P-0021 | My area, Sign-in & security | Read own record and roles |
| Team Lead: `people:self`, P-0030 | Above + own team(s) under People | Add team members, edit team fields, end ordinary team memberships; never appoint or end a Lead without `people:appoint` + admin access |
| Capo Admin: `people:self`, P-0003 | My area + Telegram › Capo Admin | Read-only list of the admins who have them as Capo Admin of reference |
| `people:read` | People overview, person records, Admins, Teams, Linking | Read contacts and notes; no editing, linking or appointments |
| `people:link` | Link account and Unlink on records and Overview | Search the IdP's accounts, link one by hand, unlink (Auth revokes the roles first) |
| `people:read` (mockups) | Member register, Receipts, Census; the fee card in My area | None: unconnected mockups with sample data (#138), to be rebuilt in Phase 2 (#144) and Phase 3 (#145) |
| Master Admin: all explicit permissions, P-0007 | All permitted sections | All People mutations |
| Viewer / extra permissions | Pages | Actions |
| ---------------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Volunteer: `people:self`, P-0021 | My area, Sign-in & security | Read own record and roles |
| Team Lead: `people:self`, P-0030 | Above + own team(s) under People | Add team members, edit team fields, end ordinary team memberships; never appoint or end a Lead without `people:appoint` + admin access |
| Capo Admin: `people:self`, P-0003 | My area + Telegram › Capo Admin | Read-only list of the admins who have them as Capo Admin of reference |
| `people:read` | People overview, person records, Admins, Teams, Linking | Read contacts and notes; no editing, linking or appointments |
| `people:link` | Link account and Unlink on records and Overview | Search the IdP's accounts, link one by hand, unlink (Auth revokes the roles first) |
| `soci:read` | Soci › Register, socio pages | Read the Libro Soci, its activity and the Soci group's accounts without a record |
| `soci:write` | Same | Admit socio, Register existing socio, Edit, Change number |
| `people:read` (mockups) | Receipts, Census; the fee card in My area | None: unconnected mockups with sample data (#138), to be rebuilt in Phase 2 (#144) and Phase 3 (#145) |
| Master Admin: all explicit permissions, P-0007 | All permitted sections | All People mutations |

`people:write` enables record, admin-role, team and invite mutations on readable pages;
`people:appoint` enables Capo/Lead appointments and ending those roles; `people:link` enables linking by hand and
Expand Down
Loading
Loading