Skip to content
Draft
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
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ What the app is and how to run it: [`README.md`](README.md). UI rules: [`docs/de
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/`.
- **Regolamenti** (`src/features/regulations/`): pages talk to `regulations.*` through `regulationsApi(context)`,
which parses responses with `regulations.contract.ts` (a copy of the backend's) and, in agent mode, uses the fake with
its local Hocuspocus server and `xelatex`. Per-draft access (viewer, commenter, editor) and deleghe are backend data:
`regulations.me.get` admits users without `admin:access` to Bozze only, draft-scoped server functions use
`regulationsAssigneeMiddleware`, and pages act on the draft's `can` from the backend. The editor connects to the
collab service with a single-use ticket from a server function, never a token. UI copy is Italian. Details:
`docs/regulations/README.md`.
- **Shared UI**: `src/components/shell`, `src/components/primitives`, `src/components/ui`.

## Conventions
Expand Down
45 changes: 28 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ rebuilt in Phase 2 (#144) and Phase 3 (#145). Permissions: `people:read` (which
`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`.

**Regolamenti** edits, approves, publishes and notifies the governance documents (v1: the Raccolta dei Regolamenti
Interni): a collaborative LaTeX editor (CodeMirror and Yjs over the collab service) with a live PDF preview, comments,
history, merges between drafts, the approval procedure with "Emana e notifica", the differences view and the
Segretario's deleghe. It talks to the backend's `regulations.*` contract (`src/features/regulations/regulations.contract.ts`);
agent mode serves a fake with a local collab server and `xelatex`. Permissions: `regulations:read`, `regulations:write`,
`regulations:manage`, `regulations:rectify`; a draft assignment or a delega alone admits anyone to Bozze. See
[`docs/regulations/README.md`](docs/regulations/README.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
**dedicated Redis**, separate from the shared backend Redis. Backend requests carry a user bearer token, and permissions
Expand All @@ -32,23 +40,26 @@ Signing in as a real user needs a development client registered in the IdP.

Set the following runtime variables (the build does not need secrets):

| Variable | Meaning |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `APP_URL` | Dashboard's public origin. Required outside development; HTTPS in production. Development defaults to `http://localhost:$PORT` (3001). Used for exact Origin CSRF validation and callback/logout URLs. |
| `BACKEND_URL` | tRPC backend origin; use the in-cluster service address in production. Defaults to `http://localhost:3000` in development. |
| `IDP_URL` | Public IdP origin; defaults to `https://auth.polinetwork.org`. Issuer is `$IDP_URL/api/auth`. Browser redirects retain this public origin. |
| `IDP_INTERNAL_URL` | Optional internal IdP origin, e.g. `http://auth-service.auth.svc.cluster.local:3000`. Rewrites discovery, token, JWKS and revocation transport only; issuer, JWT assertion audiences (public token/revoke endpoints) and browser URLs remain public. |
| `OIDC_CLIENT_ID` | Registered confidential dashboard client, with authorization code and refresh grants, scopes `openid profile email offline_access backend:admin`, and backend resource link. |
| `OIDC_CLIENT_PRIVATE_JWK` | Private signing JWK JSON with `kid` and `alg` (`EdDSA`/Ed25519 or `ES256`/P-256); inject from this service's Key Vault. Register only its public JWKS in the IdP. |
| `OIDC_CLIENT_SECRET` | Alternative `client_secret_basic` credential; set exactly one client credential mode. |
| `BACKEND_RESOURCE` | Backend OAuth resource/audience; defaults to `https://backend.internal.polinetwork.org`. Sent on every authorize, code exchange and refresh request. |
| `REDIS_URL` | Dedicated dashboard Redis connection. Required outside development; development defaults to `redis://localhost:6379`. Never point to shared backend Redis. |
| `SESSION_SECRET` | Independent random secret of at least 32 characters, encrypting the 10-minute state/nonce/PKCE cookie. Rotation invalidates pending login attempts. |
| `AGENT_PERMISSIONS` | Development only. Comma-separated permissions for the agent-mode user (default: all). `people:self` alone previews the restricted People view. |
| `AGENT_PERSON` | Development only. The agent-mode user's People record (default `P-0007`, Direttivo). `P-0098` is a Capo Admin, `P-0034` the IT Team Lead, `P-0115` an IT member; `none` previews a sign-in without a record. Sending an invite prints its link in the dev server's console. |
| `AGENT_MODE` | Fake all-permission user in development only. It has no access token, so the backend refuses its calls; People serves sample data. Production ignores this mode. |
| `PORT` | Local listening port (3001 by default); use a port ≥10000 for agent previews. |
| `TEST_REDIS_URL` | Opt-in disposable Redis for integration tests. Tests create/delete only UUID session keys. |
| Variable | Meaning |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `APP_URL` | Dashboard's public origin. Required outside development; HTTPS in production. Development defaults to `http://localhost:$PORT` (3001). Used for exact Origin CSRF validation and callback/logout URLs. |
| `BACKEND_URL` | tRPC backend origin; use the in-cluster service address in production. Defaults to `http://localhost:3000` in development. |
| `IDP_URL` | Public IdP origin; defaults to `https://auth.polinetwork.org`. Issuer is `$IDP_URL/api/auth`. Browser redirects retain this public origin. |
| `IDP_INTERNAL_URL` | Optional internal IdP origin, e.g. `http://auth-service.auth.svc.cluster.local:3000`. Rewrites discovery, token, JWKS and revocation transport only; issuer, JWT assertion audiences (public token/revoke endpoints) and browser URLs remain public. |
| `OIDC_CLIENT_ID` | Registered confidential dashboard client, with authorization code and refresh grants, scopes `openid profile email offline_access backend:admin`, and backend resource link. |
| `OIDC_CLIENT_PRIVATE_JWK` | Private signing JWK JSON with `kid` and `alg` (`EdDSA`/Ed25519 or `ES256`/P-256); inject from this service's Key Vault. Register only its public JWKS in the IdP. |
| `OIDC_CLIENT_SECRET` | Alternative `client_secret_basic` credential; set exactly one client credential mode. |
| `BACKEND_RESOURCE` | Backend OAuth resource/audience; defaults to `https://backend.internal.polinetwork.org`. Sent on every authorize, code exchange and refresh request. |
| `REDIS_URL` | Dedicated dashboard Redis connection. Required outside development; development defaults to `redis://localhost:6379`. Never point to shared backend Redis. |
| `SESSION_SECRET` | Independent random secret of at least 32 characters, encrypting the 10-minute state/nonce/PKCE cookie. Rotation invalidates pending login attempts. |
| `AGENT_PERMISSIONS` | Development only. Comma-separated permissions for the agent-mode user (default: all). `people:self` alone previews the restricted People view. |
| `AGENT_PERSON` | Development only. The agent-mode user's People record (default `P-0007`, Direttivo). `P-0098` is a Capo Admin, `P-0034` the IT Team Lead, `P-0115` an IT member; `none` previews a sign-in without a record. Sending an invite prints its link in the dev server's console. |
| `AGENT_BACKEND_TOKEN` | Development only. A bearer token agent mode sends to the backend (e.g. from the backend's dev IdP shim): permissions come from that backend's `me.access` and Regolamenti uses it instead of the fake. Two dev servers with two tokens are two people. |
| `REGULATIONS_DEV_LEGAL_DIR` | Development only. A checkout of PoliNetworkOrg/legal: agent mode's Regolamenti fake serves the real RRI and compiles it with the real class. |
| `REGULATIONS_DEV_COLLAB_PORT` | Development only. Port of agent mode's local collab server (default `PORT + 1`). |
| `AGENT_MODE` | Fake all-permission user in development only. It has no access token, so the backend refuses its calls; People serves sample data. Production ignores this mode. |
| `PORT` | Local listening port (3001 by default); use a port ≥10000 for agent previews. |
| `TEST_REDIS_URL` | Opt-in disposable Redis for integration tests. Tests create/delete only UUID session keys. |

Before review run `pnpm check`, `pnpm typecheck`, `pnpm test` and `pnpm build`. Run real Redis tests with
`TEST_REDIS_URL=redis://127.0.0.1:<test-port> pnpm test`. The OIDC integration test uses a local fake provider with
Expand Down
13 changes: 12 additions & 1 deletion docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ service title ("PoliNetwork Admin" on Overview), Search, the theme toggle and th
as horizontally scrolling pills that scroll away with the page. The current pill stays in view after navigation,
font loading and changes to the bar's width, including when it first appears below 760px. A 64px bottom nav lists the visible services (current one
accent with a top bar, Reports with the open-reports dot). The device's bottom safe area adds space below the 64px
bar. Below 360px, WhatsApp uses "WA" so all labels remain readable. With seven services, WhatsApp uses "WA" below 440px and Telegram uses "TG" below 360px. Section pills and bottom nav are the only navigation; there
bar. Below 360px, WhatsApp uses "WA" so all labels remain readable. With seven services, WhatsApp uses "WA" below 440px and Telegram uses "TG" below 360px. With eight (Regolamenti, "Regole"), Telegram uses "TG" below 420px. Section pills and bottom nav are the only navigation; there
is no sheet.

**Command palette** (`⌘K`/`Ctrl+K`, the rail and top bar Search, the Overview search): sections, "Find “…” in
Expand Down Expand Up @@ -406,6 +406,10 @@ the theme reveal and the skeleton pulse switch off; the signed box is removed at

## 7. Copy

Regolamenti is the one Italian part of the dashboard: its pages, dialogs, toasts and empty states follow these rules in
Italian ("Crea bozza", "Bozza creata.", "Non è stato possibile creare la bozza."), dates as the documents print them
("12/03/2026", `regulations-format.ts`), and pass `locale="it"` to the primitives that print their own words.

- Sentence case everywhere. Verb first, object named: "Delete passkey", "Save labels".
- No "please", "successfully", exclamation marks or "Are you sure". Contractions are fine in errors.
- "Microsoft 365", never "Azure" or "Office 365", in user-facing text ("Microsoft Entra" when naming the directory).
Expand Down Expand Up @@ -613,4 +617,11 @@ Rules that the templates above don't imply.
- **Capo Admin** (Telegram) and **My area** (Account): self-service pages that open with `people:self` and a role on
the person's own record; no personal emails of others, only phone, Telegram and PoliNetwork addresses.

- **Regolamenti**: Documenti is a card per document; a document page lists its versions (the newest carries "In vigore",
each has its PDF, release, differences and "Nuova bozza da qui") and its drafts. Bozze adds "Il tuo accesso" for people
admitted only by an assignment, who see no other section. The editor is a workspace (`PageContent fill`); the
procedure page is a record with the states as a stepper, disabled transitions showing why, and the emanation's steps
live; the differences page is read-only (category summary, then old and new side by side for changed articles only).
Deleghe is a list with a segmented Attive/Tutte filter.

Receipt previews use eSign’s `PdfViewer` in its compact mode. Receipt requests in Signatures show their receipt reference; their signature boxes are fixed.
Loading
Loading