pal-e-app
Notes
Project Page 1
-
Project: pal-e-app
project-pal-e-appVision
The SvelteKit frontend for the
pal-e-docsproject. The/route is the public landing page (sign-in CTA, public notes, marketing surface); all other routes are gated by Keycloak. Once authenticated, users see role-scoped projects, kanban boards, and notes. The permission model is project-scoped: users are assigned to projects with read or write access, and see all child notes of those projects. Perdefinition-app, the landing page is a route inside the app, not a separate service — one repo, one hostname, one auth funnel.User Stories
Key Role Story Status PA-S1Stakeholder Register via pal-e-landing form so Lucas can onboard me Not started PA-S2Stakeholder Log in and reset password via Keycloak so I can access my scoped content Not started PA-S3Stakeholder See only the projects and boards assigned to me so I'm not overwhelmed Not started PA-S4Admin (Lucas) Assign users to projects with read/write permissions so I control what each person sees Not started PA-S5Admin (Lucas) Configure a user's landing page so they see what matters most on login Not started Architecture
Three architecture notes (pending creation):
- Domain Model — user, project, permission, note hierarchy
- Data Flow — landing → Keycloak → pal-e-app → pal-e-docs API (filtered by permissions)
- Deployment — pal-e-landing (static) + pal-e-app (SvelteKit, adapter-node) + Keycloak + pal-e-docs API
Key Decisions
- Permission scope = project. User gets access to a project → sees all child notes of that project note.
- Permission levels: read or write per user per project.
- Keycloak handles authentication (who are you). pal-e-docs API handles authorization (what can you see).
- pal-e-landing is a separate static site (adapter-static, new repo). Links to pal-e-app for login.
- pal-e-docs-app (old deployment name) is retired. pal-e-app is the canonical frontend.
- Existing SvelteKit codebase is the foundation — block renderer, board views, project nav, Keycloak integration all stay.
Board
Status
Project created 2026-03-30. Existing pal-e-app repo has 11 routes, Keycloak OIDC, block renderer, board kanban views, project navigation. Missing: project-scoped permissions, registration flow, configurable user landing pages.
Milestones
None yet.
Repos
Repo Platform Role Status pal-e-app Forgejo SvelteKit authenticated frontend (adapter-node) Active — needs permissions layer pal-e-landing Forgejo Static landing page (adapter-static) Not yet created Key People
Role Person Access Superadmin Lucas Everything — all projects, full read/write Admin Marcus westside-basketball — read/write on boards, stories, docs Stakeholder Mom westside-basketball — read-only on project kanban, timeline/dependency visibility First Users & AC
Phase 1 AC: Marcus and Mom can register via pal-e-landing, log in via Keycloak, reset password, and see scoped project boards. Lucas can see them in Postgres and assign permissions.
Phase 2 AC: Authenticated views (projects, kanban, tickets) look good and are useful for stakeholders. Mom can see dependencies and timelines.
User Story 1
-
Story: Board Card Traceability (pal-e-app)
story-pal-e-app-board-card-traceabilitystory: Board Card Traceability
Role
Lucas (platform owner / operator)
Key
board-card-traceabilityWant
As a platform owner, I want to see the full traceability triangle (story / arch / spec / PRs) for any board card I click in pal-e-app.
So That
So that I can navigate from any ticket to why it exists, what part of the system it touches, and what code came from it — without leaving pal-e-app or hand-grepping Forgejo. This is the foundation of "every piece of code known and mapped."
Acceptance Criteria
- [ ] Clicking any board card opens a right-side drawer (does not navigate away)
- [ ] Drawer shows: title, type badge, current column, full label list, linked Forgejo issue (if any), linked note (if note_slug set)
- [ ] Each label in the drawer is a clickable link:
story:X→/notes/story-{project}-X,arch:X→/notes/arch-*-{project}(resolution order documented in the convention) - [ ] Drawer closes on Escape, backdrop click, or close button
- [ ] "Move to column" affordance moves to a button inside the drawer (no longer triggered by tap-on-card)
- [ ] Long unbreakable tokens in card titles (e.g.
draft_tournament_email) wrap correctly viaoverflow-wrap: anywhere - [ ] Create-Item and Delete-Item modals render correctly without Tailwind utility classes — pure CSS vars matching
app.css - [ ] Visually verified on Lucas's phone (mobile-first) and on desktop
Success Metric
Lucas can click any board card on any board and reach all four traceability links (story note, arch note, Forgejo issue, parent project page) in ≤ 1 click each from the drawer. Self-reported "I can find anything" — measured by absence of follow-up complaints in the next two weeks of active use.
Related Architecture
arch-dataflow-pal-e-app— SvelteKit kanban page is the data-flow surface; this story extends it. Components table needs an entry for "Board Renderer" with the drawer pattern (discovered scope, separate ticket).arch-domain-pal-e-app— BoardItem entity carries the labels the drawer surfaces; no schema change needed (data is already there).- Canonical label for tickets:
arch:sveltekit-ssr(perconvention-architecture-ids) since the board page is the SvelteKit rendering surface.
Related
project-pal-e-app— parent project pageboard-pal-e-app— board where execution tickets liveconvention-architecture-ids— defines canonicalarch:labels used in the drawer's link resolutionfeedback_traceability_triangle— the platform principle this story dogfoodsfeedback_no_tailwind— drives the modal cleanup acceptance criterionfeedback_block_component_model— documents the Board as the renderer exception- Future:
convention-admin-surface-ui(to be created from this work, applied towestside-adminnext)
Doc 1
-
Validation: pal-e-production → pal-e-app rename
validation-114-2026-04-12Validation: pal-e-production → pal-e-app rename (#114)
Verdict: PASS
Acceptance Criteria
Criteria Status Evidence Forgejo repo at forgejo_admin/pal-e-app PASS API rename returned 200, URL accessible k8s namespace pal-e-app with running pod PASS kubectl: 1/1 Running https://pal-e-app.tail5b443a.ts.net returns 200 PASS curl: HTTP/2 200, content-type text/html ArgoCD synced + healthy PASS Synced Healthy Monitoring probe renamed PASS PR #287 merged — probe name + labels updated Network policies reference pal-e-app PASS PR #287 merged — lines 172, 196 updated Golden signals dashboard renamed PASS PR #287 merged — file renamed, 14+ PromQL refs updated Local remote updated PASS ~/pal-e-app origin → forgejo_admin/pal-e-app.git PRs Merged
- pal-e-deployments#120 — new kustomize overlay
- pal-e-deployments#121 — SOPS harbor-creds (initial)
- pal-e-deployments#122 — fix harbor-creds password
- pal-e-deployments#123 — fix harbor-creds username (bash $ expansion)
- pal-e-platform#287 — monitoring + network policies + dashboard
Issues Encountered
- SOPS harbor-creds had wrong username: bash
$expansion turnedrobot$pal-e-appintoldraney. Fixed by generating YAML with Python. - Harbor image was OCI format — containerd HEAD request got 404 misread as 401. Fixed with
skopeo copy --format v2s2(OCI → Docker manifest). - Terraform state drift: pal-e-production robots not in state, blocking applies. Resolved by removing pal-e-production from tfvars.
- Overlay directory was
pal-e-docs-appnotpal-e-production— previous rename never completed at directory level.
Remaining Cleanup
- Old
overlays/pal-e-docs-app/directory still in pal-e-deployments — can be deleted in a future PR - CORS env var
PALDOCS_ALLOWED_ORIGINSon pal-e-docs deployment needs updating to includehttps://pal-e-app.tail5b443a.ts.net - Woodpecker CI webhook needs verification on next push to renamed repo
- Board items #979, #980 have Forgejo URLs pointing to old repo name (auto-redirected by Forgejo)
Review 2
-
Review: infra: rename pal-e-production to pal-e-app across all layers
review-989-2026-04-12-r2Verdict: APPROVED
Re-review after refinement. All 6 items from review-989-2026-04-12 have been addressed. Ticket is well-scoped with verified file targets, clear decomposition, and blue-green execution strategy. Routes to
skill-decompose-ticketfor sub-board creation.Template Completeness
- [x] Type — Feature
- [x] Lineage — standalone, references related bugs #99, #97, #81
- [x] Repo — multi-repo documented (pal-e-services, pal-e-deployments, pal-e-platform, pal-e-production)
- [x] User Story — platform operator naming convention compliance
- [x] Context — explains 5-layer name embedding, blue-green strategy
- [x] File Targets — comprehensive with line numbers, includes "do not touch" section
- [x] Acceptance Criteria — 12 criteria covering all layers
- [x] Test Expectations — tofu plan, curl, CORS, grep verification
- [x] Constraints — blue-green, lock=false, SOPS, Harbor re-tag, dashboard filename
- [x] Checklist — 10 items tracking execution
- [x] Related — project, definition, CORS fix, naming convention
- [x] Decomposition — 5-step ordered breakdown with parallelism noted
Traceability
- [x] story:app-definition label — new story key for naming convention compliance initiative. Not yet in project-pal-e-app user-stories table. Acceptable for cross-cutting infra work.
- [ ] story note NOT YET CREATED — [SCOPE] Add "app-definition" story entry to project-pal-e-app user-stories section: "As a platform operator, I want infrastructure names to match the naming convention so that discoverability and consistency are maintained."
- [x] arch:pal-e-app label — references the component being renamed. Architecture notes (arch-deployment-pal-e-app) are listed as pending on the project page. Acceptable for infra rename — no arch diagram changes needed.
- [ ] arch note pending — arch-deployment-pal-e-app not yet created per project page. Not blocking for this ticket.
- [x] Forgejo issue — forgejo_admin/pal-e-deployments#114, open
File Targets
- [x]
pal-e-services/terraform/k3s.tfvars— verified: line 202 haspal-e-productionservice key with forgejo_repo, image_repo, source_path - [x]
pal-e-deployments/overlays/pal-e-production/— verified: directory exists with prod overlay (ingress.yaml, kustomization.yaml) - [x]
pal-e-deployments/overlays/pal-e-docs/prod/kustomization.yaml— verified: 2 occurrences of pal-e-production (cross-namespace refs) - [x]
pal-e-platform/terraform/modules/monitoring/main.tflines 386-388 — verified: old pal-e-production probe exists alongside pal-e-app probe at 391 - [x]
pal-e-platform/terraform/modules/monitoring/main.tflines 649-661 — verified: pal-e-production dashboard ConfigMap with file() reference - [x]
pal-e-platform/terraform/modules/monitoring/main.tflines 730-741 — verified: embedding worker ServiceMonitor with pal-e-production namespace selector and app labels - [x]
pal-e-platform/terraform/modules/ops/main.tflines 109-125 — verified: embedding worker metrics service in var.pal_e_production_namespace - [x]
pal-e-platform/terraform/modules/ops/variables.tfline 1-2 — verified: variable "pal_e_production_namespace" with description - [x]
pal-e-platform/terraform/modules/database/main.tflines 59-67 — verified: data source + postgres secret in pal-e-production namespace - [x]
pal-e-platform/terraform/modules/database/outputs.tfline 11-13 — verified: output "pal_e_production_namespace" with description - [x]
pal-e-platform/terraform/network-policies.tflines 172, 196 — verified: cross-namespace allow rules referencing pal-e-production - [x]
pal-e-platform/terraform/secrets.auto.tfvars.exampleline 35 — verified: comment "pal-e-production" - [x]
pal-e-platform/terraform/dashboards/pal-e-production-golden-signals.json— verified: file exists, needs rename
Repo Placement
OK. Issue filed on pal-e-deployments (central kustomize repo). Multi-repo scope is documented: pal-e-services, pal-e-deployments, pal-e-platform, pal-e-production. Decomposition section assigns each repo to a sub-task.
Dependencies
- Board items #979 and #980 reference
forgejo_admin/pal-e-productionissue URLs — ticket documents these need updating post-rename (AC item 12) - Item #714 (namespace rename pal-e-docs-app to pal-e-app) overlaps — different rename vector (from pal-e-docs-app, not pal-e-production). May need coordination.
- Sub-task ordering is correct: repo rename first, then parallel terraform/kustomize, then validation
Acceptance Criteria
12 criteria, all verifiable by an agent: kubectl checks, curl, grep, ArgoCD status, tofu plan. Test Expectations section provides specific commands. Comprehensive and testable.
Blast Radius
- pal-e-docs CORS env var needs updating (documented in AC #6)
- Woodpecker CI pipeline in pal-e-production repo references Harbor path — covered by sub-task 1 (repo rename)
- ArgoCD app definition references old overlay path — covered by sub-task 3
- No other services reference pal-e-production by name (checked network-policies.tf — only postgres and ollama netpols reference it)
Decomposition Assessment
12 AC across 4 repos, 13+ file targets. Clearly exceeds 5-minute rule. Ticket provides a 5-step decomposition with correct ordering and parallelism. Route to
skill-decompose-ticketfor sub-board creation.Recommendation
[SCOPE]Add "app-definition" story entry to project-pal-e-app user-stories table. Suggested wording: "As a platform operator, I want infrastructure names to match the naming convention so that discoverability and consistency are maintained."[DECOMPOSE]12 AC across 4 repos, 5-step decomposition provided in ticket body. Route toskill-decompose-ticketfor sub-board creation.
No blocking issues. Scope is solid. File targets all verified against live codebase.
-
Review: infra: rename pal-e-production to pal-e-app across all layers
review-989-2026-04-12Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone with consolidated bug refs
- [x] Repo -- Multi-repo identified
- [x] User Story -- present
- [x] Context -- thorough, explains 5-layer cascade
- [x] File Targets -- extensive, with "do not touch" list
- [x] Acceptance Criteria -- 11 items
- [x] Test Expectations -- 5 items with commands
- [x] Constraints -- 7 items, blue-green strategy documented
- [x] Checklist -- 10 items
- [x] Related -- cross-references present
All required sections for Feature template are present and well-populated.
Traceability
- [x] story:app-definition label -- present on board item
- [ ] story note MISSING -- No "app-definition" story found in project-pal-e-app user-stories section. Stories there are PA-S1 through PA-S5. [SCOPE] Create user story entry "app-definition" on project-pal-e-app user-stories section, or re-label to match an existing story key.
- [x] arch:pal-e-app label -- present on board item
- [ ] arch note MISSING -- search for "arch-pal-e-app" returned no results. [SCOPE] Create architecture note arch-pal-e-app for the pal-e-app component.
- [x] Forgejo issue -- forgejo_admin/pal-e-deployments#114, open
- [ ] definition-app note referenced in issue body does not exist in pal-e-docs (search returned empty). [BODY] Verify or create definition-app note.
File Targets
- [x]
pal-e-services/terraform/k3s.tfvars-- verified: containspal-e-productionservice key at line 202 - [x]
pal-e-deployments/overlays/pal-e-production/prod/-- verified: 4 files exist (kustomization.yaml, ingress.yaml, deployment-patch.yaml, harbor-creds.enc.yaml) - [x]
pal-e-deployments/overlays/pal-e-docs/prod/kustomization.yaml-- verified: lines 54, 71 contain commented pal-e-production cross-namespace refs - [x]
pal-e-platform/terraform/modules/monitoring/main.tflines 386-388 -- verified: blackbox probe name/url/labels for pal-e-production - [x]
pal-e-platform/terraform/modules/monitoring/main.tflines 649-661 -- verified: golden signals dashboard ConfigMap - [x]
pal-e-platform/terraform/modules/monitoring/main.tflines 730-741 -- verified: embedding worker ServiceMonitor with pal-e-production namespace - [x]
pal-e-platform/terraform/dashboards/pal-e-production-golden-signals.json-- verified: exists, 14 occurrences of pal-e-production - [x]
pal-e-platform/terraform/modules/ops/main.tflines 109-125 -- verified: embedding worker metrics service in pal-e-production namespace - [x]
pal-e-platform/terraform/modules/ops/variables.tfline 2 -- verified: variable description references pal-e-production - [x]
pal-e-platform/terraform/modules/database/main.tflines 59-67 -- verified: namespace data source + postgres secret - [x]
pal-e-platform/terraform/modules/database/outputs.tfline 12 -- verified: output description - [x]
pal-e-platform/terraform/network-policies.tflines 172, 196 -- verified: cross-namespace allow rules - [x]
pal-e-platform/terraform/secrets.auto.tfvars.exampleline 35 -- verified: secrets comment
All 13 file targets verified. Line numbers are accurate.
Repo Placement
Issue is filed on pal-e-deployments but touches 3 repos (pal-e-services, pal-e-deployments, pal-e-platform) plus the Forgejo repo rename. This is correctly identified in the issue body. Multi-repo coordination is acknowledged.
Dependencies
- Board items #714 (pal-e-platform#257 "Namespace rename pal-e-docs-app to pal-e-app") and #712 (pal-e-platform#255 "Keycloak client rename") are related naming work -- potential ordering dependency not documented.
- Board items #979 and #980 are filed against pal-e-production repo -- these will need URL updates after repo rename.
- Board items #716, #717 reference pal-e-production issues -- Forgejo issue URLs on these board items will break after repo rename.
- Consolidated bugs (#99, pal-e-deployments#97, #81) are listed as related but dependency ordering is clear (this ticket resolves them).
Acceptance Criteria
11 acceptance criteria. Most are verifiable by an agent (kubectl, curl, grep, tofu plan). The criteria are clear and testable. However, 11 AC across 3 repos plus a Forgejo admin API call is too many for a single agent pass.
Blast Radius
- Grep confirms 34 occurrences of "pal-e-production" in pal-e-platform/terraform/ and 16 in pal-e-deployments. The ticket's "60+ references" claim is roughly correct when including the dashboard JSON (14 alone).
- Existing board items referencing pal-e-production Forgejo URLs (#979, #980, #716, #717) will have broken issue links after rename. These need updating.
- monitoring/main.tf already has BOTH a pal-e-production probe (line 386) AND a pal-e-app probe (line 391) -- the new probe exists, so the rename is partially in progress. Ticket should note this to avoid creating a duplicate.
- The embedding worker references (ops/main.tf, monitoring/main.tf) use a
var.pal_e_production_namespacevariable -- renaming this variable cascades through the module call in the root module. Ticket should document this terraform variable rename.
Decomposition Assessment
NEEDS DECOMPOSITION. This ticket fails the 5-minute rule on all dimensions:
- 13+ file targets across 3 repos (threshold: >3 files across >2 repos)
- 11 acceptance criteria (threshold: >5)
- Estimated agent work: 30+ minutes (blue-green across 3 repos with tofu apply steps)
- Natural decomposition: (1) Forgejo repo rename, (2) pal-e-services terraform, (3) pal-e-deployments kustomize, (4) pal-e-platform monitoring/network-policies, (5) validation + old infra cleanup
Route to
skill-decompose-ticketfor sub-board creation.Recommendation
[SCOPE]Create user story entry "app-definition" on project-pal-e-app user-stories section, or relabel board item to match an existing story key (PA-S1 through PA-S5).[SCOPE]Create architecture note arch-pal-e-app for the pal-e-app component.[BODY]Note that monitoring/main.tf already has a pal-e-app probe at line 391 -- ticket should clarify this is a remove-old, not add-new for that specific target.[BODY]Document the terraform variable rename:var.pal_e_production_namespacemust becomevar.pal_e_app_namespace(affects ops/variables.tf, database/main.tf, database/outputs.tf, and the root module call).[BODY]Add note about board items (#979, #980, #716, #717) whose Forgejo issue URLs will break after repo rename -- these need URL updates.[DECOMPOSE]13 file targets across 3 repos, 11 AC, estimated 30+ min. Route to skill-decompose-ticket. Natural split: (1) Forgejo repo rename + Harbor re-tag, (2) pal-e-services terraform, (3) pal-e-deployments kustomize, (4) pal-e-platform terraform, (5) validation + cleanup.
Architecture 3
-
Deployment: pal-e-app
arch-deployment-pal-e-appDeployment: pal-e-app
Diagram
graph TB subgraph Public["Public Internet"] Browser[Browser / Mobile] end subgraph TS["Tailscale Network"] subgraph k3s["k3s Cluster"] subgraph ns_landing["Namespace: pal-e-landing"] Landing["pal-e-landing\nnginx / adapter-static"] end subgraph ns_app["Namespace: pal-e-app"] App["pal-e-app\nSvelteKit adapter-node\nPort 3000"] end subgraph ns_kc["Namespace: keycloak"] KC["Keycloak\nRealm: pal-e"] end subgraph ns_api["Namespace: pal-e-docs"] API["pal-e-docs API\nFastAPI\nPort 8000"] Worker["Embedding Worker"] end subgraph ns_db["Namespace: cnpg-system"] DB["PostgreSQL\nCNPG Cluster"] end end F1["Funnel: pal-e.tail5b443a.ts.net"] F2["Funnel: pal-e-app.tail5b443a.ts.net"] F3["Funnel: keycloak.tail5b443a.ts.net"] F4["Funnel: pal-e-docs.tail5b443a.ts.net"] end Browser -->|HTTPS| F1 --> Landing Browser -->|HTTPS| F2 --> App Browser -->|HTTPS| F3 --> KC Landing -.->|Login redirect| KC App -->|PKCE auth| KC App -->|Bearer API calls| API API --> DB KC --> DBComponents
Component Purpose Notes pal-e-landing Public landing page for Pal-E Enterprises Not yet deployed. New repo, static site, nginx or adapter-static. Hostname: pal-e.tail5b443a.ts.net pal-e-app Authenticated SvelteKit frontend Currently deployed as pal-e-docs-app in namespace pal-e-docs-app. Needs namespace rename. Hostname: pal-e-app.tail5b443a.ts.net Keycloak OIDC identity provider Running in keycloak namespace. Realm: pal-e. Client: pal-e-docs-app (needs rename to pal-e-app). pal-e-docs API Content API + authorization enforcement Running in pal-e-docs namespace. FastAPI. Will add UserProjectPermission query layer. Embedding Worker Vector embedding for semantic search Sidecar in pal-e-docs namespace. Uses Ollama. PostgreSQL Persistent storage for all services CNPG-managed cluster. Shared by pal-e-docs and Keycloak. Key Decisions
- All ingress via Tailscale Funnels. No cert-manager, no Traefik. Each service gets its own Tailscale hostname with automatic TLS.
- pal-e-landing gets its own namespace and funnel. Separate from pal-e-app because it's a different deployment (static vs node) with a different audience (public vs authenticated).
- Namespace rename needed. Current pal-e-docs-app namespace → pal-e-app. This is a deployment coordination task across ArgoCD, Tailscale Ingress, and the Keycloak client.
- ArgoCD manages deployments. pal-e-deployments repo has kustomize overlays. New services need overlay creation + ArgoCD Application.
- CI via Woodpecker. Builds push images to Harbor, trigger ArgoCD sync.
Related
- Domain Model: pal-e-app — entity relationships
- Data Flow: pal-e-app — runtime flows
- Project: pal-e-app — project page
- SOP: Platform Terraform Changes — for infra changes
- Service Onboarding SOP — for new service deployment
-
Data Flow: pal-e-app
arch-dataflow-pal-e-appData Flow: pal-e-app
Diagram
Flow 1: Registration and First Login
sequenceDiagram participant U as User (Marcus/Mom) participant L as pal-e-landing participant K as Keycloak participant A as pal-e-app participant D as pal-e-docs API participant DB as PostgreSQL U->>L: Visit pal-e.tail5b443a.ts.net U->>L: Fill registration form L->>K: Redirect to Keycloak registration K->>K: User creates account (username, password) K-->>L: Redirect back (registered) Note over U,DB: Lucas sees new user in Keycloak, assigns project permissions U->>L: Click "Login" L->>K: Redirect to Keycloak login K->>K: Authenticate (username + password) K-->>A: Redirect with PKCE auth code A->>K: Exchange code for JWT A->>D: GET /projects (Bearer token) D->>DB: SELECT projects WHERE user has permission DB-->>D: Filtered project list D-->>A: [westside-basketball] A->>A: Render scoped sidebar and homeFlow 2: Authenticated Board Interaction
sequenceDiagram participant U as User participant A as pal-e-app participant D as pal-e-docs API participant DB as PostgreSQL U->>A: Navigate to /boards/board-westside-basketball A->>D: GET /boards/board-westside-basketball/items (Bearer) D->>DB: Check UserProjectPermission for sub + project alt Has access DB-->>D: Permission found (read or write) D->>DB: SELECT board items DB-->>D: Items D-->>A: Board items JSON A->>A: Render kanban columns else No access DB-->>D: No permission row D-->>A: 403 Forbidden A->>A: Show "access denied" endComponents
Component Purpose Notes pal-e-landing Public entry point, registration form Static site. No auth. Redirects to Keycloak for login. Keycloak OIDC provider — registration, login, password reset Realm: pal-e. Public client with PKCE. Self-registration TBD. pal-e-app Authenticated SPA — renders scoped content SvelteKit, keycloak-js. Client-side API calls with Bearer token. pal-e-docs API Content + authorization — filters by user permissions FastAPI. Extracts sub from JWT, queries UserProjectPermission. PostgreSQL Persistent storage — notes, boards, permissions CNPG-managed. UserProjectPermission is the new table. Key Decisions
- Client-side auth, not SSR. pal-e-app is a SPA (ssr=false). keycloak-js handles the PKCE flow in the browser. This avoids server-side session management.
- Permission check at API layer. The pal-e-docs API checks UserProjectPermission on every request, not the frontend. Frontend renders what the API returns — no client-side permission logic.
- Registration may be manual initially. Lucas creates Keycloak users and assigns project permissions. Self-registration can be enabled on the Keycloak realm later if needed.
- Token refresh is automatic. keycloak-js refreshes 30 seconds before expiry. No user-visible session interruption.
Related
- Domain Model: pal-e-app — entity relationships
- Deployment: pal-e-app — infrastructure layout
- Project: pal-e-app — project page
-
Domain Model: pal-e-app
arch-domain-pal-e-appDomain Model: pal-e-app
Diagram
erDiagram KeycloakUser { string sub PK "Keycloak subject ID (JWT claim)" string preferred_username string email string name } UserProjectPermission { int id PK string keycloak_sub FK "References KeycloakUser.sub" int project_id FK "References Project.id" string permission "read | write" timestamp created_at } Project { int id PK string slug UK string name string platform bool is_public } Note { int id PK string slug UK string title string note_type bool is_public string parent_slug FK "nullable — hierarchy" int project_id FK "nullable — ownership" } Board { int id PK string slug UK string name int project_id FK } BoardItem { int id PK int board_id FK string column string title string item_type } KeycloakUser ||--o{ UserProjectPermission : "has permissions" Project ||--o{ UserProjectPermission : "grants access to" Project ||--o{ Note : "contains" Project ||--o{ Board : "has" Board ||--o{ BoardItem : "contains" Note ||--o{ Note : "parent-child"Components
Component Purpose Notes KeycloakUser Identity — who is this person Not a local table. Extracted from JWT subclaim at request time.UserProjectPermission Authorization — what can this person see NEW table in pal-e-docs Postgres. Maps keycloak_sub → project → read/write. Project Scope boundary for permissions Existing entity. User gets project access → sees all child notes and boards. Note Content unit — docs, SOPs, stories, phases Existing. Has parent_slug for hierarchy. Permission cascades from project. Board Kanban view of project work Existing. One board per project. Visible if user has project access. BoardItem Work item on a board Existing. Inherits visibility from board/project. Key Decisions
- Keycloak for authn, pal-e-docs for authz. Keycloak answers "who are you" (JWT). The pal-e-docs API answers "what can you see" (UserProjectPermission table). This avoids coupling Keycloak realm roles to pal-e-docs project structure.
- Project is the permission boundary, not note. Per-note permissions would create O(n) complexity. Project-scoped access with parent-child cascade is O(1) per query — check project, done.
- No local user table. The keycloak_sub in UserProjectPermission is the only user reference. User profile data stays in Keycloak. No sync, no drift.
- is_public bypasses permissions. Public notes are visible to everyone regardless of project assignment. This preserves the existing unauthenticated experience.
- read vs write is the only permission axis. No viewer/editor/admin hierarchy. Two levels is sufficient for stakeholder vs operator access.
Related
- Data Flow: pal-e-app — how auth flows at runtime
- Deployment: pal-e-app — where services run
- Project: pal-e-app — project page
Board 1
-
pal-e-app
board-pal-e-appNo content
Repos 1
-
pal-e-appactive