Skip to Content
Portal (apps/portal)Package family

The portal-* Package Family

Roughly 35 workspace packages under packages/portal-* factor the portal’s concerns out of apps/portal. The rule of thumb: the app owns routes and wiring; the packages own logic. Anything reusable, testable in isolation, or security-sensitive (session crypto, permission evaluation, projection contracts) lives in a package with an explicit boundary. The split exists because CI gates can only enforce rules along package seams — the app stays a thin composition layer, and the display-only gate (see Data Access) has clean boundaries to check against.

Map by concern

ConcernPackagesWhat they own
Session & identityportal-sessionIron-session cookie sealing/unsealing, resolveForwardableSessionToken, the ActiveGrant async-context store (/active-grant export) — the substrate for both gates and every adapter.
Security postureportal-security, portal-security-policy, portal-step-upCSRF/origin policy, security headers, step-up authentication flows.
Authorizationportal-permissions, portal-permission-acceptancePortal-side capability surfaces over @opsdna/permission-engine (ADR-0026/0027); grant acceptance flows.
Read contractsportal-read-models, portal-projectionsThe typed projection shapes display code renders — the only data types routes may import at runtime (ADR-0015 posture).
Presentationportal-ui, portal-formatting, portal-i18n, portal-a11y, portal-mobile, portal-static-data, portal-slugs, portal-route-refsComponent library per DESIGN.md, number/date formatting, accessibility helpers, URL slug/route-ref identity (guarded by the portal:check-url-slug-identity and portal:check-canonical-links gates).
Documents & sharingportal-documents, portal-document-releases, portal-investor-request-templates, portal-legalDocument surfaces and the ADR-0015 release/share flows.
LP & audit surfacesportal-lp-performance, portal-auditor-questions, portal-access-audit, portal-audit, portal-audit-exportLP performance views; auditor Q&A; access/audit trails and their exports.
Observabilityportal-observability, portal-telemetrySpan helpers (withServerSpan consumers), client tracing, boot beacons.
Integrations & infraportal-carta-adapter, portal-webhooks, portal-email-infra, portal-email-templates, portal-feature-flags, portal-release-gates, portal-seeds, portal-search, portal-support-consoleExternal adapters, email, flags, release gating, seed/demo data, search, internal support tooling.

(Authoritative list: ls packages | grep portal — this table is the map, not the territory; new packages appear as features land.)

Boundary discipline

Package boundaries are CI-enforced (bun run check:boundaries inside verify), and several portal gates key off this layout: portal:bundle-audit (AppShell bundle budget), portal:a11y-baseline-check (per-tag a11y rules), portal:trip-wire, and portal:display-only-check. When you add portal logic, the question is rarely “which file in the app” — it’s “which package owns this concern.”

Don’t confuse portal-projections with @opsdna/persistence read code. Projections are the serialized, display-safe contract; persistence rows are server-side substrates. Display code importing persistence at runtime — even “just one type helper” that isn’t import type — fails the display-only gate. See Data Access.

Last updated on