cc9c70287c
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 5255cdce06 |
Fix latenten Flake in links.service.db.test (Phantom-Sortierung)
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 4m24s
CI / Build container images (pull_request) Successful in 3m45s
CI / Auth e2e pack (pull_request) Successful in 6m48s
CI / Import/export fidelity gate (pull_request) Successful in 50s
CI / Lint, typecheck, test (push) Successful in 4m31s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 6m45s
CI / Import/export fidelity gate (push) Successful in 54s
CD / Build and push images (push) Successful in 16s
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 11s
pondGraph-Test sortierte die EMPFANGENEN Phantom-Slugs, verglich aber gegen ein UNsortiertes Literal. Da beide Slugs (ghost-<sfx>, ghost-secret-<sfx>) den Zufalls-Suffix teilen, kippt ihre Sortierreihen- folge auf ~1/5 der Suffixe (wenn sfx[0] > 's') → nicht-deterministischer Fehlschlag. In CI-Lauf 372 traf es zu (Suffix „vpxwe…"). Fix: beide Seiten sortieren. Vorbestehender Bug, unabhängig von M17–M19. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155v2aT8AG1kZDQEZiCLBWC |
|||
| e957c2a28f |
Pond-wide wikilink graph endpoint (#111)
All checks were successful
CD / Build and push images (push) Successful in 4m0s
CD / Deploy to Test (push) Successful in 9s
CI / Lint, typecheck, test (push) Successful in 4m21s
CI / Build container images (push) Has been skipped
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 11s
CI / Auth e2e pack (push) Successful in 5m41s
CI / Import/export fidelity gate (push) Successful in 47s
GET /ponds/:pondId/links returns the caller's readable slice of the wikilink graph in one read: nodes (id, title, slug, labelIds for the coloring), resolved edges deduplicated per direction (a rename can leave several slugs pointing at one target), and phantom targets with their referrer ids. An edge survives only when both endpoints are readable; a phantom disappears entirely once its last readable referrer is filtered — a hidden page's existence never leaks through any of the three collections. Trashed pages and their links are excluded. Shared PondGraphView types feed the knowledge-graph views (#112/#113). DB tests cover the owner's full graph, the label-DENY reader slice, edge dedup, trash exclusion, and labelIds on nodes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
|||
| 0c6494f209 |
Enforce permissions in API guards and retire interim access (#52)
All checks were successful
CD / Build and push images (push) Successful in 2m54s
CI / Lint, typecheck, test (push) Successful in 2m25s
CI / Auth e2e pack (push) Successful in 2m58s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m12s
CD / Promote to Int (push) Successful in 12s
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 |
|||
| 6c38abc20c |
Add backlinks panel and phantom-pages view (#48)
All checks were successful
CD / Build and push images (push) Successful in 3m3s
CI / Lint, typecheck, test (push) Successful in 2m15s
CI / Auth e2e pack (push) Successful in 2m49s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 8s
CD / Smoke tests against Test (push) Successful in 1m12s
CD / Promote to Int (push) Successful in 11s
Make wikilink relations visible: what links here, and which linked pages
do not exist yet.
- shared: `BacklinkView` gains a plain-text `snippet` for context.
- api: `LinksService` includes a short snippet (from the content cache) with
each backlink and phantom referrer.
- web:
- `BacklinksPanel` below a page in read mode: a collapsible "Linked from"
list (title + snippet, links to the source), hidden when empty. Appears
on load from the #47 index.
- `PhantomPagesView` in pond settings: wikilink targets that do not exist
yet, each with its referrers and a create shortcut that makes the page
under the phantom slug — resolving those links (#47) and navigating to it.
- i18n `links` namespace (de + en); backlinks + missing-pages styles.
- e2e `backlinks.spec.ts` (new CI pack): a link created in the editor appears
as a backlink on the target; the missing-pages view lists a phantom slug and
creating it navigates to the new page.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY
|
|||
| 14e69b399c |
Add wikilink index, backlinks API, and phantom resolution (#47)
All checks were successful
CD / Build and push images (push) Successful in 3m2s
CI / Lint, typecheck, test (push) Successful in 2m16s
CI / Auth e2e pack (push) Successful in 2m44s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 11s
Maintain a server-side `page_links` index on every content change so
backlinks and missing-target ("phantom") links can be queried.
- prisma: `PageLink` (from_page_id, nullable to_page_id, target_slug;
unique per (from, slug); cascade on source purge, set-null on target
purge); migration.
- shared: `extractWikilinkSlugs(doc)` (distinct target slugs) and the
`BacklinkView` / `PhantomLinkView` read shapes.
- collab: the persistence hook (#35) now rewrites the source page's outgoing
links in the same transaction as the content cache — one row per distinct
wikilink slug, resolved to a page in the same pond (null = phantom).
- api: `GET /pages/:id/backlinks` (permission-filtered — wikilinks resolve
within a pond, so seeing the pond is the read right) and
`GET /ponds/:id/phantom-links` (missing targets grouped with their
referrers). Creating or renaming a page to a slug that pages already link
to resolves those phantom rows; because links store the target's id,
backlinks survive a later rename of the target's slug.
- tests: shared extraction unit test; collab persistence db test (store
writes resolved + phantom rows and rewrites the index); api LinksService
db test (backlinks, permission filter, phantom aggregation, create/rename
resolution, id-based backlinks survive target rename).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY
|