|
All checks were successful
CD / Build and push images (push) Successful in 3m13s
CI / Lint, typecheck, test (push) Successful in 2m30s
CI / Auth e2e pack (push) Successful in 3m21s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
Anonymous visitors read what `public` grants allow, via the SPA and a server-rendered HTML endpoint for crawlers / PDF export (ADR 0005/0009). - api `public/`: `GET /public/:pondSlug/:pageSlug` returns a self-contained HTML document (content cache + minimal chrome + canonical link, no session-dependent content), and `…/content` returns JSON for the SPA. Both are `@Public()` and resolve the `public` subject through the shared resolver (PermissionService) — denied or missing → 404, so non-public pages never reveal their existence (security.md). Cached image nodes (`data-file-id`) are resolved to `/api/v1/media/:fileId` for the static render. - media: `GET /media/:fileId` is `@Public()` too, so embedded images on a public page stream to anonymous visitors; the attachment guard still gates on the `public` grant (non-public → 404). - web: a lightweight read-only `PublicPageView` at `/public/:pondSlug/:pageSlug` (outside the auth guard) renders the server HTML — deliberately without importing the collaborative editor, so anonymous readers load no editor bundle. New `public` i18n namespace (de+en). - tests: `public.e2e.db.test.ts` (HTML + JSON served for a public page; a non-public page never resolves; removing the grant 404s both) and a browser `public` pack (anonymous reads a public page and its image via the SPA; a non-public page shows "not found") with its own CI step. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1 |
||
|---|---|---|
| .. | ||
| access-rules.spec.ts | ||
| auth.spec.ts | ||
| backlinks.spec.ts | ||
| collab-permissions.spec.ts | ||
| collab.spec.ts | ||
| content.spec.ts | ||
| editor.spec.ts | ||
| helpers.ts | ||
| image.spec.ts | ||
| labels.spec.ts | ||
| link.spec.ts | ||
| markdown.spec.ts | ||
| members.spec.ts | ||
| offline.spec.ts | ||
| public.spec.ts | ||
| README.md | ||
| reorder.spec.ts | ||
| search.spec.ts | ||
| sidebar.spec.ts | ||
| smoke.spec.ts | ||
| trash.spec.ts | ||
| wikilink.spec.ts | ||
End-to-end tests
Playwright suites, most local-only — three run in CI/CD:
| Suite | Target | Where it runs |
|---|---|---|
smoke.spec.ts |
any deployed stage | CD pipeline against https://test.dorfteich.cloud after every deploy |
auth.spec.ts |
full local stack with Mailpit | CI job auth-e2e on every PR/push; locally against the dev stack |
content.spec.ts |
full local stack | same CI job auth-e2e (a second step), right after the auth pack |
| everything else | full local stack | locally only — editor/sidebar/image/link/markdown/trash.spec.ts |
content.spec.ts is the M2 content regression pack (issue #32): page
lifecycle, editor basics, image paste, Markdown round-trip, and trash —
enough to catch a regression across the whole content model without
re-running every edge case the feature-specific packs above already cover.
Its Markdown round-trip test is a real regression pin, not just a smoke
check: it compares the seeded "Every Element" fixture page's exported
Markdown byte-for-byte against the checked-in content-page.md (see
"Content fixtures" below) — any schema/serializer change that alters how a
node round-trips fails it, once the seed has re-run against the changed
code (build → migrate → seed → test, exactly CI's order).
Running locally
# 1. Stack: database + Mailpit, api (3001), web dev server (5173)
docker compose -f deploy/compose/docker-compose.yml -f deploy/compose/compose.dev.yml up -d db mailpit
DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich pnpm --filter @dorfteich/api db:seed
DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich PORT=3001 pnpm --filter @dorfteich/api start:dev &
pnpm --filter @dorfteich/web dev &
# 2. Tests
E2E_BASE_URL=http://localhost:5173 E2E_MAILPIT_URL=http://localhost:8025 pnpm --filter @dorfteich/web e2e
auth.spec.ts skips itself when E2E_MAILPIT_URL is unset, so the CD
smoke run never trips over it.
Fixture matrix
Seeded by pnpm --filter @dorfteich/api db:seed (idempotent — re-running
never duplicates). Shared password: fixture passwort 123. Fixtures exist
only on dev machines and disposable CI/Test databases.
| Username | State | Purpose |
|---|---|---|
fixture-admin |
active, Site Admin | admin UI/permissions cases |
fixture-user |
active | regular journeys, settings, sessions |
fixture-editor |
active | second regular account for the collab-permissions pack (reader/editor of another's pond) |
fixture-viewer |
active | signed-in non-member for authenticated/public access-rule cases (issue #55) |
fixture-pending |
e-mail not verified | unverified-login cases |
Content fixtures
db:seed also creates a shared pond content-fixtures (owned by
fixture-user) with two pages, for the content regression pack and manual
QA:
- Every Element (
every-element) — every editor schema node and mark (issue #24: headings 1–4, all list types, table, blockquote, code block, horizontal rule, hard break, and all five marks). Loaded from the checked-inapps/api/prisma/fixtures/content-page.yjs, a Yjs snapshot generated from the human-readablecontent-page.mdnext to it —content-page.mdis the thing to read or edit; the.yjsfile is a build artifact of it, not source. - Fixture Image (
fixture-image) — one real, servable uploaded image (the placeholderfileIdinside the Markdown fixture above is not a real attachment; this page's image is).
Regenerating after editing content-page.md:
pnpm --filter @dorfteich/api fixtures:regenerate
This is deterministic — re-running without editing the Markdown produces a
byte-identical .yjs file (the script pins the Yjs document's clientID,
which is otherwise randomized per Y.Doc instance) — and it refuses to
write a snapshot that isn't a fixed point of the Markdown round-trip
(docToMarkdown(markdownToDoc(x)) === x), so a stale fixture can't get
checked in silently.
Conventions
- New feature packs get their own
<feature>.spec.tsnext to these and extend the fixture matrix here (permission matrix arrives with M5, issue #60). - Use
contextForUser()fromhelpers.tsfor signed-in tests — it logs in through the api and hands you a browser context with the session cookie, no UI login repetition. - Flaky tests are defects (ADR 0014): fix or quarantine immediately.