Domain Model: pal-e-app

arch-domain-pal-e-app Architecture

architecture active

Domain Model: pal-e-app

Diagram

Components

Component Purpose Notes
KeycloakUser Identity — who is this person Not a local table. Extracted from JWT <code>sub</code> claim 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.