Skip to content

Integrate TimeKeeper at /exam-countdown with guarded migration - #73

Merged
kewonit merged 9 commits into
mainfrom
feat/timekeeper-integration
Oct 9, 2026
Merged

kewonit merged 9 commits into
mainfrom
feat/timekeeper-integration

Conversation

@kewonit

@kewonit kewonit commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

TimeKeeper now runs inside Deetnuts' existing Next.js application at /exam-countdown, preserving the confirmed production Version-3 source (8cb737981c61f06e7b0baca248f7e237c763abd4): 58 exams, 13 categories, custom countdowns, themes, session selection, fullscreen, sharing, Picture-in-Picture and the study map.

Public pages are static and cacheable with final production canonicals, structured data and a sitemap in Deetnuts' index. Fonts, styles, themes and PWA caches are scoped to the feature. The existing Supabase backend is retained through dedicated public runtime configuration and one feature CSP; Deetnuts consent and analytics are reused. Navigation includes the feature and a return link.

The old-origin helper transfers saved countdowns, theme and avatar seed through private, hashed, single-use PocketBase tickets expiring after 15 minutes. Original browser data remains intact and JSON recovery is available. The additive collection and backend hooks prevent public collection access, replay and concurrent redemption. PocketBase 0.40.5 resolves the image's blocking Go security findings.

The compatibility service is maintained here and defaults to serving the preserved old deployment. It provides direct redirects for 74 pages and seven historical aliases, query/fragment preservation, accurate 404/410 responses, a timed non-cacheable teaching canary and retained helpers/assets. Only the two import-helper paths are currently bound; existing old page URLs remain unchanged. The runbook, measured capacity runner, evidence guards and pinned compatible rollback protect the phased move.

Validation:

  • Production build, lint, typecheck, dependency audit and existing platform checks passed; required PR static/browser/CodeQL checks pass.
  • The actual production release a871ae8dd5eeb6bf5d97692fe16344a85bdc2e26 passed all 74 routes, 38 assets and existing production checks publicly, including canonical/content/CSP/indexability/sitemap/cache checks.
  • 147 production browser checks passed at 320, 390, 768, 1024 and 1440 pixels. Three existing mobile-only JEE assertions skip at wider widths. Study-map writes and transfer fixtures are isolated from live user data.
  • 22 migration unit tests, four real PocketBase integration tests and 13 JEE unit tests passed. The retained study backend passed a read-only RPC/CORS check.
  • The actual old-origin helper, real private ticket and destination import passed in a disposable browser, with old storage retained.
  • A fresh production backup passed integrity checks and a network-isolated restoration drill with the patched PocketBase image. An actual blue/green rollback passed the normal ten-minute health check plus every new route/asset; the immutable compatible release is pinned.
  • The isolated capacity run sustained 74 RPS for two 300-second phases, including direct-origin cache misses: 44,400 requests, zero failures and zero dropped requests. The offered rate exceeds twice the conservative combined seven-day minute-level peak. Exact production images ran under matching CPU/RAM ceilings on an internal Docker network with disposable credentials/data and no live backend access. Runner CPU hardware differs from DigitalOcean; full production latency observation remains required.

The native integration is live on the existing Droplet using the normal Deetnuts blue/green workflow. No new Droplet or live-host capacity load was created. Full source history, hosting records, pinned source fallback and encrypted offline recovery are preserved. A scoped Cloudflare cache exception keeps service-worker updates fresh.

The clean 24-hour observation began 2026-10-09T18:30:53Z after recovery verification. The 30-minute teaching trial, actual HTTP/HTTPS one-hop verification, permanent redirects and Search Console move remain gated. Retire/disconnect/archive Timekeeper only after at least 30 measured stable days; retain old DNS/TLS/redirects/imports indefinitely. Repository merge does not open these traffic gates. The user approved an hourly follow-up to finish these measured rollout stages, changing to daily monitoring after permanent cutover.

See the migration runbook and captured preflight records.

Comment thread lib/timekeeper/study-client.ts Fixed
Comment thread lib/timekeeper/study-client.ts Fixed
Comment thread scripts/verify-timekeeper.mjs Fixed
Comment thread scripts/verify-timekeeper.mjs Fixed
Comment thread scripts/verify-timekeeper.mjs Fixed
@kewonit
kewonit marked this pull request as ready for review October 9, 2026 18:49
@kewonit
kewonit merged commit 4e97d0a into main Oct 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants