Drive a Playwright suite that walks the entire Angular component/route surface and performs every meaningful user action, starting exactly as an anonymous visitor landing on the site and expanding into authenticated, parent, and staff/admin journeys — toward 100% E2E coverage of the app's routes and interactive flows.
While the suite runs, programmatically pull telemetry from Jaeger (traces) and Seq (logs) so that every discovered failure comes with backend visibility (which service, which span, which log line), turning the E2E run into a full-system observability harness rather than just a UI checker.
Work proceeds from master in spikersoft-angular (E2E lives there today) with a small supporting change in spikersoft-backend for verification test-hooks (see §4). Fixes discovered along the way are filed as their own tickets and linked back here.
Current base (what already exists)
spikersoft-angular/playwright.config.ts — serves the prebuilt dist/spikersoft/browser on http://127.0.0.1:4200 via serve; testDir: ./e2e/playwright.
e2e/playwright/example.spec.ts (app-loads smoke) and video-call.spec.ts (two-context fake-media smoke).
CI job e2e-smoke in .gitea/workflows/main.yml (prebuilds prod bundle, installs chromium, runs the video call grep; continue-on-error: true).
Gap: no data-testid/data-e2e selector convention across the app (only the diagram dev-tool lib uses data-testid). Robust selectors are a prerequisite for stable full coverage.
Route surface to cover (from routing audit of projects/spikersoft/src/routes.ts)
Public/anonymous:/, /intro, /mission, /our-hardware, /legacy-systems, /develop, /contact, /syllabus, /team, /employment, /links(/:id), /blog, /sponsor (+ donate/profile), /tree-of-knowledge, /geography/*, /brain-forge, /cortex-quest, /wisdom-well, /chess, /ai, /classes, /cpu-dashboard, public coding topics, and the /tools shell + ~25 named-outlet dev tools, /parental-approve/:token, /organization/confirm, /** (404).
Auth-gated (AuthGuard → Keycloak):/home, /services, /reading-journey, /reader/:bookId, /info-vault, /fundraisers, /blog/create, most /*-game routes, /calendar, /video-call, /chat, /profile, /tracker, Marks (/mark/*).
Coverage is tracked against a committed route manifest so "100%" is measurable (every route visited + its primary actions exercised).
The hard part: signup verification (email code + Twilio SMS)
Registration is a 4-step stepper (registration-stepper.component) ending in email + phone verification:
POST /api/authentication/initiate-pre-registration → creates a Mongo PreRegistration with emailVerificationCode (6 digits) + emailVerificationToken.
POST /api/authentication/verify-pre-registration-email (code or token) → triggers Twilio Verify SMS.
POST /api/authentication/verify-pre-registration-phone → checks the code with Twilio Verify (code is NOT stored locally).
POST /api/authentication/complete-pre-registration → creates the Keycloak user once fully verified.
Email is automatable today (read emailVerificationCode/emailVerificationToken from Mongo PreRegistrations, or hit the GET verify link). SMS is not — no bypass exists.
Proposed test hook (needs confirmation, backend change): in non-prod only, thread the existing SendVerificationCodeCommand.CustomCode through pre-registration behind an env flag (e.g. PreRegistration:E2E:Enabled + E2E_SMS_CODE), OR provide an E2E-profile fake ITwilioVerifyService that accepts a fixed code, OR a test-only endpoint that marks PhoneVerified for a known pre-registration id. Must be impossible to enable in Production. Related existing flags: Authentication:UseTestAuthentication + TestAuthenticationHandler (API auth bypass for authenticated tests), PreRegistration:Bypass* (cooldowns/abuse only — not verification).
For authenticated journeys generally, obtain a Keycloak token via direct grant against a dedicated non-prod test realm/user (or reuse UseTestAuthentication for API-level setup), and use Playwright storage-state to skip the interactive login on most specs.
Telemetry integration (Jaeger + Seq)
Build a reusable e2e/telemetry client used by specs and fixtures:
Jaeger (query API on the internal UI, http://<node-ip>:16686): GET /api/services, GET /api/traces?service=SpikerSoft%20API&start&end&tags&lookback, GET /api/traces/:id. Correlate by test time-window + service + tags (and, once the SPA emits W3C traceparent, by trace id).
Seq (https://seq.spikersoft.com): GET /api/events?filter=<seq-query>&count=N with X-Seq-ApiKey. Filter by ServiceName, Environment, level, and the test's correlation id.
Endpoints/keys via env (JAEGER_QUERY_URL, SEQ_URL, SEQ_API_KEY). A Playwright fixture snapshots "errors in Seq / error spans in Jaeger during this test" and attaches them to the report on failure.
(Stretch) Have the SPA propagate a per-session correlation header so browser actions map 1:1 to backend traces.
Phased plan (each phase = its own linked sub-issue)
P0 — Harness & telemetry: page-object base, route manifest + coverage reporter, JaegerClient/SeqClient, failure-time telemetry fixture, CI wiring (promote e2e-smoke beyond continue-on-error for the anonymous suite). Decide target environment (dedicated staging vs prod-read-only).
P1 — Anonymous walk: every public route loads, primary nav works, no console/JS errors, key CTAs, /tools + every dev-tool, 404. (No backend mutations.)
P2 — Selector hardening: introduce a data-testid convention across the components the walk touches.
P3 — Registration & verification: land the verification test-hook (§4), then full signup happy-path + validation/error paths; create a reusable "fresh verified user" fixture.
P4 — Authenticated core: login/logout/profile, reading journey, book reader, calendar, chat, AI, lessons + code playgrounds, games.
Every route in the manifest is visited and its primary actions exercised by a passing spec.
Signup (incl. email + SMS verification) is fully automated via a safe, non-prod-only hook.
Each spec has a telemetry fixture that surfaces correlated Jaeger spans + Seq logs on failure.
CI runs the suite (anonymous suite blocking; authenticated suites at least nightly) with a coverage report.
Open decisions (need a call before/at P0)
Target environment for E2E: stand up a dedicated staging stack, or run read-mostly against prod with disposable test accounts? (affects data-safety of P3+.)
Verification hook shape (CustomCode+flag vs fake service vs test endpoint) — security review required so it can never arm in Production.
Whether to invest in SPA → W3C traceparent propagation now (best trace correlation) or defer.
## Vision
Drive a Playwright suite that **walks the entire Angular component/route surface and performs every meaningful user action**, starting exactly as an anonymous visitor landing on the site and expanding into authenticated, parent, and staff/admin journeys — toward **100% E2E coverage of the app's routes and interactive flows**.
While the suite runs, **programmatically pull telemetry from Jaeger (traces) and Seq (logs)** so that every discovered failure comes with backend visibility (which service, which span, which log line), turning the E2E run into a full-system observability harness rather than just a UI checker.
> Work proceeds from `master` in `spikersoft-angular` (E2E lives there today) with a small supporting change in `spikersoft-backend` for verification test-hooks (see §4). Fixes discovered along the way are filed as their own tickets and linked back here.
---
## Current base (what already exists)
- `spikersoft-angular/playwright.config.ts` — serves the prebuilt `dist/spikersoft/browser` on `http://127.0.0.1:4200` via `serve`; `testDir: ./e2e/playwright`.
- `e2e/playwright/example.spec.ts` (app-loads smoke) and `video-call.spec.ts` (two-context fake-media smoke).
- CI job `e2e-smoke` in `.gitea/workflows/main.yml` (prebuilds prod bundle, installs chromium, runs the `video call` grep; `continue-on-error: true`).
- **Gap:** no `data-testid`/`data-e2e` selector convention across the app (only the diagram dev-tool lib uses `data-testid`). Robust selectors are a prerequisite for stable full coverage.
---
## Route surface to cover (from routing audit of `projects/spikersoft/src/routes.ts`)
- **Public/anonymous:** `/`, `/intro`, `/mission`, `/our-hardware`, `/legacy-systems`, `/develop`, `/contact`, `/syllabus`, `/team`, `/employment`, `/links(/:id)`, `/blog`, `/sponsor` (+ donate/profile), `/tree-of-knowledge`, `/geography/*`, `/brain-forge`, `/cortex-quest`, `/wisdom-well`, `/chess`, `/ai`, `/classes`, `/cpu-dashboard`, public coding topics, and the `/tools` shell + ~25 named-outlet dev tools, `/parental-approve/:token`, `/organization/confirm`, `/**` (404).
- **Auth-gated (AuthGuard → Keycloak):** `/home`, `/services`, `/reading-journey`, `/reader/:bookId`, `/info-vault`, `/fundraisers`, `/blog/create`, most `/*-game` routes, `/calendar`, `/video-call`, `/chat`, `/profile`, `/tracker`, Marks (`/mark/*`).
- **Special guards:** `ReadingInterestGuard` (`/reading-journey`), `ParentGuard` (`/parent-dashboard`), `RoleGuard` Admin/Staff (`/admin/*`, `/keycloak-admin`), `unsavedChangesGuard` (`/profile`).
Coverage is tracked against a committed **route manifest** so "100%" is measurable (every route visited + its primary actions exercised).
---
## The hard part: signup verification (email code + Twilio SMS)
Registration is a 4-step stepper (`registration-stepper.component`) ending in email + phone verification:
- `POST /api/authentication/initiate-pre-registration` → creates a Mongo `PreRegistration` with `emailVerificationCode` (6 digits) + `emailVerificationToken`.
- `POST /api/authentication/verify-pre-registration-email` (code or token) → triggers Twilio Verify SMS.
- `POST /api/authentication/verify-pre-registration-phone` → checks the code with **Twilio Verify** (code is NOT stored locally).
- `POST /api/authentication/complete-pre-registration` → creates the Keycloak user once fully verified.
**Email is automatable today** (read `emailVerificationCode`/`emailVerificationToken` from Mongo `PreRegistrations`, or hit the GET verify link). **SMS is not** — no bypass exists.
**Proposed test hook (needs confirmation, backend change):** in non-prod only, thread the existing `SendVerificationCodeCommand.CustomCode` through pre-registration behind an env flag (e.g. `PreRegistration:E2E:Enabled` + `E2E_SMS_CODE`), OR provide an E2E-profile fake `ITwilioVerifyService` that accepts a fixed code, OR a test-only endpoint that marks `PhoneVerified` for a known pre-registration id. Must be **impossible to enable in Production**. Related existing flags: `Authentication:UseTestAuthentication` + `TestAuthenticationHandler` (API auth bypass for authenticated tests), `PreRegistration:Bypass*` (cooldowns/abuse only — not verification).
For **authenticated journeys generally**, obtain a Keycloak token via direct grant against a dedicated non-prod test realm/user (or reuse `UseTestAuthentication` for API-level setup), and use Playwright storage-state to skip the interactive login on most specs.
---
## Telemetry integration (Jaeger + Seq)
Build a reusable `e2e/telemetry` client used by specs and fixtures:
- **Jaeger** (query API on the internal UI, `http://<node-ip>:16686`): `GET /api/services`, `GET /api/traces?service=SpikerSoft%20API&start&end&tags&lookback`, `GET /api/traces/:id`. Correlate by test time-window + service + tags (and, once the SPA emits W3C `traceparent`, by trace id).
- **Seq** (`https://seq.spikersoft.com`): `GET /api/events?filter=<seq-query>&count=N` with `X-Seq-ApiKey`. Filter by `ServiceName`, `Environment`, level, and the test's correlation id.
- Endpoints/keys via env (`JAEGER_QUERY_URL`, `SEQ_URL`, `SEQ_API_KEY`). A Playwright fixture snapshots "errors in Seq / error spans in Jaeger during this test" and attaches them to the report on failure.
- (Stretch) Have the SPA propagate a per-session correlation header so browser actions map 1:1 to backend traces.
---
## Phased plan (each phase = its own linked sub-issue)
- [ ] **P0 — Harness & telemetry:** page-object base, route manifest + coverage reporter, `JaegerClient`/`SeqClient`, failure-time telemetry fixture, CI wiring (promote `e2e-smoke` beyond continue-on-error for the anonymous suite). Decide target environment (dedicated staging vs prod-read-only).
- [ ] **P1 — Anonymous walk:** every public route loads, primary nav works, no console/JS errors, key CTAs, `/tools` + every dev-tool, 404. (No backend mutations.)
- [ ] **P2 — Selector hardening:** introduce a `data-testid` convention across the components the walk touches.
- [ ] **P3 — Registration & verification:** land the verification test-hook (§4), then full signup happy-path + validation/error paths; create a reusable "fresh verified user" fixture.
- [ ] **P4 — Authenticated core:** login/logout/profile, reading journey, book reader, calendar, chat, AI, lessons + code playgrounds, games.
- [ ] **P5 — Parent & family:** parental approval, parent dashboard, child-account flows.
- [ ] **P6 — Staff/Admin:** `/admin/*` review surfaces + `/keycloak-admin` named-outlet UI (role-scoped test users).
- [ ] **P7 — Realtime/media:** video-call two-party, gameserver, streaming (build on existing fake-media scaffold).
- [ ] **P8 — Coverage gate:** route-manifest coverage report in CI; ratchet toward 100%.
## Definition of done
- Every route in the manifest is visited and its primary actions exercised by a passing spec.
- Signup (incl. email + SMS verification) is fully automated via a safe, non-prod-only hook.
- Each spec has a telemetry fixture that surfaces correlated Jaeger spans + Seq logs on failure.
- CI runs the suite (anonymous suite blocking; authenticated suites at least nightly) with a coverage report.
## Open decisions (need a call before/at P0)
1. **Target environment** for E2E: stand up a dedicated staging stack, or run read-mostly against prod with disposable test accounts? (affects data-safety of P3+.)
2. **Verification hook** shape (CustomCode+flag vs fake service vs test endpoint) — security review required so it can never arm in Production.
3. Whether to invest in **SPA → W3C traceparent** propagation now (best trace correlation) or defer.
#310/blog crash on API failure — fixed in spikersoft-angular#90
#311 429s carry no CORS headers (middleware order) — fix open in spikersoft-backend#50
#312GET /api/interests 401s anonymously — fix open in spikersoft-backend#50
Environment decisions locked in
Live-is-test for now; safe-mode split deferred.
E2E origin is https://localhost:4200 (already in Keycloak redirect URIs + API CORS allowlist; https://127.0.0.1:4200 also added to Keycloak). The suite runs API-connected.
## Phase sub-issues + status
| Phase | Issue | Status |
|---|---|---|
| P0 Harness & telemetry | #313 | Largely done (PR spikersoft-angular#90); CI env wiring + coverage reporter remain |
| P1 Anonymous walk | #314 | Route-load coverage done, **25/25 green**; per-page actions + tools walk remain |
| P2 data-testid convention | #315 | Not started |
| P3 Registration & verification | #318 | Not started (SMS hook is the blocker) |
| P4 Authenticated core | #316 | Not started |
| P5 Parent & family | #317 | Not started |
| P6 Staff/Admin | #319 | Not started |
| P7 Realtime & media | #320 | Not started |
| P8 Coverage gate | #321 | Not started |
## Bugs found by the suite so far
- #308 `/geography` crash on API failure — **fixed** in spikersoft-angular#90
- #309 `/ai` blank render — triaged, harness assertion issue, **resolved** in spikersoft-angular#90
- #310 `/blog` crash on API failure — **fixed** in spikersoft-angular#90
- #311 429s carry no CORS headers (middleware order) — **fix open** in spikersoft-backend#50
- #312 `GET /api/interests` 401s anonymously — **fix open** in spikersoft-backend#50
## Environment decisions locked in
- Live-is-test for now; safe-mode split deferred.
- E2E origin is `https://localhost:4200` (already in Keycloak redirect URIs + API CORS allowlist; `https://127.0.0.1:4200` also added to Keycloak). The suite runs API-connected.
Foundation merged (PR #107): storage-state Keycloak login, 38-route + 9-tool authenticated walk, nightly full-suite workflow. Blocked on a seeded live-realm test user (E2E_USER_USERNAME/E2E_USER_PASSWORD in .env.e2e + repo secrets); journeys next
#341 rate limiter 503→429 — fix open (backend PR #59); the two /api/system/version allowlist entries in EXPECTED_CONSOLE_NOISE come out after it deploys
#344 (new, infra) SonarQube CE task fails server-side on every run — filed so the permanently-red context stops masking real regressions
## Phase status refresh (2026-07-03, evening)
| Phase | Issue | Status |
|---|---|---|
| P0 Harness & telemetry | #313 | **Closed** (PR #105 + #106 merged; `SEQ_API_KEY` repo secret still to be created) |
| P1 Anonymous walk | #314 | Console-error hard-fail merged (PR #106); only the id-dependent click-throughs remain (seeded-data dependent) |
| P2 data-testid convention | #315 | Closed |
| P3 Registration & verification | #318 | Not started (SMS hook blocker) |
| P4 Authenticated core | #316 | **Foundation merged** (PR #107): storage-state Keycloak login, 38-route + 9-tool authenticated walk, nightly full-suite workflow. Blocked on a seeded live-realm test user (`E2E_USER_USERNAME`/`E2E_USER_PASSWORD` in `.env.e2e` + repo secrets); journeys next |
| P5 Parent & family | #317 | Not started |
| P6 Staff/Admin | #319 | Not started (needs a staff-role test account; `/keycloak-admin` now properly RoleGuard-gated) |
| P7 Realtime & media | #320 | Not started |
| P8 Coverage gate | #321 | Anonymous baseline 32%; jumps to ~72% once P4 creds activate the authenticated walk |
## Bugs from the suite closed/open today
- #342 blockly ViewChild crash — **fixed** (PR #106)
- #343 /tree-of-knowledge anonymous 401 noise — **fixed** (PR #106)
- #340 /keycloak-admin missing RoleGuard — **fixed** (PR #108)
- #341 rate limiter 503→429 — **fix open** (backend PR #59); the two `/api/system/version` allowlist entries in `EXPECTED_CONSOLE_NOISE` come out after it deploys
- #344 (new, infra) SonarQube CE task fails server-side on every run — filed so the permanently-red context stops masking real regressions
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Vision
Drive a Playwright suite that walks the entire Angular component/route surface and performs every meaningful user action, starting exactly as an anonymous visitor landing on the site and expanding into authenticated, parent, and staff/admin journeys — toward 100% E2E coverage of the app's routes and interactive flows.
While the suite runs, programmatically pull telemetry from Jaeger (traces) and Seq (logs) so that every discovered failure comes with backend visibility (which service, which span, which log line), turning the E2E run into a full-system observability harness rather than just a UI checker.
Current base (what already exists)
spikersoft-angular/playwright.config.ts— serves the prebuiltdist/spikersoft/browseronhttp://127.0.0.1:4200viaserve;testDir: ./e2e/playwright.e2e/playwright/example.spec.ts(app-loads smoke) andvideo-call.spec.ts(two-context fake-media smoke).e2e-smokein.gitea/workflows/main.yml(prebuilds prod bundle, installs chromium, runs thevideo callgrep;continue-on-error: true).data-testid/data-e2eselector convention across the app (only the diagram dev-tool lib usesdata-testid). Robust selectors are a prerequisite for stable full coverage.Route surface to cover (from routing audit of
projects/spikersoft/src/routes.ts)/,/intro,/mission,/our-hardware,/legacy-systems,/develop,/contact,/syllabus,/team,/employment,/links(/:id),/blog,/sponsor(+ donate/profile),/tree-of-knowledge,/geography/*,/brain-forge,/cortex-quest,/wisdom-well,/chess,/ai,/classes,/cpu-dashboard, public coding topics, and the/toolsshell + ~25 named-outlet dev tools,/parental-approve/:token,/organization/confirm,/**(404)./home,/services,/reading-journey,/reader/:bookId,/info-vault,/fundraisers,/blog/create, most/*-gameroutes,/calendar,/video-call,/chat,/profile,/tracker, Marks (/mark/*).ReadingInterestGuard(/reading-journey),ParentGuard(/parent-dashboard),RoleGuardAdmin/Staff (/admin/*,/keycloak-admin),unsavedChangesGuard(/profile).Coverage is tracked against a committed route manifest so "100%" is measurable (every route visited + its primary actions exercised).
The hard part: signup verification (email code + Twilio SMS)
Registration is a 4-step stepper (
registration-stepper.component) ending in email + phone verification:POST /api/authentication/initiate-pre-registration→ creates a MongoPreRegistrationwithemailVerificationCode(6 digits) +emailVerificationToken.POST /api/authentication/verify-pre-registration-email(code or token) → triggers Twilio Verify SMS.POST /api/authentication/verify-pre-registration-phone→ checks the code with Twilio Verify (code is NOT stored locally).POST /api/authentication/complete-pre-registration→ creates the Keycloak user once fully verified.Email is automatable today (read
emailVerificationCode/emailVerificationTokenfrom MongoPreRegistrations, or hit the GET verify link). SMS is not — no bypass exists.Proposed test hook (needs confirmation, backend change): in non-prod only, thread the existing
SendVerificationCodeCommand.CustomCodethrough pre-registration behind an env flag (e.g.PreRegistration:E2E:Enabled+E2E_SMS_CODE), OR provide an E2E-profile fakeITwilioVerifyServicethat accepts a fixed code, OR a test-only endpoint that marksPhoneVerifiedfor a known pre-registration id. Must be impossible to enable in Production. Related existing flags:Authentication:UseTestAuthentication+TestAuthenticationHandler(API auth bypass for authenticated tests),PreRegistration:Bypass*(cooldowns/abuse only — not verification).For authenticated journeys generally, obtain a Keycloak token via direct grant against a dedicated non-prod test realm/user (or reuse
UseTestAuthenticationfor API-level setup), and use Playwright storage-state to skip the interactive login on most specs.Telemetry integration (Jaeger + Seq)
Build a reusable
e2e/telemetryclient used by specs and fixtures:http://<node-ip>:16686):GET /api/services,GET /api/traces?service=SpikerSoft%20API&start&end&tags&lookback,GET /api/traces/:id. Correlate by test time-window + service + tags (and, once the SPA emits W3Ctraceparent, by trace id).https://seq.spikersoft.com):GET /api/events?filter=<seq-query>&count=NwithX-Seq-ApiKey. Filter byServiceName,Environment, level, and the test's correlation id.JAEGER_QUERY_URL,SEQ_URL,SEQ_API_KEY). A Playwright fixture snapshots "errors in Seq / error spans in Jaeger during this test" and attaches them to the report on failure.Phased plan (each phase = its own linked sub-issue)
JaegerClient/SeqClient, failure-time telemetry fixture, CI wiring (promotee2e-smokebeyond continue-on-error for the anonymous suite). Decide target environment (dedicated staging vs prod-read-only)./tools+ every dev-tool, 404. (No backend mutations.)data-testidconvention across the components the walk touches./admin/*review surfaces +/keycloak-adminnamed-outlet UI (role-scoped test users).Definition of done
Open decisions (need a call before/at P0)
Phase sub-issues + status
Bugs found by the suite so far
/geographycrash on API failure — fixed in spikersoft-angular#90/aiblank render — triaged, harness assertion issue, resolved in spikersoft-angular#90/blogcrash on API failure — fixed in spikersoft-angular#90GET /api/interests401s anonymously — fix open in spikersoft-backend#50Environment decisions locked in
https://localhost:4200(already in Keycloak redirect URIs + API CORS allowlist;https://127.0.0.1:4200also added to Keycloak). The suite runs API-connected.Phase status refresh (2026-07-03)
e2e-anonymousCI job)New bug from the P0 reporter: #340 (/keycloak-admin missing RoleGuard).
Phase status refresh (2026-07-03, evening)
SEQ_API_KEYrepo secret still to be created)E2E_USER_USERNAME/E2E_USER_PASSWORDin.env.e2e+ repo secrets); journeys next/keycloak-adminnow properly RoleGuard-gated)Bugs from the suite closed/open today
/api/system/versionallowlist entries inEXPECTED_CONSOLE_NOISEcome out after it deploys