Every route now declares its access rule explicitly and is enforced
through the shared resolution algorithm (permissions.md):
- PermissionGuard + decorators (@RequiresPondRole, @RequiresPagePermission,
@RequiresAttachmentPermission, @AuthenticatedOnly) applied to every
route; a route-enumeration test proves full coverage alongside
@Public()/Site-Admin-guarded routes.
- 404/403 policy (documented in README conventions): denied reads answer
404 (existence hiding), denied writes on readable things answer 403;
trash views need write capability (ADR 0013).
- PermissionService resolves page/pond questions via the shared resolver,
with an in-process pond-context cache (grants + label parents) that is
invalidated on every grant/label-tree change and TTL-bounded as a
multi-process safety net. Grant changes also fire pond_access_changed
for collab revalidation (#39/#53).
- shared: pond-scope resolution (hasPondRole, canSeePond) next to the
page resolver; grant wire schemas + GrantView.
- Owner Pond-Admin grants: migration backfill for all existing ponds,
created transactionally with every new pond (shared + personal + seed).
- Grant CRUD under /ponds/:id/grants (pond_admin-gated) with structural
and referential validation, last-admin protection, audit logs.
- InterimAccessService deleted; page lists, search, backlinks, phantom
links, and trash listings are filtered per page through the resolver;
collab tokens are now truly ro for readers.
- Fixture-matrix e2e (reader/editor/pond admin/foreign, label-deny,
authenticated-subject, revoke-then-immediate-deny cache test).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY
Prisma models per data-model.md: users (status enum, site-admin flag),
user_identities (password provider now, OIDC later — subject is the
stable user id), sessions (hashed ids), auth_tokens (hashed, single-
use), plus rate_limits and mail_outbox for the upcoming M1 stories.
UsersService creates accounts transactionally with Argon2id-hashed
password identities (OWASP parameters, rehash detection) and maps
uniqueness violations to field-level conflicts. Database-backed suites
run when TEST_DATABASE_URL is set — locally against the dev db, in CI
via a new postgres service container; shared auth schemas (username,
password policy incl. common-password blocklist) ship with tests.
Closes#10
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>