Date: 2026-04-24
Scope: repository-wide audit of /Users/btc2020/Bitbi/Bitbi.
Constraint honored: no application code was changed. This report is based on local repository inspection and safe validation commands only.
This section is the current implementation checkpoint. The Admin Control Plane received a 2026-04-27 corrective polish/data-accuracy pass that fixed new card/grid/nav/mobile rendering defects, tightened status wording and sanitization, and added layout/data-accuracy regression tests. The Pricing / Credit Purchase rollout adds a controlled admin-only pricing surface for the existing Stripe Testmode checkout foundation. The original audit findings, risk ratings, score estimates, and command output below remain a historical pre-remediation baseline from 2026-04-24. They are intentionally preserved and must not be read as the current state after Phase 0-A through Phase 2-J.
Current repository state at checkpoint:
- Branch:
main - Latest committed phase observed before Admin Control Plane edits:
c3b36d9 Phase 2-J - Working tree: Pricing / Credit Purchase rollout adds
/pricing.html, pricing JS/CSS, admin-only header links, Testmode pack catalog updates, model status copy updates, tests, and documentation until committed. - Latest auth D1 migration:
0039_raise_credit_balance_cap_for_pricing_packs.sql - Latest AI Worker Durable Object migration:
v1-service-auth-replay - Current aggregate validation before Pricing edits:
npm run release:preflightpassed on the committed Admin Control Plane baseline. Pricing rollout validation is recorded inPHASE_PRICING_PAGE_CREDIT_PACKS_REPORT.mdafter the phase command suite. Live Cloudflare validation and production deploy were not run. - Production deploy status: blocked until live Cloudflare secret/binding/resource validation, auth migrations through
0038, Stripe Testmode secret/URL/webhook endpoint verification, staging Worker verification, staging data lifecycle cleanup/executor verification, staging organization-flow verification, staging billing/entitlement/credit verification, staging org-scoped AI image/text usage retry/reservation verification, staging AI usage attempt cleanup/admin inspection verification, staging replay object cleanup verification, staging synthetic billing webhook verification/admin inspection/no-side-effect verification, staging Stripe Testmode checkout/webhook/exactly-once credit grant verification, Admin Control Plane staging UI verification, and admin-only Pricing checkout/return/model-status staging verification are complete.
Completed remediation phases:
| Phase | Status | Main deliverables | Validation summary | Remaining deploy/staging blockers | Report |
|---|---|---|---|---|---|
| Phase 0-A | Completed | Static smoke fixes, priority fail-closed throttles, Auth-to-AI HMAC, critical config validation, AI worker lockfile. | Static 155/155, Worker 260/260, release preflight passed in report. | Matching AI_SERVICE_AUTH_SECRET and live Worker resource verification. |
PHASE0_REMEDIATION_REPORT.md |
| Phase 0-A+ | Completed | Nonce-backed HMAC replay protection with SERVICE_AUTH_REPLAY, expanded fail-closed route coverage, CSRF/security regressions. |
HMAC/replay/MFA/limiter/config tests passed in Phase 0 report. | SERVICE_AUTH_REPLAY binding/migration and secret parity must be live-verified. |
PHASE0_REMEDIATION_REPORT.md |
| Phase 0-B | Completed | Cloudflare prereq validator, byte-limited parsers, more fail-closed write limits, durable admin MFA failed-attempt state, async video design. | Worker 272/272, static 155/155, release preflight passed. | Migrations from 0028 onward and live Cloudflare prereqs must be verified before deploy. |
PHASE0B_REMEDIATION_REPORT.md |
| Phase 1-A | Completed | Async video D1 table, queue binding, admin video job create/status APIs, idempotency foundation, body-parser guard. | Worker 280/280, static 155/155, release preflight passed. | AI_VIDEO_JOBS_QUEUE and migration 0029 must be staged/live-verified. |
PHASE1A_REMEDIATION_REPORT.md |
| Phase 1-B | Completed | Queue-safe video task create/poll, R2 output/poster ingest, poison-message persistence, async admin UI default path. | Worker 285/285, static 155/155, release preflight passed. | Staging provider/R2 validation; keep sync debug route disabled. | PHASE1B_REMEDIATION_REPORT.md |
| Phase 1-C | Completed | Sync video debug gate, admin poison/failed-job inspection APIs, low-risk quality gates, toolchain pinning. | Worker 289/289, static 155/155, release preflight passed. | Alerts/IaC and broader type/lint migration remain later work. | PHASE1C_REMEDIATION_REPORT.md |
| Phase 1-D | Completed | Purpose-specific auth secrets, dual-read/single-write compatibility, config/prereq validation. | Worker 300/300, static 155/155, release preflight passed. | Provision new secrets and keep legacy SESSION_SECRET until fallback is intentionally disabled. |
PHASE1D_SECRET_ROTATION_REPORT.md |
| Phase 1-E | Completed | High-risk auth Worker route policy registry and route-policy static guard. | Route-policy guard passed; Worker/static/release checks passed in report. | Registry is metadata/checking, not full central enforcement. | PHASE1E_ROUTE_POLICY_REPORT.md |
| Phase 1-F | Completed | Health probes, operational readiness checks, SLO/event docs, backup/restore drill plan, runbooks, live-check scripts. | Worker 303/303, static 155/155, release preflight passed. | Live alerts, restore drills, dashboard drift checks remain manual/unproven. | PHASE1F_OPERATIONAL_READINESS_REPORT.md |
| Phase 1-G | Completed | Indexed/redacted activity search projection, signed activity cursors, query-shape guard. | Worker 306/306, static 155/155, release preflight passed. | Migration 0031, staging projection verification, optional historical backfill. |
PHASE1G_AUDIT_SEARCH_SCALABILITY_REPORT.md |
| Phase 1-H | Completed | Data inventory, retention baseline, lifecycle request schema, admin planning APIs, dry-run export/delete plans. | Worker 309/309, static 155/155, release preflight passed. | Migration 0032, legal/product policy, no irreversible deletion. |
PHASE1H_DATA_LIFECYCLE_REPORT.md |
| Phase 1-I | Completed | Bounded sanitized export archive generation, private AUDIT_ARCHIVE storage, archive authorization, deletion executor design. |
Worker 311/311, static 155/155, release preflight passed. | Migration 0033, archive generation/download staging verification. |
PHASE1I_EXPORT_DELETE_EXECUTOR_REPORT.md |
| Phase 1-J | Completed | Bounded expired archive cleanup, scheduled cleanup integration, admin cleanup visibility, safe reversible-action executor pilot. | Worker 313/313, static 155/155, release preflight passed. | Live AUDIT_ARCHIVE cleanup verification and safe executor staging verification. |
PHASE1J_RETENTION_EXECUTOR_REPORT.md |
| Phase 2-A | Completed for current scope | Additive organizations/memberships schema, basic roles, org/RBAC helper, minimal user org APIs, admin org inspection, backfill plan, route-policy/release updates. | Worker 317/317, static 155/155, release preflight passed. | Migration 0034, staging org-flow verification, and later domain-by-domain tenant migration. |
PHASE2A_ORG_RBAC_REPORT.md |
| Phase 2-B | Completed for current scope | Additive plans/subscriptions/entitlements/credit-ledger/usage schema, billing helper, org billing/entitlement reads, admin plan/org billing inspection, admin credit grants, route-policy/release updates. | Worker 320/320, static 155/155, release preflight passed after ledger ordering fix. | Migration 0035, staging billing/entitlement/credit verification, later AI route wiring, and future payment-provider integration. |
PHASE2B_BILLING_ENTITLEMENTS_REPORT.md |
| Phase 2-C | Completed for current scope | Opt-in org-scoped /api/ai/generate-image entitlement and credit enforcement, AI usage policy helper, usage idempotency request fingerprinting, legacy no-org compatibility, route-policy/check-js/doc updates. |
Worker 326/326, static 155/155, release preflight passed. | Staging org-scoped image charge/idempotency/insufficient-credit verification, and future provider-result idempotency/text-video wiring. | PHASE2C_AI_USAGE_ENTITLEMENTS_REPORT.md |
| Phase 2-D | Completed for current scope | Org-scoped image usage attempts/reservations, duplicate provider-call suppression, temporary result replay, provider-failure reservation release, billing-failure terminal state, migration 0036, release/doc/test updates. |
Worker 331/331, static 155/155, release preflight passed. | Migration 0036 and staging retry/replay/no-duplicate-provider/no-duplicate-charge verification; expired-attempt cleanup is handled by Phase 2-E. |
PHASE2D_AI_USAGE_RESERVATION_REPORT.md |
| Phase 2-E | Completed for current scope | Bounded AI usage attempt cleanup, stale reservation release without debits, replay metadata expiry, scheduled cleanup integration, admin usage-attempt list/detail/cleanup APIs, route-policy/release/doc/test updates. | Worker 334/334, static 155/155, release preflight passed. | Migration 0036, staging cleanup/admin inspection/dry-run/execution/scheduled cleanup verification, and later temporary replay object deletion policy. |
PHASE2E_AI_USAGE_ATTEMPT_CLEANUP_REPORT.md |
| Phase 2-F | Completed for current scope | Prefix-scoped deletion of expired temporary replay objects, generic temp cleanup skip for attempt-linked objects, sanitized cleanup counts/logs, route-policy note updates, docs/tests. | Worker 336/336, static 155/155, release preflight passed. | Migration 0036, staging replay cleanup dry-run/execution, scheduled cleanup, R2 delete failure handling, no unrelated object deletion, no debit/ledger/usage mutation. |
PHASE2F_AI_REPLAY_OBJECT_RETENTION_REPORT.md |
| Phase 2-H | Completed for current scope | Backend-only org-scoped POST /api/ai/generate-text, HMAC Auth-to-AI text proxying, ai.text.generate entitlement/credit enforcement, attempt reservation/finalization, bounded text replay metadata, route-policy/release/doc/test updates. |
Worker 339/339, static 155/155, release preflight passed, git diff --check passed. |
Migration 0036, staging org-scoped text success/replay/denial/provider-failure/billing-failure verification, and live Auth-to-AI secret/binding verification. |
PHASE2H_MEMBER_TEXT_GENERATION_API_REPORT.md |
| Phase 2-I | Completed for current scope | Provider-neutral billing event ingestion, migration 0037, synthetic raw-body HMAC verification, idempotent event storage, duplicate/mismatch handling, dry-run action planning, sanitized admin billing-event inspection, route-policy/release/doc/test updates. |
Worker 342/342 passed during implementation; final full validation is in PHASE2I_BILLING_EVENT_INGESTION_REPORT.md and the Phase 2-I response. |
Migration 0037, staging synthetic webhook signature failure/success/dedup/mismatch/admin-inspection/no-side-effect verification; no live provider enabled. |
PHASE2I_BILLING_EVENT_INGESTION_REPORT.md |
| Phase 2-J | Completed for current scope | Stripe Testmode credit-pack checkout foundation, migration 0038, fixed server-side test pack catalog, org owner/admin checkout creation, Stripe raw-body signature verification, verified Testmode checkout credit grant, duplicate/mismatch handling, route-policy/release/doc/test updates. |
Worker 346/346, static 155/155, release preflight passed. | Migration 0038, Stripe Testmode config and webhook endpoint, staging checkout creation, valid checkout completion, duplicate/mismatch handling, exactly-once credit grant, failed/unpaid no-credit behavior, and no live billing side effects. |
PHASE2J_STRIPE_TESTMODE_CREDIT_PACK_CHECKOUT_REPORT.md |
| Admin Control Plane | Completed for current scope | Frontend-only admin command center and sections for security posture, organizations/RBAC, billing/credits, billing events/Stripe Testmode, AI usage attempts/cleanup, data lifecycle, operations, readiness, and settings using existing sanitized APIs. Corrective pass fixed cramped cards, vertical text wrapping, badge overlap, mobile table visibility, ambiguous readiness labels, and action duplicate-submit risks. | Validation is recorded in PHASE_ADMIN_CONTROL_PLANE_REPORT.md. No backend API, migration, dependency, or live billing activation was added. |
Staging admin UI verification with real backend APIs; production remains blocked by existing Phase 0 through Phase 2-J staging/live prerequisites. | PHASE_ADMIN_CONTROL_PLANE_REPORT.md |
| Pricing / Credit Purchase | Completed for current scope pending validation | Admin-only /pricing.html, admin-only desktop/mobile Pricing header link, Free/5000/10000 pricing cards, existing org owner/admin Stripe Testmode checkout route integration, success/cancel states, product-facing credits_5000 and credits_10000 catalog, truthful Models overlay statuses. |
Validation is recorded in PHASE_PRICING_PAGE_CREDIT_PACKS_REPORT.md. No migration, dependency, live Stripe activation, subscription, invoice, customer portal, or public rollout was added. |
Staging pricing link/access-gate verification, Stripe Testmode checkout URL configuration, checkout creation, webhook exact-once credit grant, success/cancel return states, model status truthfulness, and no live billing side effects. | PHASE_PRICING_PAGE_CREDIT_PACKS_REPORT.md |
Current status estimate:
- The repository has completed the Phase 0/1 hardening roadmap through Phase 1-J, Phase 2-A organization/RBAC foundation, Phase 2-B billing/entitlement foundation, targeted Phase 2-C org-scoped AI image usage enforcement, Phase 2-D org-scoped image usage retry/reservation hardening, Phase 2-E usage-attempt cleanup/admin inspection, Phase 2-F temporary replay object cleanup, Phase 2-H backend-only org-scoped member text generation, Phase 2-I provider-neutral billing event ingestion, Phase 2-J Stripe Testmode credit-pack checkout foundation, the Admin Control Plane UI phase, and the admin-only Pricing / Credit Purchase Testmode rollout for the documented scope.
- It is substantially safer and more operable than the original audit baseline, but it is not full enterprise SaaS maturity.
- Existing assets remain user-owned; full tenant isolation, live payment activation, subscriptions, invoices, customer portal, production-trusted live webhooks, broad AI route credit enforcement, permanent provider-result cache, full IaC/dashboard drift enforcement, full type/lint migration, full user self-service privacy flows, irreversible deletion execution, formal load budgets, and live SLO/alert evidence remain open.
- The next implementation phase should be chosen between live-provider hardening/subscription design, video AI entitlement wiring, and domain-by-domain tenant ownership migration. Do not redo Phase 0/1/2-A/2-B/2-C/2-D/2-E/2-F/2-G/2-H/2-I/2-J or Admin Control Plane foundations.
This section records remediation progress after the original 2026-04-24 audit. The findings, risk ratings, command output, and maturity assessment below remain historically accurate for the repository state at audit time; they should not be read as the current status of every Phase 0 item.
Reference documents:
PHASE0_REMEDIATION_REPORT.mdcontains the detailed Phase 0-A/0-A+ implementation evidence, validation results, merge readiness, deploy blockers, and remaining risks.PHASE0B_REMEDIATION_REPORT.mdcontains the Phase 0-B implementation evidence for deploy preflight, body-size limits, route throttling expansion, admin MFA failed-attempt state, CSRF coverage, and async video design.PHASE1A_REMEDIATION_REPORT.mdcontains the Phase 1-A async admin video job foundation evidence, validation results, deploy requirements, and remaining risks.PHASE1B_REMEDIATION_REPORT.mdcontains the Phase 1-B async admin video production-usability hardening evidence, validation results, deploy requirements, and remaining risks.PHASE1C_REMEDIATION_REPORT.mdcontains the Phase 1-C sync-route restriction, admin poison/failed-job inspection, quality-gate, validation, and deploy-readiness evidence.PHASE1D_SECRET_ROTATION_REPORT.mdcontains the Phase 1-D purpose-specific security secret inventory, dual-read/single-write compatibility behavior, validation evidence, rollout plan, and rollback guidance.PHASE1E_ROUTE_POLICY_REPORT.mdcontains the Phase 1-E auth-worker route policy registry, coverage guard, CI/preflight integration, validation evidence, and remaining route-policy migration risks.PHASE1F_OPERATIONAL_READINESS_REPORT.mdcontains the Phase 1-F health/readiness, live-check, SLO, runbook, backup/restore drill, queue/backlog, validation, and remaining operational-readiness evidence.PHASE1G_AUDIT_SEARCH_SCALABILITY_REPORT.mdcontains the Phase 1-G indexed audit/activity search projection, signed activity cursor behavior, query-shape guard, validation evidence, migration requirements, and remaining historical-backfill risks.PHASE1H_DATA_LIFECYCLE_REPORT.mdcontains the Phase 1-H data lifecycle request schema, admin lifecycle APIs, export/deletion/anonymization planning behavior, validation evidence, deploy requirements, and remaining privacy-operation risks.PHASE1I_EXPORT_DELETE_EXECUTOR_REPORT.mdcontains the Phase 1-I bounded export archive generation, private R2 archive storage, archive authorization, deletion executor design, validation evidence, deploy requirements, and remaining privacy-operation risks.PHASE1J_RETENTION_EXECUTOR_REPORT.mdcontains the Phase 1-J expired export archive cleanup, safe deletion/anonymization executor pilot, admin retention visibility, validation evidence, deploy requirements, and remaining privacy-operation risks.PHASE2A_ORG_RBAC_REPORT.mdcontains the Phase 2-A organization/membership schema, RBAC helper, minimal user/admin org APIs, route-policy/release updates, backfill plan, validation evidence, and remaining tenant-isolation risks.PHASE2B_BILLING_ENTITLEMENTS_REPORT.mdcontains the Phase 2-B plan/entitlement/credit-ledger schema, billing helper, org/admin billing APIs, route-policy/release updates, validation evidence, deploy requirements, and remaining monetization risks.PHASE2C_AI_USAGE_ENTITLEMENTS_REPORT.mdcontains the Phase 2-C org-scoped AI image usage policy, entitlement/credit enforcement behavior, idempotency rules, validation evidence, deploy requirements, and remaining monetization risks.PHASE2D_AI_USAGE_RESERVATION_REPORT.mdcontains the Phase 2-D AI usage attempt/reservation schema, provider-result idempotency behavior, credit reservation/finalization behavior, validation evidence, deploy requirements, and remaining monetization risks.PHASE2E_AI_USAGE_ATTEMPT_CLEANUP_REPORT.mdcontains the Phase 2-E AI usage attempt cleanup/admin inspection behavior, scheduled cleanup behavior, validation evidence, deploy requirements, and remaining monetization/retention risks.PHASE2F_AI_REPLAY_OBJECT_RETENTION_REPORT.mdcontains the Phase 2-F temporary replay object cleanup behavior, prefix/attempt-linkage safety rules, scheduled/admin cleanup behavior, validation evidence, deploy requirements, and remaining monetization/retention risks.PHASE2H_MEMBER_TEXT_GENERATION_API_REPORT.mdcontains the Phase 2-H backend-only org-scoped member text generation API behavior, entitlement/credit enforcement, text replay behavior, validation evidence, deploy requirements, and remaining monetization/tenant risks.PHASE2I_BILLING_EVENT_INGESTION_REPORT.mdcontains the Phase 2-I provider-neutral billing event ingestion schema, raw-body verification boundary, idempotency behavior, sanitized admin inspection, validation evidence, deploy requirements, and remaining payment-provider risks.PHASE2J_STRIPE_TESTMODE_CREDIT_PACK_CHECKOUT_REPORT.mdcontains the Phase 2-J Stripe Testmode credit-pack checkout schema, checkout creation behavior, Stripe raw-body webhook verification, exactly-once credit grant behavior, validation evidence, deploy requirements, and remaining payment-provider risks.PHASE_ADMIN_CONTROL_PLANE_REPORT.mdcontains the Admin Control Plane frontend implementation evidence, API inventory, UI action safety model, validation evidence, deploy requirements, and remaining UI/staging risks.PHASE_PRICING_PAGE_CREDIT_PACKS_REPORT.mdcontains the admin-only Pricing page, Free/5000/10000 credit-pack presentation, checkout integration, success/cancel state, model status, validation evidence, deploy requirements, and remaining Testmode/live-billing risks.DATA_INVENTORY.mdanddocs/DATA_RETENTION_POLICY.mdcontain the Phase 1-H/1-I/1-J data inventory and engineering retention-policy baseline.docs/DATA_DELETION_EXECUTOR_DESIGN.mdcontains the Phase 1-I/1-J deletion/anonymization executor state model, approval gates, safe reversible-action pilot, disabled irreversible-action policy, rollback limitations, and future test plan.PHASE1_OBSERVABILITY_BASELINE.mdcontains the initial async video job observability baseline.AUDIT_ACTION_PLAN.mdtracks the top 20 findings in original priority order with current status, evidence, remaining risk, and next action.
Phase 0-A completed summary:
- Fixed the three failing static smoke tests from the original audit; final
npm run test:staticis recorded as passing 155/155. - Added fail-closed app-layer throttling for priority admin/MFA/auth/AI/avatar routes.
- Added HMAC service authentication for Auth-to-AI Worker requests using
AI_SERVICE_AUTH_SECRET. - Added fail-closed Worker config validation for Phase 0 critical auth and AI service-auth configuration.
- Added
workers/ai/package-lock.jsonand CI/package checks for root and Worker packages. - Expanded Worker security tests and release/preflight checks.
Phase 0-A+ completed summary:
- Added nonce-backed replay protection for internal AI service auth using
x-bitbi-service-nonceand theSERVICE_AUTH_REPLAYDurable Object. - Required every
/internal/ai/*route to verify signed service-auth requests before dispatch. - Converted additional priority routes to fail-closed limiter behavior, including auth/session mutations, wallet SIWE, favorites add, admin mutations, admin AI, MFA operations, member AI generation, and avatar write paths.
- Added regression coverage for service-auth replay rejection, missing/malformed/expired/invalid signatures, body tampering, unavailable nonce backend, fail-closed limiter behavior, admin MFA throttling, and selected CSRF-sensitive mutations.
- Updated release compatibility/config evidence for
AI_SERVICE_AUTH_SECRETprerequisites and theSERVICE_AUTH_REPLAYDurable Object binding/migration.
Phase 0-B completed summary:
- Added
scripts/validate-cloudflare-deploy-prereqs.mjsplus tests for repo-side Cloudflare secret/binding/migration prerequisites and explicit live-validation skipped/blocked status. - Added limited request body readers in
js/shared/request-body.mjsand routed auth, admin, MFA, profile, favorites, avatar, wallet, AI, contact, and internal AI JSON/multipart parsing through byte-limited helpers. - Converted additional authenticated/write routes to fail-closed Durable Object backed limits, including profile update, favorites delete, avatar delete, wallet unlink, AI folder/bulk/publication/text/audio/image writes, and contact submit.
- Added D1 migration
0028_add_admin_mfa_failed_attempts.sqland durable admin MFA failed-attempt lockout/reset-on-success behavior. - Expanded CSRF regression coverage for profile update, favorites delete, wallet unlink, and AI folder create.
- Created
AI_VIDEO_ASYNC_JOB_DESIGN.mdwith a concrete D1/Queue/R2 migration plan for async video jobs.
Phase 1-A completed summary:
- Added auth D1 migration
0029_add_ai_video_jobs.sqlfor durable admin async video job state. - Added auth Worker queue binding/consumer contract
AI_VIDEO_JOBS_QUEUE/bitbi-ai-video-jobs. - Added
/api/admin/ai/video-jobscreate and/api/admin/ai/video-jobs/:idowner-scoped status APIs. - Added idempotency-key handling, fail-closed queue/config behavior, queue lease/retry/exhaustion handling, and focused Worker tests.
- Added
scripts/check-worker-body-parsers.mjsplus package/CI/release-preflight integration as a low-risk guardrail against new unsafe direct body parsing. - Added
PHASE1_OBSERVABILITY_BASELINE.mdfor async video lifecycle logs, safe fields, alert candidates, and SLO candidates.
Phase 1-B completed summary:
- Added bounded internal AI task routes
/internal/ai/video-task/createand/internal/ai/video-task/poll. - Updated the auth queue consumer so async video jobs no longer call
/internal/ai/test-video. - Added D1 migration
0030_harden_ai_video_jobs_phase1b.sqlfor polling/ingest statuses, output/poster metadata, andai_video_job_poison_messages. - Added R2 ingest into the existing
USER_IMAGESbucket with content-type and byte limits for video output and optional posters. - Made the admin AI Lab use async video job create/status polling by default and kept the synchronous route only as an explicit debug compatibility path.
- Required
Idempotency-Keyfor async video job creation. - Added Worker/static tests for duplicate queue messages, no duplicate provider task creation, R2 ingest, protected output routes, poison-message recording, and default UI avoidance of
/api/admin/ai/test-video.
Phase 1-C completed summary:
- Made
/api/admin/ai/test-videodefault-disabled unlessALLOW_SYNC_VIDEO_DEBUG=true, while preserving admin auth, MFA boundary, same-origin checks, fail-closed rate limiting, body limits, and safe warning logs when explicitly used. - Added admin-only operational APIs for sanitized video poison messages and failed video job diagnostics:
/api/admin/ai/video-jobs/poison,/poison/:id,/failed, and/failed/:id. - Added low-risk quality gates:
.nvmrc,package.jsonengines, toolchain check, secret scan, DOM sink baseline, targeted JS syntax check, quality-gate tests, and preflight/CI integration. - Updated release compatibility contracts to mark the sync route as debug-only and include the new operational routes.
- Final Phase 1-C validation passed:
npm run test:workers289/289,npm run test:static155/155,npm run release:preflight, andgit diff --check.
Phase 1-D completed summary:
- Added
workers/auth/src/lib/security-secrets.jsto centralize purpose-specific auth secret lookup and explicit legacySESSION_SECRETfallback. - New session hashes use
SESSION_HASH_SECRET; legacySESSION_SECREThashes are accepted during fallback and opportunistically upgraded after successful validation. - New admin MFA TOTP encryption, proof cookies, and recovery-code hashes use
ADMIN_MFA_ENCRYPTION_KEY,ADMIN_MFA_PROOF_SECRET, andADMIN_MFA_RECOVERY_HASH_SECRET; legacy decrypt/proof/hash fallback remains explicit and tested. - New pagination cursors use
PAGINATION_SIGNING_SECRET, and generated-image save references useAI_SAVE_REFERENCE_SIGNING_SECRET. - Auth config validation, release compatibility, and Cloudflare prerequisite checks now require the new purpose-specific auth secret names.
PHASE1D_SECRET_ROTATION_REPORT.mddocuments the inventory, rollout plan, rollback plan, remaining risks, and validation evidence.
Phase 1-E completed summary:
- Added
workers/auth/src/app/route-policy.jswith explicit route metadata for high-risk auth-worker routes across auth/session, wallet SIWE, profile/avatar, favorites, admin users, admin MFA, admin AI, async video jobs, member AI writes, and protected media reads. - Added
scripts/check-route-policies.mjsto prevent new mutating branches in selected auth-worker dispatcher files from existing without a registered policy marker. - Added
ctx.routePolicylookup inworkers/auth/src/index.jsfor future low-risk instrumentation/enforcement without changing route behavior. - Integrated
npm run check:route-policiesinto package scripts, release planning, release compatibility workflow checks, CI, targeted JS syntax checks, and Worker tests. PHASE1E_ROUTE_POLICY_REPORT.mddocuments route inventory coverage, deferred routes, registry design, checks, validation, and remaining central-enforcement risks.
Phase 1-F completed summary:
- Added public-safe liveness probes for the AI and contact Workers:
GET /healthinworkers/ai/src/index.jsandworkers/contact/src/index.js. - Added skipped-by-default live checks:
scripts/check-live-health.mjsandscripts/check-live-security-headers.mjs, with--require-livefor staging/production evidence. - Added repo-owned operational readiness checks through
scripts/check-operational-readiness.mjsandscripts/test-operational-readiness.mjs. - Added
docs/OBSERVABILITY_EVENTS.md,docs/SLO_ALERT_BASELINE.md,docs/BACKUP_RESTORE_DRILL.md, and service/failure-mode runbooks underdocs/runbooks/. - Integrated the operational readiness checks into package scripts, release planning, release compatibility workflow checks, CI, and targeted JS syntax checks.
PHASE1F_OPERATIONAL_READINESS_REPORT.mddocuments the inventory, health/readiness behavior, scripts, runbooks, SLO/alert baseline, validation evidence, and remaining live-verification gaps.
Phase 1-G completed summary:
- Added D1 migration
0031_add_activity_search_index.sqlfor a normalizedactivity_search_indexprojection table with indexes for source/time, action, actor email, target email, and entity lookup. - Added
workers/auth/src/lib/activity-search.jsto normalize searchable fields and sanitize returned activity metadata. - Updated activity write paths and queue ingestion so new admin audit/user activity events populate the projection table.
- Updated
/api/admin/activityand/api/admin/user-activityto use signed cursors backed byPAGINATION_SIGNING_SECRET, route/filter-bound cursor payloads, and projection-backed prefix search instead of rawmeta_jsonsearch. - Bounded admin action counts to the hot retention window.
- Added
scripts/check-admin-activity-query-shape.mjsplus CI/preflight integration to block raw metadata search, raw activity cursors, and unbounded admin action count regressions. PHASE1G_AUDIT_SEARCH_SCALABILITY_REPORT.mddocuments the baseline inventory, migration, search behavior change, backfill strategy, validation, deploy requirements, and remaining risks.
Phase 1-H completed summary:
- Added
DATA_INVENTORY.mdanddocs/DATA_RETENTION_POLICY.mdto document D1/R2/contact data classes, exportability, deletion/anonymization behavior, and open legal/product decisions. - Added D1 migration
0032_add_data_lifecycle_requests.sqlfordata_lifecycle_requests,data_lifecycle_request_items, anddata_export_archives. - Added
workers/auth/src/lib/data-lifecycle.jsandworkers/auth/src/routes/admin-data-lifecycle.jsfor admin-only lifecycle request create/list/detail/plan/approve APIs. - Added export planning that records sanitized D1 summaries and R2 references while excluding password hashes, session/token hashes, MFA secrets/recovery codes, service signatures, and provider credentials.
- Added deletion/anonymization planning that is dry-run by default, records revoke/delete/anonymize/retain actions, and blocks only-active-admin deletion/anonymization.
- Added route policies, release compatibility updates, lifecycle static guardrails, CI/preflight wiring, Worker tests, and auth Worker operational documentation for the new lifecycle routes.
Phase 1-I completed summary:
- Added D1 migration
0033_harden_data_export_archives.sqlfor export archive manifest/status/download/error metadata and expiration indexes. - Added
workers/auth/src/lib/data-export-archive.jsfor bounded sanitized JSON archive generation from approved export plans. - Stores export archives in the existing private
AUDIT_ARCHIVEbucket under deterministicdata-exports/{subjectUserId}/{requestId}/{archiveId}.jsonkeys without raw email/user text in object paths. - Added admin-only archive generation, metadata, and authorized download routes while keeping user-facing self-service deferred.
- Enforces archive item-count and byte-size bounds, SHA-256 metadata, no binary media inlining, no internal R2 key exposure in metadata, and 14-day archive access expiration.
- Added
docs/DATA_DELETION_EXECUTOR_DESIGN.mdto document the safe deletion/anonymization executor model while leaving irreversible hard deletion disabled by default. - Added route policies, release compatibility updates, lifecycle static guardrails, Worker tests, and documentation updates for Phase 1-I.
Phase 1-J completed summary:
- Added
workers/auth/src/lib/data-export-cleanup.jsfor bounded expired export archive cleanup scoped to privateAUDIT_ARCHIVEobjects underdata-exports/. - Integrated export archive cleanup into the existing auth Worker scheduled cleanup path without adding a new cron trigger.
- Added admin-only archive retention visibility and cleanup routes:
GET /api/admin/data-lifecycle/exportsandPOST /api/admin/data-lifecycle/exports/cleanup-expired. - Added
POST /api/admin/data-lifecycle/requests/:id/execute-safeas a safe executor pilot for approved delete/anonymize requests. It supports dry-run by default and can only revoke sessions, expire reset/verification/SIWE tokens, and expire export archive metadata. - Kept irreversible hard deletion, R2 media deletion, audit-log deletion, primary identity anonymization, and user self-service delete disabled by default.
- Added route policies, release compatibility updates, lifecycle static guards, Worker tests, and documentation updates for Phase 1-J.
Phase 2-A completed summary:
- Added D1 migration
0034_add_organizations.sqlfor organizations and memberships. - Added
workers/auth/src/lib/orgs.js,workers/auth/src/routes/orgs.js, andworkers/auth/src/routes/admin-orgs.jsfor basic organization roles, membership checks, user org APIs, and admin org inspection. - Added idempotent organization creation, member add/list, role enforcement, cross-org denial, fail-closed limiter behavior, route-policy coverage, release compatibility updates, and Worker tests.
- Preserved existing user-owned assets and documented that Phase 2-A is an additive foundation rather than full tenant isolation.
Phase 2-B completed summary:
- Added D1 migration
0035_add_billing_entitlements.sqlfor plans, organization subscriptions, entitlements, future billing-customer mappings, credit ledger entries, and usage events. - Added
workers/auth/src/lib/billing.jsfor default free plan resolution, entitlement checks, credit balance checks, idempotent credit grants, and idempotent credit consumption without negative balances. - Added organization billing/entitlement/usage read APIs and admin plan/org billing/credit grant APIs with route-policy coverage, fail-closed admin limiters, same-origin mutation protection, byte-limited JSON parsing, and idempotency.
- Updated release compatibility, route-policy checks, Worker harness/tests, data inventory, retention policy, and auth Worker operational documentation.
- No live payment provider, checkout, invoice, webhook, pricing, or production billing activation is enabled.
Phase 2-C completed summary:
- Added
workers/auth/src/lib/ai-usage-policy.jsfor centralized AI operation-to-entitlement/credit mapping and org-scoped usage policy checks. - Updated
workers/auth/src/lib/billing.jsso usage consumption can include a request fingerprint and idempotency conflicts can be rejected before provider execution. - Wired
/api/ai/generate-imageto enforce active org membership,owner/admin/memberrole,ai.image.generateentitlement, available credits, andIdempotency-Keyonly whenorganization_id/organizationIdis supplied. - Preserved legacy user-scoped image generation when no organization context is supplied; no global paywall is enabled.
- No live payment provider, checkout, invoice, webhook, production billing activation, text/video route charging, or full tenant isolation is enabled.
Phase 2-D completed summary:
- Added D1 migration
0036_add_ai_usage_attempts.sqlfor durable org-scoped AI image usage attempts, credit reservations, provider/billing/result status, safe temporary result replay metadata, and expiration. - Added
workers/auth/src/lib/ai-usage-attempts.jsand updatedworkers/auth/src/lib/ai-usage-policy.jsto reserve credits before provider execution and classify same-key retries. - Updated
/api/ai/generate-imageorg-scoped mode to suppress duplicate provider calls for pending/succeeded idempotency keys, replay stored temporary results when available, release reservations on provider failure, and fail safely on billing finalization failure without persisting uncharged paid results. - Preserved legacy no-org image generation, admin AI routes, text routes, video routes, live payment-provider flows, and full tenant migration as out of scope.
Phase 2-E completed summary:
- Added bounded
ai_usage_attemptscleanup inworkers/auth/src/lib/ai-usage-attempts.jsfor expired/stuck reservations and expired replay metadata. - Integrated cleanup into the existing auth Worker scheduled cleanup path without adding a new cron trigger.
- Added admin-only sanitized APIs for usage-attempt list/detail and cleanup:
GET /api/admin/ai/usage-attempts,GET /api/admin/ai/usage-attempts/:id, andPOST /api/admin/ai/usage-attempts/cleanup-expired. - Cleanup releases stale reservations without debits, marks expired finalizing attempts terminal, expires replay metadata, and does not delete attempts, ledger rows, usage events, or temporary replay objects.
- No new migration was required; Phase 2-E uses the existing
0036_add_ai_usage_attempts.sqlschema and indexes. - Preserved legacy no-org image generation, admin AI routes, text routes, video routes, payment-provider flows, and full tenant migration as out of scope.
Phase 2-F completed summary:
- Added strict temporary replay object key validation for
tmp/ai-generated/{userId}/{tempId}and explicit skips for unsafe or unrelated keys. - Updated
workers/auth/src/lib/ai-usage-attempts.jsso expired, finalized, attempt-linked replay objects are deleted fromUSER_IMAGESonly after prefix/user/attempt linkage checks pass. - Updated the generic scheduled generated-temp cleanup in
workers/auth/src/index.jsto skip objects that are still linked fromai_usage_attempts; linked objects are handled by the usage-attempt cleanup path instead. - Extended sanitized admin/scheduled cleanup counts without returning raw R2 keys, save references, hashes, prompts, provider payloads, or internal SQL/debug details.
- No new migration or route was required; Phase 2-F uses the existing
0036_add_ai_usage_attempts.sqlschema and the existing admin cleanup route. - Preserved legacy no-org image generation, admin AI routes, text routes, video routes, payment-provider flows, and full tenant migration as out of scope.
Phase 2-H completed summary:
- Added backend-only
POST /api/ai/generate-textfor member-facing text generation with explicit organization context required. - Reused the existing HMAC-authenticated
AI_LABservice binding to call/internal/ai/test-text; no admin route handler is bypassed or charged. - Enforced active org membership,
owner/admin/memberrole,ai.text.generateentitlement, sufficient credits, andIdempotency-Key. - Reused
ai_usage_attemptsfor credit reservation, provider-call suppression, billing finalization, same-key conflict detection, and bounded text replay metadata. - No new migration was required; Phase 2-H uses existing
0036_add_ai_usage_attempts.sqlmetadata/status/expiry fields. - Preserved legacy no-org image generation, org-scoped image behavior, admin AI Lab text generation, text asset storage routes, video routes, payment-provider flows, frontend UI, and full tenant migration as out of scope.
Findings resolved:
| Original finding | Current status | Evidence |
|---|---|---|
| Failing static smoke tests | Resolved | PHASE0_REMEDIATION_REPORT.md records npm run test:static PASS, 155/155. |
Missing workers/ai/package-lock.json and unreproducible AI worker package checks |
Resolved | workers/ai/package-lock.json exists; .github/workflows/static.yml runs worker npm ci, npm ls --depth=0, and npm audit --audit-level=low. |
| Unsigned internal Auth-to-AI Worker requests | Resolved in code | js/shared/service-auth.mjs, workers/auth/src/lib/admin-ai-proxy.js, and workers/ai/src/index.js implement and enforce HMAC service auth. |
| Timestamp-only service-auth replay window | Resolved in code | workers/ai/src/lib/service-auth-replay.js, workers/ai/src/lib/service-auth-replay-do.js, and workers/ai/wrangler.jsonc implement nonce-backed replay protection via SERVICE_AUTH_REPLAY. |
| Request body-size limited parsers for prioritized Worker routes | Resolved for Phase 0-B scope | js/shared/request-body.mjs, workers/auth/src/lib/request.js, workers/contact/src/index.js, and workers/ai/src/lib/validate.js enforce route-specific limits before parsing. |
| Admin MFA fixed-window-only lockout | Resolved for Phase 0 hardening | workers/auth/migrations/0028_add_admin_mfa_failed_attempts.sql and workers/auth/src/lib/admin-mfa.js add durable failed-attempt state and reset-on-success behavior. |
| Async video poison-message persistence for malformed/exhausted messages | Resolved for video jobs | workers/auth/migrations/0030_harden_ai_video_jobs_phase1b.sql adds ai_video_job_poison_messages; workers/auth/src/lib/ai-video-jobs.js records redacted poison entries. |
| Runtime/toolchain pinning baseline | Resolved for Node/npm baseline | .nvmrc, package.json engines, and scripts/check-toolchain.mjs pin and validate Node 20/npm 10+ expectations. |
SESSION_SECRET overused across independent security boundaries |
Reduced | workers/auth/src/lib/security-secrets.js, session.js, admin-mfa.js, pagination.js, and generated-image-save-reference.js now use purpose-specific secrets for new writes with explicit legacy fallback. |
Findings reduced but not fully resolved:
| Original finding | Current status | Remaining risk |
|---|---|---|
| Sensitive route rate limits fail open or degrade to isolate-local memory | Reduced | Priority and several lower-priority write routes now fail closed, but this remains route-specific rather than a full SaaS abuse/entitlement platform. |
| Missing fail-closed Worker config validation | Reduced | Phase 0 critical auth/AI service-auth config fails closed, and repo-side Cloudflare prereq validation exists, but live Cloudflare resources and dashboard controls are not fully verified. |
| Cloudflare dashboard drift | Partially addressed | Release config and prereq validator now record service-auth/replay requirements, but live Cloudflare WAF/header/RUM/secrets/bindings are not fully repo-enforced or verified. |
| CI security gates | Reduced | Root/Worker npm checks, Cloudflare prereq tests, body-parser guard, toolchain check, scanner tests, secret scan, DOM sink baseline, and targeted JS syntax check are now in CI/preflight. CodeQL/SAST, dependency review, SBOM, and license gates remain open. |
| Async admin video job foundation | Reduced | Phase 1-B adds default admin UI async create/status polling, queue-safe provider task create/poll, R2 output ingest, and poison-message persistence. Phase 1-C adds sanitized poison/failed-job inspection APIs. Full operational maturity still needs staging verification and dashboards. |
| Synchronous AI video provider polling | Reduced | The default admin UI and async queue path no longer call the old long synchronous provider route. Phase 1-C default-disables /api/admin/ai/test-video unless ALLOW_SYNC_VIDEO_DEBUG=true, but the route still exists for controlled admin/debug fallback. |
| Purpose-specific security secrets | Reduced | Phase 1-D separates new session, pagination, admin MFA encryption/proof/recovery, and AI save-reference material from SESSION_SECRET; legacy fallback remains during the migration window. |
| Route security policy scattered across handlers | Reduced | workers/auth/src/app/route-policy.js, scripts/check-route-policies.mjs, source route-policy markers, CI/preflight integration, and tests/workers.spec.js now provide explicit high-risk auth-worker route metadata and coverage checks. |
| Missing operational runbooks/SLO baseline | Reduced | docs/SLO_ALERT_BASELINE.md, docs/OBSERVABILITY_EVENTS.md, docs/BACKUP_RESTORE_DRILL.md, docs/runbooks/*, and PHASE1F_OPERATIONAL_READINESS_REPORT.md define repo-owned operational expectations and incident procedures, but Cloudflare alerts and restore drills remain unproven. |
| Scan-prone admin audit/activity search and raw activity cursors | Reduced | 0031_add_activity_search_index.sql, workers/auth/src/lib/activity-search.js, updated workers/auth/src/routes/admin.js, and scripts/check-admin-activity-query-shape.mjs replace raw metadata search and raw cursors with indexed projection search and signed cursors for the admin audit/activity endpoints. |
| Compliance-grade data lifecycle | Reduced | 0032_add_data_lifecycle_requests.sql, 0033_harden_data_export_archives.sql, workers/auth/src/lib/data-lifecycle.js, workers/auth/src/lib/data-export-archive.js, workers/auth/src/lib/data-export-cleanup.js, workers/auth/src/routes/admin-data-lifecycle.js, DATA_INVENTORY.md, docs/DATA_RETENTION_POLICY.md, and docs/DATA_DELETION_EXECUTOR_DESIGN.md add admin/support planning foundations, bounded export archive generation, private archive metadata, bounded expired archive cleanup, safe reversible-action execution, deletion executor design, and retention documentation. User self-service, contact processor workflow, legal policy approval, irreversible deletion execution, and historical R2 owner backfill remain open. |
| Billing/plans/entitlements foundation | Reduced | 0035_add_billing_entitlements.sql, 0036_add_ai_usage_attempts.sql, 0037_add_billing_event_ingestion.sql, 0038_add_stripe_credit_pack_checkout.sql, 0039_raise_credit_balance_cap_for_pricing_packs.sql, workers/auth/src/lib/billing.js, workers/auth/src/lib/ai-usage-policy.js, workers/auth/src/lib/ai-usage-attempts.js, workers/auth/src/lib/billing-events.js, workers/auth/src/lib/stripe-billing.js, workers/auth/src/routes/orgs.js, workers/auth/src/routes/admin-billing.js, workers/auth/src/routes/billing-webhooks.js, workers/auth/src/routes/ai/text-generate.js, route-policy/release updates, and Worker tests add default free plan resolution, org billing/entitlement reads, admin plan/org billing inspection, idempotent credit grants, idempotent credit consumption helpers, org-scoped image and text generation credit enforcement, credit reservations, duplicate provider-call suppression, temporary result replay, bounded cleanup, provider-neutral billing event ingestion, Stripe Testmode credit-pack checkout, verified Testmode checkout webhook credit grants, admin-only Pricing page checkout initiation, and sanitized admin billing/usage inspection. Live payment activation, subscriptions, invoices, customer portal, taxes, public pricing rollout, and broad/video route-level credit enforcement remain open. |
Findings still open:
- Synchronous AI video provider polling is reduced but not eliminated because the legacy compatibility route still exists behind
ALLOW_SYNC_VIDEO_DEBUG=trueand should be retired after async staging confidence. - Full lint/typecheck/checkJs and safe DOM remediation remain incomplete; Phase 1-C added low-risk baseline gates, and Phase 1-E added route policy guardrails for high-risk auth-worker route review.
- Legacy
SESSION_SECRETfallback remains enabled until operators provision new secrets, deploy Phase 1-D safely, verify compatibility, and explicitly disable fallback after the migration window. - Large admin/frontend/test modules remain monolithic.
- Historical audit/activity backfill, non-video queue schemas/DLQ, full tenant isolation, live payment-provider activation, permanent provider-result caching beyond temporary replay, video route credit enforcement, user self-service privacy flows, irreversible deletion execution, full observability/SLOs, and load/performance budgets remain open or deferred.
Current merge/deploy status:
| Area | Status | Notes |
|---|---|---|
| Merge readiness | Pending final Admin Control Plane validation/review | The Admin Control Plane phase adds frontend-only admin surfaces, API wrappers, CSS, static tests, and documentation. Full command evidence is recorded in PHASE_ADMIN_CONTROL_PLANE_REPORT.md; all changed/new Admin Control Plane files must be committed together after review. |
| Production deploy readiness | Blocked | Do not deploy until all required Worker secrets/bindings are live-verified, auth migrations 0028-0038 are applied, SERVICE_AUTH_REPLAY, bitbi-ai-video-jobs, USER_IMAGES, AUDIT_ARCHIVE, and AI_LAB are verified, Stripe Testmode config/secrets and webhook endpoint are configured in staging, VIDU_API_KEY is provisioned if Vidu async jobs are enabled, ALLOW_SYNC_VIDEO_DEBUG is absent/false unless explicitly approved, live health/header checks run with --require-live, dashboard-managed WAF/header/RUM/alert controls are verified, Phase 1-G activity projection writes/search are verified in staging, Phase 1-H/1-I/1-J data lifecycle planning/archive generation/archive cleanup/safe executor behavior is verified in staging, Phase 2-A organization flows are verified in staging after migration 0034, Phase 2-B billing/entitlement/credit flows are verified in staging after migration 0035, Phase 2-D/E/F/H AI usage/replay/cleanup behavior is verified in staging after migration 0036, Phase 2-I billing event ingestion is verified in staging after migration 0037, Phase 2-J Stripe Testmode checkout/webhook/exactly-once-credit-grant behavior is verified in staging after migration 0038, and the Admin Control Plane UI is verified in staging against real admin APIs. |
| Current recommended next phase | Stripe hardening, video AI route, or tenant track | Choose one narrow track: harden Stripe Testmode/staging operations toward later live-readiness review, wire an async/member-safe video route family to entitlements/credits, or continue domain-by-domain tenant ownership migration. Do not combine all tracks into one broad rewrite. |
This repository is a real product codebase, not a toy prototype. It has meaningful Cloudflare Worker route tests, release compatibility checks, D1 migrations, admin MFA, private media handling, R2 cleanup flows, queue consumers, signed pagination in some places, and deliberate static asset versioning. Those are serious foundations.
It is not yet state-of-the-art SaaS production standard. The main blockers are not one-off bugs. They are systemic gaps: failing static smoke tests, inconsistent rate-limit fail-closed behavior on privileged and expensive paths, no defense-in-depth authentication on the internal AI worker, synchronous long-running AI video work, no enforced Cloudflare infrastructure-as-code for dashboard-managed security behavior, weak supply-chain reproducibility for workers/ai, no static type system, large monolithic modules, and missing enterprise SaaS primitives such as organizations, tenant isolation, billing enforcement, compliance-grade data lifecycle, SLOs, structured alerting, and disaster recovery evidence.
Current maturity estimate: functional single-product SaaS foundation, approximately 4.5 out of 10 for enterprise SaaS readiness. The repository can likely support a controlled launch if the failing tests are fixed and operational runbooks are followed. It should not be treated as enterprise-ready or investor/security-review-ready without the Phase 0 and Phase 1 work in this document.
Observed architecture:
| Area | Evidence | Assessment |
|---|---|---|
| Static frontend | index.html, account/, admin/, legal/, js/, css/ |
Plain HTML/CSS/vanilla ES modules. Intentional according to AGENTS.md. |
| Auth/API worker | workers/auth/src/index.js, workers/auth/src/routes/, workers/auth/src/lib/ |
Primary API surface for auth, account, admin, private media, member AI assets, admin AI proxy, queues, cron. |
| AI service worker | workers/ai/src/index.js, workers/ai/src/routes/, workers/ai/src/lib/ |
Internal AI lab service behind service binding. Handles Cloudflare AI, AI Gateway, Vidu fallback, live agent. |
| Contact worker | workers/contact/src/index.js |
Contact form endpoint on contact.bitbi.ai using Resend and Durable Object rate limiting. |
| Database | workers/auth/migrations/*.sql |
Cloudflare D1 schema with users, sessions, reset/verification tokens, profiles, favorites, AI folders/images/assets, quota usage, wallet SIWE, admin MFA. |
| Object storage | workers/auth/wrangler.jsonc:81-97 |
R2 buckets for private media, user images, audit archive. |
| Queues | workers/auth/wrangler.jsonc:23-47 |
AI image derivatives and activity ingest queues. |
| Durable Objects | workers/auth/wrangler.jsonc:67-80, workers/contact/wrangler.jsonc |
Public rate limiter DOs. |
| Cloudflare Images | workers/auth/wrangler.jsonc:58-60 |
Image derivative pipeline depends on Images binding. |
| Release contract | config/release-compat.json |
Strong repo-enforced release compatibility model, but manual dashboard prerequisites remain. |
| CI/CD | .github/workflows/static.yml |
GitHub Pages deploy only. Workers deploy separately. Runs release checks, worker tests, static smoke tests, build. |
| Tests | tests/*.spec.js, playwright.config.js, playwright.workers.config.js |
Playwright static and worker tests. Worker suite is broad; static suite currently fails locally. |
| Tooling | package.json, worker package files |
No TypeScript, no lint script, no formatter script, no coverage script. workers/ai lacks package lock. |
Main execution flows:
| Flow | Path evidence | Notes |
|---|---|---|
| Register/login/session | workers/auth/src/routes/auth.js, workers/auth/src/lib/session.js, workers/auth/src/lib/cookies.js |
D1 user/session model, new session tokens hashed with SESSION_HASH_SECRET, legacy SESSION_SECRET fallback during Phase 1-D compatibility, cookies are HttpOnly, production admin secure-session policy exists. |
| Password reset/email verification | workers/auth/src/routes/password.js, workers/auth/src/routes/verification.js, workers/auth/src/lib/email.js |
Token-hash model, Resend email, some best-effort behavior if email send fails. |
| Admin protection | workers/auth/src/lib/session.js:187-257, workers/auth/src/routes/admin-mfa.js |
Role check plus production MFA enforcement. MFA endpoints lack route-level rate limiting. |
| Admin AI | workers/auth/src/routes/admin-ai.js, workers/auth/src/lib/admin-ai-proxy.js, workers/ai/src/index.js |
Auth worker proxies admin requests to AI worker via service binding. AI worker itself does not verify a signed service credential. |
| Member AI image generation | workers/auth/src/routes/ai/images-write.js |
Per-user generation limiter and daily quota slots. Generated image payloads are returned to client and later saved. |
| Private media | workers/auth/src/routes/media.js, workers/auth/src/routes/avatar.js, workers/auth/src/routes/ai/files-read.js |
Authenticated ownership checks for private images/music/text assets. |
| Favorites and galleries | workers/auth/src/routes/favorites.js, static modules under js/pages/index/ |
Static catalog plus authenticated favorite state. |
| Wallet/SIWE | workers/auth/src/routes/wallet.js, js/shared/wallet/ |
Nonce/challenge flow, address checks, local wallet UI state. |
| Background work | workers/auth/src/index.js:300-459 |
Cron R2 cleanup and derivative re-enqueue; queue consumer processes activity and derivatives. |
Product domain:
The codebase appears to power BITBI, a media and AI creative SaaS with public galleries, Sound Lab, video/gallery decks, user accounts, saved AI images/assets, favorites, profile/avatar features, admin user management, admin AI lab tooling, wallet sign-in/linking, and contact form.
Missing production context that matters:
| Missing evidence | Why it matters | How to verify |
|---|---|---|
| Cloudflare dashboard WAF/rate-limit rules | Repo explicitly says some security behavior is dashboard-managed. | Export Cloudflare rules or codify with Terraform/OpenTofu/Cloudflare API validation. |
| Static security headers transform rules | Static Pages headers depend on dashboard state. | Verify live response headers and encode rules in IaC or deployment checks. |
| Secret inventory and rotation policy | Phase 1-D separates auth purpose secrets, but Resend, Vidu, AI Gateway and future billing secrets still need lifecycle control. | Document secret owners, rotation cadence, break-glass, and validation tests. |
| Backup/restore evidence for D1/R2 | SaaS data durability cannot be inferred from code alone. | Run restore drills and add runbooks with RPO/RTO. |
| Production observability dashboards/alerts | Logs are enabled but traces, alerts, SLOs are not repo-defined. | Link dashboards, alert rules, on-call policy, and SLO burn alerts. |
| Load/performance baselines | No load tests or capacity targets were found. | Add k6/Artillery/Workers load tests and set budgets. |
| Legal/compliance operating procedures | App handles accounts, email, IPs, generated assets and audit logs. | Document retention, deletion, export, DPA/privacy flows, subprocessors. |
All commands below were non-destructive. Deployment, production mutation, destructive git commands, D1 remote migrations, and release:apply were not run.
| Command | Result | Interpretation |
|---|---|---|
git status --short |
Clean before audit documentation work | Baseline was clean before report files were added. |
npm run test:release-compat |
Passed | Release compatibility contract is currently internally consistent. |
npm run test:release-plan |
Passed | Release planner tests pass. |
npm run test:asset-version |
Passed | Static asset-version placeholders and references pass current validation. |
npm run validate:release |
Passed | Release contract validates against repo state. |
npm run validate:asset-version |
Passed | Asset version validation passes. |
npm run test:workers |
Passed, 245 tests | Worker route tests are a relative strength. |
npm run test:static |
Failed, 152 passed and 3 failed | Main static smoke suite is not green locally. This is release-blocking because .github/workflows/static.yml:190-191 runs it before deploy. |
npm audit --audit-level=low at repo root |
Initial sandbox DNS failure, rerun with approved network succeeded, 0 vulnerabilities | Root dependency audit is clean at current lockfile. |
npm audit --audit-level=low in workers/auth |
Initial sandbox DNS failure, rerun with approved network succeeded, 0 vulnerabilities | Auth worker dependency audit is clean at current lockfile. |
npm audit --audit-level=low in workers/contact |
Initial sandbox DNS failure, rerun with approved network succeeded, 0 vulnerabilities | Contact worker dependency audit is clean at current lockfile. |
npm audit --audit-level=low in workers/ai |
Failed with ENOLOCK |
Real repo issue: workers/ai has no lockfile, so it cannot be audited reproducibly. |
npm ls --depth=0 at root |
Passed | Root installed packages resolve. |
npm ls --depth=0 in workers/auth |
Passed | Auth worker installed packages resolve. |
npm ls --depth=0 in workers/contact |
Passed | Contact worker installed packages resolve. |
npm ls --depth=0 in workers/ai |
Failed, UNMET DEPENDENCY wrangler@^4.81.0 |
Real repo issue: AI worker install state is incomplete and no lockfile exists. |
node --version |
v24.14.0 |
Local runtime differs from CI Node 20 in .github/workflows/static.yml:33-39, 57-63, 181-187. |
npm --version |
11.9.0 |
Local npm likely differs from CI. Pinning via engines or toolchain file is absent. |
npm run release:plan |
Passed, no file changes | Release plan script reports manual prerequisites and deploy order. |
npm run release:preflight |
Passed | Aggregated release checks passed, but note static smoke failure was run separately and failed. |
npm run build:static |
Not run by design | It rewrites _site; audit scope allowed documentation files only. |
npx wrangler deploy, D1 remote migrations, npm run release:apply |
Not run | Production-affecting commands were intentionally avoided. |
| Typecheck/lint/format/coverage | Not available as repo scripts | Tooling maturity gap. package.json:4-20 has no lint, typecheck, format, or coverage script. |
Static test failures observed:
| Test | Evidence | Failure meaning |
|---|---|---|
refreshing mid-page preserves the current scroll position |
tests/smoke.spec.js:369-383, source candidate index.html:44 |
Reload scroll restoration regressed by 793 px locally. |
refreshing near the category stage does not auto-jump the stage under the header |
tests/smoke.spec.js:386-414, source candidate index.html:44 and js/pages/index/category-carousel.js |
Reload near home category stage regressed by 237 px locally. |
Sign In with Ethereum shows a discovery state... |
tests/wallet-nav.spec.js:369-383, source candidate js/shared/wallet/wallet-controller.js |
Wallet discovery UI state regressed; modal skips the expected discovery text when injected wallet announcement is delayed. |
| ID | Severity | Category | Evidence | Summary |
|---|---|---|---|---|
| C1 | High | Release quality | npm run test:static failed; .github/workflows/static.yml:190-191 |
Static smoke suite is failing. The repo is not in a releasable state until this is fixed or explained as an environment-specific false positive. |
| C2 | High | Security | workers/auth/src/routes/admin-mfa.js:52-240 |
Admin MFA setup/enable/verify/disable/recovery endpoints lack route-level rate limiting and lockout/backoff. |
| C3 | High | Security/abuse | workers/auth/src/lib/rate-limit.js:300-360, workers/auth/src/lib/admin-ai-proxy.js:37-41, workers/auth/src/routes/admin.js:174-176 |
Privileged and expensive route rate limits fail open to per-isolate memory unless configured otherwise. |
| C4 | High | Service security | workers/ai/src/index.js:15-72, workers/auth/src/lib/admin-ai-proxy.js:134-151 |
Internal AI worker accepts /internal/ai/* requests without signed service authentication. |
| C5 | High | Reliability/scalability | workers/ai/src/lib/invoke-ai-video.js:327-563 |
Vidu video fallback can synchronously poll for up to 450 seconds in a request path. |
| C6 | High | Supply chain | workers/ai/package.json:1-14; no workers/ai/package-lock.json |
AI worker dependency install/audit is not reproducible and currently fails npm ls. |
| C7 | Medium/High | Operations | config/release-compat.json:224-244 |
WAF, static security headers, and RUM settings remain dashboard-managed and are not repo-enforced. |
| C8 | Medium/High | Maintainability | wc -l: js/pages/admin/ai-lab.js 4613 lines, tests/workers.spec.js 12497 lines |
Critical code and tests are monolithic, untyped, and hard to safely scale across a team. |
| C9 | Medium/High | Database/performance | workers/auth/src/routes/admin.js:679-703, 746-788; workers/auth/migrations/0012_add_user_activity_log.sql |
Admin/activity search and counts will scan large tables; cursors are raw unsigned strings in activity endpoints. |
| C10 | Medium/High | SaaS readiness | Schema and routes are user-centric only | No organization/team model, tenant isolation boundary, billing model, feature flags, compliance-grade data export/deletion, or SLO-defined operations. |
Severity: High
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/routes/admin-mfa.js |
Setup, enable, verify, disable, and recovery-code regeneration handlers parse bodies and call MFA functions without any isSharedRateLimited or lockout check at 52-240. |
workers/auth/src/lib/admin-mfa.js |
TOTP is 6 digits with one time-step window at 16-21; replay guard exists later, but brute-force throttling is not visible at the route boundary. |
Why it is dangerous:
Admin MFA is the final gate after password/session compromise. Without route-level throttling and account/IP backoff, a compromised admin password/session can repeatedly attempt TOTP or recovery code verification until external rate limits intervene. Dashboard WAF cannot be the only control because same-origin authenticated traffic can still be abusive.
Exploit or failure scenario:
An attacker obtains an admin password and session cookie, then scripts /api/admin/mfa/verify with TOTP guesses or stolen recovery code candidates. Application-layer audit logs see failures, but no deterministic per-admin/per-IP lockout stops attempts.
Recommended fix:
Add fail-closed Durable Object rate limiting and lockout for MFA verification and recovery-code attempts, keyed by admin user id plus IP. Add separate lower limits for setup/disable/regenerate. Record failed attempt counters and lockout expiration in D1 for durable account protection.
Best-practice alternative:
Use WebAuthn/passkeys for admin step-up and keep TOTP only as a fallback. Require fresh password or WebAuthn assertion for disabling MFA or regenerating recovery codes.
Estimated difficulty: Medium
Priority: P0
Severity: High
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/lib/rate-limit.js:300-360 |
isSharedRateLimited falls back to in-memory counters unless failClosed is set. |
workers/auth/src/lib/admin-ai-proxy.js:37-41 |
Admin AI rate limiting does not pass failClosedInProduction or Durable Object backend options. |
workers/auth/src/routes/admin.js:174-176 |
Admin role mutation uses shared rate limiting without fail-closed options. |
workers/auth/src/routes/avatar.js:274-276 |
Avatar upload limiter uses default behavior, then parses multipart form data. |
workers/auth/src/routes/ai/images-write.js:220-221 |
Member AI generation limiter uses default behavior. |
Why it is dangerous:
The code has good fail-closed patterns for public auth/contact paths, but not consistently for expensive or privileged authenticated paths. If D1 rate-limit counters are unavailable, the fallback is per-isolate memory. Under Cloudflare scaling, that is not a global abuse control.
Exploit or failure scenario:
D1 has an outage or migration issue. An attacker with a valid low-privilege account sends many AI generation requests. Each isolate enforces its own memory counter, bypassing the intended global quota, increasing costs and load.
Recommended fix:
Make a default policy: privileged, auth, admin, upload, and AI-cost paths must use Durable Object rate limiting and fail closed in production. Keep fail-open only for low-risk read-only paths, and make that explicit with a named option.
Best-practice alternative:
Centralize abuse policy in a declarative route registry with per-route limiter backend, key, limits, fail behavior, and audit event names.
Estimated difficulty: Medium
Priority: P0
Severity: High
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/ai/src/index.js:15-72 |
/internal/ai/* routes dispatch directly to handlers. No token, mTLS, HMAC, or service-auth validation is present. |
workers/auth/src/lib/admin-ai-proxy.js:134-151 |
Auth worker sends admin id/email headers and correlation id, but no signed proof. |
workers/ai/wrangler.jsonc:5-6 |
workers_dev:false and preview_urls:false reduce exposure, but are deployment configuration controls, not application authentication. |
Why it is dangerous:
The AI worker is protected by topology rather than by a cryptographic service boundary. A future route misconfiguration, preview exposure, custom domain, or additional service binding could expose expensive AI endpoints.
Exploit or failure scenario:
An operator adds a route for debugging or enables preview URLs. Attackers call /internal/ai/test-video directly and trigger AI/Vidu spend without an admin session.
Recommended fix:
Add a shared service secret for auth-to-AI calls. Sign method, path, timestamp, body hash, correlation id, and admin id with HMAC. Reject missing, expired, replayed, or invalid signatures in workers/ai before dispatch.
Best-practice alternative:
Use Cloudflare service binding plus application-level HMAC plus narrow per-route allowlist and structured audit logs of rejected internal calls.
Estimated difficulty: Medium
Priority: P0
Severity: Medium/High
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/lib/session.js:52,99 |
Session token hashes derive from SESSION_SECRET. |
workers/auth/src/lib/admin-mfa.js:115-180 |
Admin MFA proof HMAC keys and AES-GCM encryption keys derive from SESSION_SECRET. |
config/release-compat.json:158-167 |
Manual prerequisite states SESSION_SECRET is required for sessions, signed pagination cursors, and admin MFA material. |
Why it is dangerous:
One secret compromise invalidates multiple independent security boundaries: sessions, admin MFA secret encryption, admin MFA proof signing, signed cursor material if used by pagination. It also complicates safe rotation because every use case has different blast radius and migration needs.
Exploit or failure scenario:
If SESSION_SECRET leaks, an attacker may not only attack sessions but also decrypt MFA secrets or mint MFA proof material depending on implementation details and available ciphertexts.
Recommended fix:
Split secrets by purpose: SESSION_HASH_SECRET, PAGINATION_SIGNING_SECRET, ADMIN_MFA_ENCRYPTION_KEY, ADMIN_MFA_PROOF_SECRET, AI_SERVICE_AUTH_SECRET. Add key ids and rotation support.
Best-practice alternative:
Use a small key-management module with versioned keys, purpose labels, rotation plan, and tests proving old tokens remain valid only for defined grace periods.
Estimated difficulty: Medium/Large
Priority: P1
Severity: Medium
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/lib/session.js:52,99 |
env.SESSION_SECRET is interpolated directly. |
workers/auth/src/lib/admin-mfa.js:115-119 |
MFA helper explicitly throws if missing, but session hashing does not. |
Why it is dangerous:
If SESSION_SECRET is absent in a non-production or misconfigured production environment, token hashing uses the string value of an undefined binding. That weakens isolation between environments and hides critical config mistakes.
Exploit or failure scenario:
A preview or staging Worker lacks SESSION_SECRET, silently uses predictable hash material, and sessions become transferable or forgeable within that environment.
Recommended fix:
Add environment validation on every Worker startup/fetch path before security-sensitive logic. Fail closed with a generic 503 and log a redacted config error if critical secrets are absent or too short.
Best-practice alternative:
Create assertAuthWorkerConfig(env) and assertAiWorkerConfig(env) functions with tests for missing/invalid bindings.
Estimated difficulty: Small
Priority: P0/P1
Severity: Medium
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/contact/src/index.js:133-155 |
Calls request.json() before field slicing/length limits. |
workers/auth/src/routes/avatar.js:298-323 |
Calls request.formData() before checking file.size. |
workers/auth/src/routes/ai/images-write.js:224-235 |
Reads JSON prompt body through common helper; repository evidence did not show a global byte-size gate. |
Why it is dangerous:
Field-level limits after parsing do not protect CPU/memory from large request bodies. Workers have runtime limits; attackers can cause high memory or latency before validation rejects data.
Exploit or failure scenario:
An unauthenticated or low-privilege client posts an oversized JSON/multipart body to contact or avatar endpoints. The Worker spends memory parsing before applying small field limits.
Recommended fix:
Enforce Content-Length limits where present, stream/size-limit body reads, and reject unsupported media types before parsing. Use endpoint-specific max body sizes.
Best-practice alternative:
Centralize request parsing helpers: readJsonBodyLimited(request, maxBytes) and readFormDataLimited(request, maxBytes).
Estimated difficulty: Small/Medium
Priority: P1
Severity: Medium
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/routes/admin.js:679-682 |
Admin audit search uses %search% over admin email, target email, action, and meta_json. |
workers/auth/src/routes/admin.js:770-773 |
User activity search uses %search% over user email, action, and meta_json. |
Why it is dangerous:
This is mostly performance and data-governance risk, not SQL injection because bindings are used. Searching raw JSON metadata broadens accidental sensitive-data exposure to admins and becomes expensive on large logs.
Exploit or failure scenario:
An admin searches short terms repeatedly; D1 scans large log tables and returns metadata containing fields that should not be routinely browsed.
Recommended fix:
Define an explicit searchable audit projection. Index action, created_at/id, actor, target, and normalized email prefixes. Avoid %term% over raw JSON.
Best-practice alternative:
Move audit search to a dedicated log/search store with field-level redaction and RBAC for support/admin roles.
Estimated difficulty: Medium
Priority: P2
Severity: Medium
Confidence: Medium
Affected files:
| File | Evidence |
|---|---|
js/pages/index/soundlab.js:47 |
Large template uses ${tr.artwork} and ${tr.title} in innerHTML. |
js/pages/index/locked-sections.js:218,326 |
Templates insert media URLs/titles into HTML. |
js/shared/soft-nav.js:59 |
Copies newMain.innerHTML during soft navigation. |
js/pages/admin/ai-lab.js |
Many innerHTML sinks in a 4613-line admin file. |
Why it is dangerous:
The current catalog data appears mostly local/static, and some modules escape data. But the codebase has no enforced safe DOM abstraction, no lint rule, and no CSP evidence in repo. As the product grows, one user/admin-supplied value flowing into a template becomes XSS.
Exploit or failure scenario:
A future admin-provided title or AI-generated metadata is rendered through an existing template without escaping, executing script in an authenticated user/admin context.
Recommended fix:
Create safe DOM helpers, ban raw innerHTML except reviewed constants, and add an ESLint/Semgrep rule. Convert data-driven templates to textContent, setAttribute, and DOM node construction.
Best-practice alternative:
Adopt a small trusted rendering layer that requires explicit htmlTrustedConstant() for static SVG/markup and default-escapes all dynamic values.
Estimated difficulty: Medium/Large
Priority: P1/P2
Severity: Medium
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/lib/passwords.js |
PBKDF2-SHA256 default/cap is 100,000 iterations. |
workers/auth/src/routes/auth.js |
Registration enforces length but not broader password-risk controls. |
Why it is dangerous:
PBKDF2 at 100k is acceptable in constrained Workers but not world-class password storage compared to Argon2id/scrypt. Length-only validation also misses compromised password checks.
Exploit or failure scenario:
If the D1 user table leaks, password cracking cost is lower than a modern Argon2id baseline.
Recommended fix:
Raise iterations if Worker latency budget allows, add password breach checks where appropriate, promote wallet/passkey login, and add admin MFA/WebAuthn requirements.
Best-practice alternative:
Use WebAuthn/passkeys for high-privilege roles and an auth provider or isolated password-hashing service if stronger memory-hard hashing is required.
Estimated difficulty: Medium
Priority: P2
Severity: Medium
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/lib/email.js |
Verification/reset email helpers call Resend directly and return/suppress failures in places. |
workers/auth/src/routes/password.js |
Forgot-password response is generic, which is good, but delivery failure is logged and the request still returns generic success. |
Why it is dangerous:
Direct provider calls couple UX-critical auth flows to a third-party transient state. Generic success is correct for enumeration prevention, but without delivery status/outbox retry, users get stuck and support has poor diagnostics.
Exploit or failure scenario:
Resend has a transient failure. Reset tokens are created but emails do not arrive; users retry and create more tokens, support cannot tell whether delivery failed or the user missed the email.
Recommended fix:
Add an auth email outbox table/queue with provider status, retry/backoff, idempotency keys, and support-visible redacted delivery diagnostics.
Best-practice alternative:
Use a transactional email service abstraction with durable queue, webhook event ingestion, suppression handling, and template versioning.
Estimated difficulty: Medium
Priority: P2
Severity: Medium
Confidence: High
Affected files:
| File | Evidence |
|---|---|
workers/auth/src/index.js:433-448 |
If a batch is neither activity nor derivative, logs an error and ack()s each message. |
Why it is dangerous:
Silently acknowledging unknown messages can permanently drop messages after routing/config bugs. This protects the queue from poison loops but reduces forensic recovery.
Exploit or failure scenario:
A deploy changes message shape or queue name. Messages are misclassified, acknowledged, and lost before the issue is noticed.
Recommended fix:
Send unrecognized messages to a dead-letter queue or durable audit table instead of ack-only. Include message id, queue, sanitized body shape, and deploy version.
Best-practice alternative:
Version all queue messages with schemas and reject unknown versions to a DLQ with alerting.
Estimated difficulty: Medium
Priority: P2
Severity: Medium/High
Confidence: High
Affected files:
| File | Evidence |
|---|---|
config/release-compat.json:224-244 |
WAF rule, static security Transform Rules, and RUM setting are manual/dashboard-managed. |
Why it is dangerous:
Security controls that live only in a dashboard drift silently. The repository cannot prove production has the intended headers/rate limits/privacy settings.
Exploit or failure scenario:
A dashboard rule is edited or deleted during incident work. CI continues to pass, but production loses security headers or WAF throttling.
Recommended fix:
Move Cloudflare dashboard controls into IaC or add a CI/live validation step that fails if live settings drift.
Best-practice alternative:
Use Terraform/OpenTofu/Cloudflare API-managed infrastructure with drift detection and environment-specific plans.
Estimated difficulty: Medium/Large
Priority: P1
| Strength | Evidence |
|---|---|
| Same-origin guard for mutating auth worker requests | workers/auth/src/index.js:131-143 checks Origin or Referer; email verification GET is intentionally exempt at 64-68. |
| Admin secure-session policy | workers/auth/src/lib/session.js:207-219 requires secure transport and secure cookie in production. |
| Admin MFA enforcement exists | workers/auth/src/lib/session.js:221-253 rejects production admin access when MFA proof/enrollment is required. |
Session cookies are HttpOnly, SameSite=Lax, and secure in secure contexts |
workers/auth/src/lib/cookies.js. |
| SIWE wallet flow is relatively robust | Nonce, domain, URI, version, chain, statement, timestamp, and signature checks exist in workers/auth/src/routes/wallet.js; nonce/verify use fail-closed DO limits. |
| Contact form has strict origin and fail-closed Durable Object limiter | workers/contact/src/index.js:70-131. |
| Avatar MIME type and magic bytes are checked | workers/auth/src/routes/avatar.js:311-327. |
| Private media access uses authenticated route ownership | workers/auth/src/routes/media.js, workers/auth/src/routes/ai/files-read.js. |
Evidence: workers/ai/src/lib/invoke-ai-video.js:327-563 creates a Vidu task and polls until a URL is returned or timeout. Default timeout is 450,000 ms at 36-37.
Why it will not scale:
Long-running Worker requests tie up runtime, increase failure probability, amplify provider latency, and create poor user/admin UX under load.
How it manifests under load:
Concurrent video tests generate many open outbound connections and long requests. Retries can duplicate provider work. Admin UI waits rather than observing job state.
How to measure:
Record p50/p95/p99 duration for /api/admin/ai/test-video, provider task creation latency, poll attempts, timeout rate, and Worker CPU/wall time. Add synthetic load for concurrent video requests.
Recommended fix:
Move video generation to a job model: create job row, enqueue provider work, poll/provider callback updates D1/R2, UI polls job status or uses SSE.
Expected benefit:
Lower request tail latency, safer retries, clearer cost control, better observability.
Priority: P0/P1
Evidence: workers/auth/src/routes/admin.js:679-703 searches joined audit logs with %search% and runs GROUP BY action over all audit rows. User activity search at 770-788 has the same pattern.
Why it will not scale:
Wildcard search over emails/actions/raw JSON prevents efficient indexing. Counts over all history become slower as logs grow.
How it manifests under load:
Admin activity pages become slow, D1 query time grows, and support dashboards compete with user traffic.
How to measure:
Seed 100k, 1M, and 10M audit rows locally or in staging. Track query duration and D1 read units for search, empty search, and counts.
Recommended fix:
Use signed cursor pagination everywhere, add indexed normalized columns, pre-aggregate counts by day/action, and avoid searching meta_json.
Expected benefit:
Predictable admin latency and lower D1 cost.
Priority: P1
Evidence: workers/auth/src/routes/ai/assets-read.js:25-59 returns /api/ai/images with LIMIT 200, while /api/ai/assets has signed cursor pagination at 61-120.
Why it will not scale:
Hard-capped unpaginated endpoints create UX truncation and push clients to refetch large pages.
How it manifests under load:
Users with more than 200 images see incomplete results or repeated large payloads.
How to measure:
Create users with 50, 200, 1000 assets and measure response size, time to render, and client memory.
Recommended fix:
Deprecate /api/ai/images in favor of /api/ai/assets or add cursor pagination to the image-only endpoint.
Expected benefit:
Lower payloads and consistent asset browsing.
Priority: P2
Evidence: workers/auth/src/routes/ai/images-write.js decodes/saves image data and returns generation results including image data in the request/response flow.
Why it will not scale:
Base64 adds approximately 33 percent payload overhead and increases Worker/client memory pressure. Large generated assets are better stored once and referenced.
How it manifests under load:
Slow generation responses, higher egress, higher memory, larger browser heap, higher chance of request failure.
How to measure:
Track response sizes, browser heap, and Worker memory/latency for each model output size.
Recommended fix:
Write generated outputs directly to R2 temporary storage and return signed references/URLs. Keep save references HMAC-signed and short-lived.
Expected benefit:
Smaller responses and safer asset lifecycle.
Priority: P1/P2
Evidence: temp object cleanup lists only 1000 objects at workers/auth/src/index.js:81-85; R2 cleanup queue processes 50 rows at 300-356; derivative recovery enqueues 25 rows at 361-419.
Why it will not scale:
Fixed small batches are safe, but without backlog metrics and alerts they can fall permanently behind after outages or traffic spikes.
How it manifests under load:
Expired temp objects accumulate, cleanup queues grow, derivative backlog persists, storage cost increases.
How to measure:
Emit metrics for scanned/deleted/failed counts, queue depth, oldest pending row age, derivative backlog and oldest pending derivative.
Recommended fix:
Add backlog metrics/alerts and adaptive pagination loops bounded by runtime budget.
Expected benefit:
Operational visibility and predictable cleanup.
Priority: P2
Evidence: No bundler or performance budget exists in package.json:4-20 or CI. The frontend uses many ES modules and large files such as js/pages/admin/ai-lab.js with 4613 lines.
Why it will not scale:
Without bundle/perf budgets, page weight and module waterfalls can grow invisibly.
How it manifests under load:
Slow first load on mobile, more requests, worse Core Web Vitals, harder cache invalidation.
How to measure:
Add Lighthouse CI or WebPageTest scripts for homepage/account/admin with budgets for JS bytes, CSS bytes, LCP, CLS, INP.
Recommended fix:
Keep vanilla architecture if desired, but add performance budgets, module splitting discipline, and static analysis of JS/CSS sizes.
Expected benefit:
Prevents front-end degradation without requiring framework migration.
Priority: P2
Evidence: workers/auth/src/lib/rate-limit.js:321-333 writes/updates a D1 counter for each limited request unless Durable Object backend is selected.
Why it will not scale:
D1 is not ideal as a high-frequency global counter backend for hot abuse paths.
How it manifests under load:
Write contention, increased latency, rate-limit failures during DB degradation.
How to measure:
Compare D1 limiter p95 latency and error rate against DO limiter under concurrent request load.
Recommended fix:
Use Durable Object counters for hot abuse paths; reserve D1 for durable audit snapshots or low-rate limits.
Expected benefit:
Lower DB pressure and cleaner failure modes.
Priority: P1
The architecture is a Cloudflare-native, mostly serverless SaaS:
| Layer | Current design |
|---|---|
| Frontend | Static GitHub Pages site, vanilla JS modules, CSS, no SPA framework. |
| API gateway | workers/auth handles /api/* on bitbi.ai. |
| Internal AI service | workers/ai via Cloudflare service binding, no public route in wrangler config. |
| Contact service | Separate Worker on custom domain. |
| Data | D1 for relational account/app metadata, R2 for binary assets, Cloudflare Images for derivatives, Queues for async derivatives/activity ingest, DOs for rate limits. |
| Release | GitHub Pages workflow for static deploy; Workers deploy separately via wrangler/release scripts. |
Good architecture choices:
| Choice | Evidence | Why it is good |
|---|---|---|
| Static frontend is intentionally simple | AGENTS.md, package.json:4-20 |
Low hosting complexity and small dependency surface. |
| Auth, AI, contact are separate Workers | workers/* |
Clear service-level separation. |
| Release compatibility contract exists | config/release-compat.json |
Prevents drift in critical routes/bindings/migrations. |
| Queues are used for derivatives/activity | workers/auth/wrangler.jsonc:23-47 |
Correct direction for async work. |
| D1 migrations are explicit | workers/auth/migrations |
Better than implicit schema drift. |
| Some cursor pagination is signed | workers/auth/src/routes/admin.js:102-156, workers/auth/src/routes/ai/assets-read.js:74-93 |
Protects pagination state where applied. |
Dangerous or missing boundaries:
| Missing/dangerous boundary | Evidence | Risk |
|---|---|---|
| No service-auth boundary for AI worker | workers/ai/src/index.js:15-72 |
Topology-only protection fails under misconfiguration. |
| No tenant/org boundary | Schema is user-centric; no organization/team tables found | Hard to add B2B, RBAC, billing, audit scoping later. |
| Manual route dispatcher is growing | workers/auth/src/index.js:145-210 plus delegated route modules |
As routes increase, policy consistency becomes harder. |
| No shared typed API contracts | No tsconfig, no typecheck script, no schema library |
Frontend/backend contracts rely on tests and convention. |
| Admin UI is monolithic | js/pages/admin/ai-lab.js 4613 lines |
Risky to evolve admin product safely. |
| Async model only partially applied | video remains synchronous | Expensive workflows are not uniformly job-based. |
Where current structure will break:
| Growth pressure | Failure point |
|---|---|
| More admins/support roles | Current role is effectively user or admin; no permission model for least privilege. |
| Organizations/teams | Tables and route ownership checks assume user_id; retrofitting org_id will touch most queries. |
| More AI providers/models | Admin AI lab and AI worker invocation modules are large and provider-specific logic is embedded in handlers. |
| Higher traffic/cost attacks | Rate limiting is inconsistent and some paths fail open. |
| Audit/compliance review | Dashboard-managed controls, no data retention/deletion/export proof, no restore drill evidence. |
| Team expansion | Lack of type system, linting, modular ownership and contract tests will increase review burden. |
Target design:
| Layer | Target state |
|---|---|
| Static frontend | Keep vanilla if intentional, but add safe DOM layer, route-level modules, performance budgets, and optional build step for analysis only. |
| API policy layer | Central route registry for auth level, body size, rate limit, CSRF/origin policy, response schema, audit event. |
| Domain modules | auth, accounts, orgs, media, ai-assets, admin, billing, audit, notifications, wallets. |
| Internal service auth | Signed HMAC service-to-service requests for Auth to AI. |
| Async jobs | Job table plus queues for video/music/image derivatives/email outbox/audit archive. |
| Data model | Organization/tenant tables, memberships, roles/permissions, plan/quota, audit scopes, data export/deletion jobs. |
| Observability | Structured logs plus traces, metrics, SLOs, alert definitions, correlation ids across workers and queues. |
| Infrastructure | Wrangler plus Terraform/OpenTofu or Cloudflare API validation for WAF, headers, RUM, routes, queues, buckets, D1, secrets metadata. |
| Contracts | Shared validators/schemas and contract tests for frontend/backend/admin/internal APIs. |
Suggested folder evolution:
workers/auth/src/
app/
route-registry.js
request-policy.js
config.js
domains/
auth/
accounts/
orgs/
admin/
media/
ai-assets/
audit/
billing/
notifications/
wallets/
platform/
d1/
r2/
queues/
rate-limit/
observability/
crypto/
contracts/
public-api/
admin-api/
internal-events/
Migration strategy:
- Add route policy wrappers around existing handlers without moving logic.
- Add typed/runtime schemas for new or changed endpoints first.
- Move one domain at a time behind interfaces.
- Introduce org/tenant model with dual-write/compatibility views before enforcing tenancy.
- Move long-running AI work to job model before adding more providers.
Major issues:
| Issue | Evidence | Why it matters | Recommended implementation style |
|---|---|---|---|
| Large monolithic modules | js/pages/admin/ai-lab.js 4613 lines; js/shared/saved-assets-browser.js 1531; js/shared/wallet/wallet-controller.js 1460; workers/auth/src/lib/admin-mfa.js 961; workers/ai/src/lib/invoke-ai-video.js 984 |
Hard to review, test, and own. Changes become risky and conflicts increase. | Split by domain responsibility: state, API, rendering, validation, provider adapters, persistence. |
| Monolithic tests | tests/workers.spec.js 12497 lines; tests/auth-admin.spec.js 6004 lines |
Hard to isolate failures and parallelize ownership. | Split by domain and route group; add test fixtures/builders. |
| No static type checking | find showed no root tsconfig.json; package.json:4-20 has no typecheck |
Runtime errors and API contract drift are caught late. | Start with // @ts-check plus JSDoc in Workers, then migrate contracts/domains to TypeScript if accepted. |
| No lint/format script | package.json:4-20 |
Code style and security rules cannot be enforced automatically. | Add ESLint or Biome with targeted rules for DOM sinks, no unbounded body reads, no raw service internal routes. |
| Mixed safe/unsafe rendering patterns | Some modules escape HTML, others use raw templates | Security quality depends on reviewer memory. | Provide safe rendering primitives and ban raw innerHTML except trusted constants. |
| Manual route dispatch | workers/auth/src/index.js:145-210, workers/ai/src/index.js:23-71 |
Policy is scattered across handlers. | Centralize route metadata and middleware/policy evaluation. |
What becomes expensive later:
| Current shortcut | Future cost |
|---|---|
| User-only data model | Adding teams/orgs later requires rewriting most ownership checks and indexes. |
| Untyped frontend/backend contracts | Every endpoint change requires manual grep/test inference. |
| Raw dashboard prerequisites | Production drift investigations become manual and incident-prone. |
| Synchronous provider calls | Hard to add retries, idempotency, cost controls, and user-facing progress. |
| Area | Rating | Evidence | Assessment |
|---|---|---|---|
| Cloudflare platform usage | Good but incomplete | Workers, D1, R2, Queues, DO, Images all used | Modern platform choices; missing IaC, traces, and consistent fail-closed policies. |
| Frontend stack | Simple and maintainable at small scale | Vanilla modules, static deploy | Not inherently bad. Needs safe DOM, performance budgets, and stronger modular discipline. |
| Type safety | Weak | No tsconfig, no typecheck script |
Behind professional SaaS standard. |
| Dependency management | Mixed | Root/auth/contact locks exist; workers/ai lock missing |
AI worker is below production standard. |
| CI/CD | Medium | Release checks and tests exist; no security gates | Good release-contract idea, but missing CodeQL/SAST/audit/coverage/perf gates. |
| Testing stack | Medium/Good | Broad Playwright worker tests | Strong worker route coverage, but static suite failing and no unit/load/security/contract coverage baseline. |
| Observability | Medium/Weak | Logs enabled, traces disabled | Correlation IDs/logging exist; metrics/alerts/SLOs not repo-defined. |
| Database tooling | Medium | Explicit migrations and indexes | No migration dry-run/rollback proof, no schema diagram, no load-tested query plans. |
Clear answer:
This repo is partially modern. The Cloudflare-native architecture and release compatibility checks are forward-looking. The absence of type safety, linting, reproducible AI worker dependency state, IaC for dashboard controls, SLOs, and load/security gates is behind top-tier SaaS practice.
Parts that are state-of-the-art or close:
| Part | Why |
|---|---|
| Release compatibility contract | Repository-specific, practical, and valuable. |
| Worker route tests | 245 passing tests is substantial. |
| Cloudflare service decomposition | Auth/AI/contact separation is sound. |
| Some signed cursor pagination | Correct pattern where applied. |
| SIWE validation detail | Good security discipline. |
Parts that are amateur-level or risky:
| Part | Why |
|---|---|
workers/ai dependency state |
No lockfile and failed install/audit checks. |
| No lint/typecheck/coverage scripts | Not acceptable for a scaling engineering team. |
| Dashboard-managed production security | Cannot prove production state from repo. |
| Long synchronous video polling | Classic pre-scale implementation pattern. |
| Huge untyped UI/admin modules | Fragile under team expansion. |
SaaS maturity score: 4.5 out of 10.
Why:
| Capability | Status |
|---|---|
| User/account model | Present. |
| Sessions/password reset/email verification | Present. |
| Admin role and MFA | Present but hardening needed. |
| Private media ownership | Present. |
| Quotas | Basic member AI daily slots exist. |
| Organization/team model | Missing. |
| Tenant isolation | Missing beyond per-user ownership checks. |
| Billing/subscription | Missing. |
| Plan limits/entitlements | Missing except hardcoded AI quota. |
| Abuse prevention | Present but inconsistent. |
| Audit logs | Present for admin/user activity, but search/retention/compliance maturity is incomplete. |
| Data export/deletion | Not proven as product-grade user-facing capability. |
| Feature flags | Missing. |
| Environment separation | Some config exists; no full IaC evidence. |
| Backup/restore | Missing evidence. |
| Incident readiness | Missing SLOs, alerts, runbooks, on-call evidence. |
| Monitoring/error tracking | Logs/correlation exist, but no repo-defined alerting/tracing/metrics. |
SaaS blockers:
| Blocker | Why it blocks |
|---|---|
| No org/tenant model | Enterprise customers need teams, roles, invitations, audit scoping, ownership transfer. |
| No billing/entitlements | Cannot enforce paid plans, usage limits, or cost controls. |
| No compliance-grade data lifecycle | Users/customers will ask for export, deletion, retention, subprocessors, audit logs. |
| Incomplete ops posture | No evidence of backups, restore drills, SLOs, alerting, incident workflow. |
| Static tests failing | Release pipeline cannot be trusted until green. |
Findings:
| Finding | Evidence | Risk | Recommended action |
|---|---|---|---|
| Static deploy path fails local static tests | npm run test:static failure; CI runs same script |
Deploy blocks or flakes. | Fix failing scroll/wallet tests or isolate environment-specific cause. |
| Queue unknown messages are acked | workers/auth/src/index.js:433-448 |
Message loss on schema/config mismatch. | DLQ unknown message shapes. |
| Cron cleanup lacks backlog alerts | workers/auth/src/index.js:81-85, 300-419 |
Backlog can grow silently. | Emit queue depth/oldest age metrics and alerts. |
| Traces disabled | workers/auth/wrangler.jsonc:19-21, workers/ai/wrangler.jsonc:12-14 |
Cross-service debugging is harder. | Enable traces where cost/privacy allows; propagate correlation IDs. |
| Manual Cloudflare prerequisites | config/release-compat.json:158-244 |
Production drift. | IaC or live drift checks. |
| Release deploys static only | .github/workflows/static.yml |
Worker/static version skew possible. | Add coordinated release pipeline or enforced deploy order. |
| No disaster recovery proof | No backup/restore scripts found | Data loss or long outage risk. | D1/R2 backup and restore drill runbooks. |
| No idempotency framework for expensive operations | AI/video/provider calls are not uniformly job-idempotent | Duplicate cost under retry. | Idempotency keys and job table. |
Current state:
| Test type | Evidence | Assessment |
|---|---|---|
| Static E2E/smoke | playwright.config.js, tests/smoke.spec.js, tests/wallet-nav.spec.js |
Exists but currently failing locally. |
| Worker route tests | playwright.workers.config.js, tests/workers.spec.js |
Strong. 245 passing tests. |
| Admin/auth tests | tests/auth-admin.spec.js |
Broad but monolithic. |
| Release compatibility tests | scripts/test-release-compat.mjs, scripts/validate-release-compat.mjs |
Strong custom validation. |
| Unit tests | Not clearly separated | Most tests are broad Playwright-style integration tests. |
| Contract tests | Partial through release tests, not schema-based | Needs explicit API contract validation. |
| Security tests | Partial route tests; no SAST or negative security suite baseline | Needs dedicated abuse/security tests. |
| Load/performance tests | Not found | Missing. |
| Coverage | Not found | Missing. |
Important missing tests:
| Missing test | Why it matters | Where it should live | Suggested cases |
|---|---|---|---|
| Admin MFA throttling/lockout | Protects admin boundary | tests/auth-admin.spec.js or split tests/admin-mfa.spec.js |
Repeated invalid TOTP, recovery code failures, lockout expiry, fail-closed limiter outage. |
| AI service HMAC auth | Prevents internal endpoint exposure | tests/workers.spec.js |
Missing signature, bad signature, expired timestamp, replay, valid service call. |
| Request body size limits | Prevents memory abuse | Worker tests | Oversized JSON to contact/auth/AI, oversized multipart avatar before parse. |
| Rate limiter fail-closed policy | Consistency for expensive routes | Worker tests | D1 missing/outage on admin AI/member AI/avatar/admin action. |
| Queue schema/DLQ behavior | Prevents silent message loss | Worker queue tests | Unknown message shape, bad version, partial failure, retry exhaustion. |
| Video job lifecycle | Required after async refactor | New AI job tests | create job, poll status, provider timeout, retry, duplicate idempotency key. |
| DB pagination/search at scale | Prevents future slow admin screens | Scripted integration/perf tests | 100k audit rows, cursor correctness, search latency, count aggregates. |
| Data deletion/export | Compliance | Worker tests | User delete removes/archives PII and R2 assets, export contains expected records. |
| CSP/XSS regression | Frontend security | Static tests plus lint/Semgrep | Inject generated metadata/title and verify it renders as text. |
| Backup/restore smoke | Ops | Scripts/CI manual workflow | Restore D1 export to staging/local and verify schema/checkpoints. |
Strengths:
| Strength | Evidence |
|---|---|
| Explicit migrations | workers/auth/migrations/*.sql. |
| User/session/token indexes exist | workers/auth/migrations/0001_init.sql, 0002_add_password_reset_tokens.sql, 0004_add_email_verification.sql. |
| Some cascade cleanup exists | Later migrations add ON DELETE CASCADE for profiles/activity-related tables and wallet tables. |
| Daily AI quota uses unique slots | workers/auth/migrations/0014_add_ai_daily_quota_usage.sql and reservation logic in workers/auth/src/routes/ai/images-write.js:175-199. |
| Cursor-support indexes exist | workers/auth/migrations/0026_add_cursor_pagination_support.sql. |
Risks:
| Risk | Evidence | Recommendation |
|---|---|---|
| No org/tenant tables | No organizations, memberships, tenant_id, or plan tables found |
Add org/membership/role/plan schema before enterprise growth. |
| Some early user-owned tables lack cascade and rely on manual cleanup | ai_images and ai_folders originally reference users without cascade in 0007_add_image_studio.sql |
Decide between cascade and explicit deletion services; test all paths. |
| Activity search is not index-friendly | workers/auth/src/routes/admin.js:679-703, 770-788 |
Add searchable projection and indexes, avoid raw JSON search. |
| Table-recreate migrations for CHECK changes | 0021, 0022, 0025 |
Acceptable for D1 constraints, but needs migration rehearsals and backups. |
| D1 batch used for related security updates | Password reset/email verification use batch-style operations | Verify D1 transactional guarantees; use explicit transactions if available or single guarded statements where possible. |
| Timestamps are plain ISO strings | Repo pattern | Standardize timezone, precision, and DB defaults. |
Target data model additions:
| Table/domain | Purpose |
|---|---|
organizations |
Tenant boundary and billing owner. |
organization_memberships |
User roles within orgs. |
roles / permissions or enum policy table |
Least-privilege admin/support/product roles. |
subscriptions / plans / entitlements |
Billing and feature enforcement. |
usage_events / usage_counters |
Billable and quota usage. |
jobs |
Async AI/email/export/deletion lifecycle. |
audit_events normalized projection |
Searchable, exportable, retention-aware audit stream. |
data_exports / deletion_requests |
Compliance operations. |
Findings:
| Finding | Evidence | Risk | Recommended action |
|---|---|---|---|
| Static smoke failures in homepage scroll restore | tests/smoke.spec.js:369-414, index.html:43-44 |
UX regressions and failed CI deploy. | Fix scroll restoration logic and add stable waits/test instrumentation. |
| Wallet discovery state failure | tests/wallet-nav.spec.js:369-383, js/shared/wallet/wallet-controller.js |
Authentication UX regression. | Make discovery state deterministic until announcement timeout expires. |
Many innerHTML sinks |
rg innerHTML output across js/ |
Future XSS risk. | Safe DOM helper and lint rule. |
| Large admin AI page | js/pages/admin/ai-lab.js 4613 lines |
Hard to secure and evolve. | Split into API client, provider panels, save modal, state reducer/store, render helpers. |
| Local storage state not threat-modeled | Wallet/audio/admin AI store local state | Privacy/session confusion risk. | Define persisted keys, TTLs, clear-on-logout semantics, and tests. |
| No accessibility audit evidence | Static tests likely cover some UI, but no axe/lighthouse config found | Enterprise UX/compliance gap. | Add accessibility scans for critical flows. |
| No performance budget | No Lighthouse CI or asset budget script | Regressions hidden. | Add budgets for homepage/account/admin. |
Strengths:
| Strength | Evidence |
|---|---|
| Route-level auth helpers | requireUser, requireAdmin. |
| Same-origin mutating request guard | workers/auth/src/index.js:131-143. |
| Parameter binding for SQL queries | Admin/search code uses bound placeholders, reducing SQL injection risk. |
| Some signed pagination | Admin users and member assets. |
| Structured diagnostics | Shared observability module imported widely. |
Weaknesses:
| Weakness | Evidence | Recommendation |
|---|---|---|
| API policy is not centralized | Each route manually applies auth, rate limit, body parsing, validation | Route registry with policy metadata. |
| Response schemas are informal | No shared schema/types | Add validators and contract tests. |
| Pagination consistency gaps | Activity endpoints use raw cursors, assets endpoint uses signed cursors | Sign all cursors. |
| Versioning strategy absent | No /v1 or explicit contract version |
Add explicit API version or compatibility policy before external integrations. |
| Admin RBAC is binary | role is user or admin |
Introduce permissions for support/admin/security/billing roles. |
| Expensive provider calls not idempotent enough | Video path synchronous | Job/idempotency framework. |
Findings:
| Finding | Evidence | Risk | Recommended action |
|---|---|---|---|
| Static CI deploy does not deploy Workers | .github/workflows/static.yml deploys GitHub Pages only |
Static/backend version skew. | Use release pipeline that enforces migrations, workers, static deploy order or blocks incompatible static deploys. |
| Manual prerequisites remain | config/release-compat.json:158-244 |
Drift and human error. | IaC or live validation. |
| No security scanning in CI | .github/workflows/static.yml lacks audit/CodeQL/SAST/secret scanning |
Supply-chain/security regressions can merge. | Add security jobs. |
workers/ai no lockfile |
no package lock found | Non-reproducible deploy. | Add lockfile and npm ci validation. |
| Worker traces disabled | wrangler configs | Harder incident investigation. | Enable traces or documented alternative. |
| No health checks for all services | Auth has /api/health; AI/contact health not evident |
Monitoring blind spots. | Add health/readiness endpoints or synthetic checks. |
| Node version mismatch | CI Node 20, local Node 24 | Reproducibility risk. | Pin engines/toolchain and use same version locally/CI. |
| Rank | Severity | Category | Affected area/files | What is wrong | Why it matters | If ignored | Fix | Effort | Blocks SaaS readiness |
|---|---|---|---|---|---|---|---|---|---|
| 1 | High | Release | npm run test:static, tests/smoke.spec.js, tests/wallet-nav.spec.js |
Static smoke suite fails. | CI deploy path is not trustworthy. | Broken UX or blocked deploys. | Fix scroll restore and wallet discovery regressions. | M | Yes |
| 2 | High | Security | workers/auth/src/routes/admin-mfa.js |
Admin MFA attempts are not rate limited/locked. | Admin boundary can be brute-forced after password/session compromise. | Privilege escalation risk. | Add fail-closed DO limiter and lockout. | M | Yes |
| 3 | High | Abuse/cost | rate-limit.js, admin-ai-proxy.js, admin.js, images-write.js |
Expensive/privileged rate limits fail open. | Cost and abuse controls degrade under DB failure. | AI spend and admin endpoints exposed to abuse. | Make fail-closed DO rate limits default for sensitive paths. | M | Yes |
| 4 | High | Service security | workers/ai/src/index.js, admin-ai-proxy.js |
Internal AI endpoints lack HMAC. | Misconfiguration can expose expensive endpoints. | Direct AI abuse. | Signed service authentication. | M | Yes |
| 5 | High | Reliability | invoke-ai-video.js |
Long synchronous video polling. | Tail latency, duplicate provider cost, Worker limits. | Unstable AI/video operations. | Async job/queue model. | L | Yes |
| 6 | High | Supply chain | workers/ai/package.json |
No lockfile, npm ls fails. |
Non-reproducible deploy/audit. | Hidden dependency drift. | Add lockfile, CI npm ci for worker packages. |
S | Yes |
| 7 | Medium/High | Operations | config/release-compat.json |
Dashboard rules outside repo. | Cannot prove production security state. | Drift, missing headers/WAF. | IaC or live drift checks. | M/L | Yes |
| 8 | Medium/High | Architecture | schema/routes | No tenant/org/billing model. | Enterprise SaaS cannot be layered cleanly. | Costly rewrite later. | Add org/membership/plan/entitlement model. | XL | Yes |
| 9 | Medium/High | Maintainability | large JS/test files | Monoliths and no typecheck. | Team velocity and safety degrade. | Regressions increase. | Split modules, add type/lint. | L | Partially |
| 10 | Medium | Database | admin.js activity queries |
Broad scans and raw cursors. | Admin pages slow as logs grow. | D1 pressure and support pain. | Indexed projections, signed cursors, aggregates. | M | Partially |
| 11 | Medium | Security | request parsing | Body limits after parsing or not visible. | Memory/CPU abuse. | Worker exhaustion. | Byte-limited parsers. | S/M | Partially |
| 12 | Medium | Ops | queue handler | Unknown messages acked. | Silent data loss. | Lost jobs/audit. | DLQ/versioned messages. | M | Partially |
| 13 | Medium | Observability | wrangler traces disabled, no alert definitions | Logs exist but no SLOs/alerts. | Incidents discovered late. | Longer outages. | SLO/metrics/alerts/runbooks. | M/L | Yes |
| 14 | Medium | Frontend security | many innerHTML sinks |
No enforced safe rendering policy. | Future XSS risk. | Account/admin compromise via XSS. | Safe DOM layer and lint rule. | M/L | Partially |
| 15 | Medium | Data lifecycle | no export/delete proof | Compliance gap. | Enterprise blockers. | Legal/support risk. | Export/delete jobs and tests. | L | Yes |
| 16 | Medium | Email reliability | direct Resend calls | No durable outbox/retry. | Auth emails can silently fail. | Support burden/login failure. | Email outbox/queue/webhook status. | M | Partially |
| 17 | Medium | Performance | no load/perf budgets | No capacity evidence. | Unknown scaling limits. | Surprises under traffic. | k6/Lighthouse budgets. | M | Partially |
| 18 | Medium | DX | no lint/type/format/coverage | Weak quality gates. | Review burden. | Slow team growth. | Add scripts and CI. | M | Partially |
| 19 | Low/Medium | Password security | PBKDF2 100k | Acceptable but not elite. | Lower breach resistance. | Faster offline cracking if DB leaks. | Improve hashing/passkeys/breach checks. | M | No |
| 20 | Low/Medium | Runtime reproducibility | CI Node 20, local Node 24 | Tooling drift. | Environment-specific bugs. | Flaky builds/tests. | Pin Node/npm versions. | S | No |
| Dimension | Score | Evidence | What raises it to 9+ | Current blocker |
|---|---|---|---|---|
| Overall code quality | 6.2 | Working product, broad tests, but large untyped modules | Modular typed domains, lint, coverage, contract tests | Monoliths, no type/lint gates |
| Security | 6.5 | Good auth/session/MFA basics, SIWE, origin checks | MFA throttling, service HMAC, body limits, IaC security, SAST | Inconsistent fail-closed controls and internal service auth |
| Architecture | 6.0 | Clean Cloudflare service split | Route policy layer, domain boundaries, org/tenant model | User-centric architecture and scattered policy |
| Performance | 5.5 | Static site and Cloudflare edge are efficient foundations | Load tests, async AI, query indexes, perf budgets | Synchronous video, scan-prone admin queries |
| Scalability | 5.2 | Queues/DOs exist | Job model, org/tenant scaling, global rate limits, capacity tests | D1 hot counters and missing tenant architecture |
| Maintainability | 5.4 | Clear file structure and tests | Smaller modules, typed contracts, owners, lint | Large files and informal contracts |
| Testing | 7.0 | 245 worker tests and many static tests | Green full suite, unit/contract/security/load/coverage gates | Static suite failing, no coverage/load/security gates |
| SaaS readiness | 4.5 | Accounts/admin/private media exist | Org/billing/compliance/ops primitives | Missing enterprise platform features |
| Operational readiness | 4.8 | Logs, release plan, queues | SLOs, alerts, restore drills, IaC, incident runbooks | Dashboard drift and no backup/alert evidence |
| Developer experience | 5.8 | Simple scripts and tests | Unified npm ci for all workspaces, lint/type/format, docs |
Worker package inconsistency and no type/lint |
| Technology modernity | 5.6 | Cloudflare-native stack is modern | Typed JS/TS, IaC, security tooling, observability | Tooling gaps and manual dashboard controls |
| Future-proofing | 4.8 | Some release discipline | Tenant architecture, async jobs, contracts, governance | Current model will be expensive to evolve for enterprise |
Target security model:
| Area | Target |
|---|---|
| Authentication | Sessions with purpose-specific secrets, rotation support, admin WebAuthn/passkeys, strict secure cookies. |
| Authorization | Central policy engine with roles/permissions scoped to org/team/admin/support contexts. |
| Service-to-service | HMAC-signed Auth to AI calls with timestamp/replay protection. |
| Rate limiting | Durable Object fail-closed by default for sensitive/expensive routes. |
| Input validation | Per-route body-size limits and schema validation before business logic. |
| Secrets | Purpose-specific key material with key ids and rotation runbooks. |
| Audit | Immutable append-only audit events with searchable redacted projections. |
Target performance strategy:
| Area | Target |
|---|---|
| AI generation | Asynchronous jobs for video/music/large images, idempotency keys, provider status tracking. |
| DB queries | Indexed pagination, precomputed aggregates, no raw JSON wildcard search on hot paths. |
| Static frontend | Performance budgets and asset-size checks in CI. |
| Media | Store binary assets in R2/Images and return references rather than base64 payloads. |
| Rate limiting | DO counters for hot paths; D1 for durable snapshots only. |
Target testing strategy:
| Layer | Target |
|---|---|
| Unit | Domain logic, validators, crypto helpers, pagination, rate policy. |
| Integration | Worker route tests by domain. |
| Contract | Shared request/response schemas for frontend/backend/internal APIs. |
| E2E | Static flows, wallet, auth, admin, media, AI happy paths. |
| Security | Abuse, CSRF/origin, auth bypass, BOLA, size limits, MFA lockout. |
| Load | k6/Artillery for auth, admin activity, AI jobs, media reads. |
| Ops | Backup restore, queue retry/DLQ, migration rehearsal. |
Target CI/CD:
| Gate | Target |
|---|---|
| Install | npm ci root and every worker package with lockfiles. |
| Static checks | lint, typecheck/checkJs, format, dependency audit, secret scan. |
| Tests | unit, worker, static, contract, release compatibility. |
| Security | CodeQL/Semgrep, dependency review, license/SBOM, audit. |
| Release | Plan, apply migrations, deploy workers in order, deploy static, run live canaries. |
| Drift | Validate Cloudflare route/binding/WAF/header/RUM state. |
Objectives:
Fix releasability, close immediate admin/AI abuse gaps, restore supply-chain reproducibility.
Tasks:
| Order | Task | Files/areas | Impact | Effort |
|---|---|---|---|---|
| 1 | Fix failing static smoke tests | index.html, js/pages/index/category-carousel.js, js/shared/wallet/ |
Restores deploy confidence | M |
| 2 | Add MFA rate limiting and lockout | workers/auth/src/routes/admin-mfa.js, workers/auth/src/lib/admin-mfa.js, tests |
Reduces admin takeover risk | M |
| 3 | Make sensitive rate limits fail closed | rate-limit.js, admin, avatar, AI generation/proxy routes |
Reduces abuse/cost exposure | M |
| 4 | Add Auth-to-AI HMAC service auth | admin-ai-proxy.js, workers/ai/src/index.js, tests |
Protects internal AI endpoints | M |
| 5 | Add workers/ai/package-lock.json and CI install/audit |
workers/ai, .github/workflows/static.yml |
Reproducible AI worker builds | S |
| 6 | Add config validation for critical secrets/bindings | all Workers | Fail-closed misconfiguration | S/M |
Expected risk reduction:
High. These items address release failure, admin boundary, AI spend exposure, and supply-chain reproducibility.
Objectives:
Harden auth/input validation, add quality gates, make behavior observable and testable.
Tasks:
| Order | Task | Files/areas | Impact | Effort |
|---|---|---|---|---|
| 1 | Add request body size limited parsers | workers/auth/src/lib/request.js, contact/avatar/AI routes |
Prevents memory abuse | S/M |
| 2 | Split security secrets by purpose | config, crypto helpers, migrations if needed | Reduces blast radius | M/L |
| 3 | Add lint/typecheck/checkJs and safe DOM rules | root tooling, js/, workers/ |
Improves maintainability/security | M |
| 4 | Add route policy registry | workers/auth/src/app/ |
Consistent auth/rate/body policies | M/L |
| 5 | Add CI security gates | .github/workflows/static.yml |
Prevents supply-chain/security drift | M |
| 6 | Add alert/runbook baseline | docs, scripts, wrangler observability | Incident readiness | M |
Objectives:
Move expensive work async, improve database/query patterns, introduce domain boundaries.
Tasks:
| Order | Task | Files/areas | Impact | Effort |
|---|---|---|---|---|
| 1 | Convert video generation to job/queue model | workers/ai, workers/auth, migrations, admin UI |
Reliability and cost control | L |
| 2 | Add indexed audit/search projection and signed activity cursors | workers/auth/migrations, routes/admin.js |
Scalable admin pages | M |
| 3 | Deprecate or paginate /api/ai/images |
assets-read.js, frontend asset browser |
Lower payloads | M |
| 4 | Split large admin/wallet/asset modules | js/pages/admin/ai-lab.js, shared modules |
Team scalability | L |
| 5 | Add load/perf tests | scripts/, CI optional workflow |
Capacity visibility | M |
Objectives:
Add SaaS platform primitives and compliance-grade operations.
Tasks:
| Order | Task | Files/areas | Impact | Effort |
|---|---|---|---|---|
| 1 | Add organization/team/membership model | migrations, auth/session, routes, UI | Tenant foundation | XL |
| 2 | Add RBAC/permissions | domain policy, admin UI | Least privilege | L |
| 3 | Add billing/plan/entitlement/usage model | migrations, AI quotas, admin/account UI | Monetization and cost controls | XL |
| 4 | Add data export/deletion jobs | migrations, queues, R2/D1 services | Compliance readiness | L |
| 5 | Add audit archive/search improvements | audit domain, R2 archive, admin tools | Enterprise support | L |
| 6 | Add feature flags | config/domain | Safer rollout | M |
Objectives:
Automate quality governance and operational excellence.
Tasks:
| Order | Task | Files/areas | Impact | Effort |
|---|---|---|---|---|
| 1 | Full IaC/drift management | Cloudflare resources, repo CI | Production reproducibility | L/XL |
| 2 | SLOs/error budgets and alerting | dashboards/runbooks/CI docs | Incident maturity | L |
| 3 | Continuous security program | CodeQL/Semgrep/dependency review/SBOM/license | Audit readiness | M/L |
| 4 | Restore drills and chaos tests | scripts/docs/staging | Disaster recovery confidence | M/L |
| 5 | Architecture governance | ADRs, ownership, module boundaries | Long-term maintainability | M |
| 6 | Advanced test matrix | unit/contract/load/security/visual/a11y | Regression prevention | L |
| Evidence | Meaning |
|---|---|
package.json:4-20 |
Scripts include tests/release/build but no lint/typecheck/format/coverage. |
.github/workflows/static.yml:28-66 |
Release compatibility and worker validation jobs. |
.github/workflows/static.yml:190-200 |
Static tests run before static build/deploy. |
workers/auth/wrangler.jsonc:14-21 |
Logs enabled, traces disabled. |
workers/auth/wrangler.jsonc:23-47 |
Queue producers/consumers configured. |
workers/auth/wrangler.jsonc:61-65 |
Auth worker binds to AI worker as AI_LAB. |
workers/ai/wrangler.jsonc:5-6 |
AI worker public dev/preview exposure disabled. |
config/release-compat.json:158-244 |
Manual prerequisites and dashboard-managed controls. |
workers/auth/src/lib/session.js:52,99 |
Session token hash uses SESSION_SECRET. |
workers/auth/src/lib/session.js:207-253 |
Admin secure session and MFA enforcement. |
workers/auth/src/routes/admin-mfa.js:52-240 |
Admin MFA handlers lack explicit route-level limiter. |
workers/auth/src/lib/admin-mfa.js:20-21 |
MFA proof TTL is 12 hours. |
workers/auth/src/lib/admin-mfa.js:140-180 |
MFA secret encryption derives key from SESSION_SECRET. |
workers/auth/src/lib/rate-limit.js:300-360 |
Shared limiter falls back to memory unless fail-closed. |
workers/auth/src/lib/admin-ai-proxy.js:37-41 |
Admin AI limiter uses default behavior. |
workers/ai/src/index.js:15-72 |
AI internal routes have no HMAC/auth check. |
workers/ai/src/lib/invoke-ai-video.js:327-563 |
Synchronous Vidu provider create and poll loop. |
workers/auth/src/routes/admin.js:679-703 |
Admin activity wildcard search/counts. |
workers/auth/src/routes/admin.js:746-788 |
User activity wildcard search/raw cursor. |
workers/auth/src/routes/avatar.js:298-323 |
request.formData() before file-size rejection. |
workers/contact/src/index.js:133-155 |
request.json() before field size validation. |
workers/auth/src/index.js:433-448 |
Unknown queue batches are acked. |
tests/smoke.spec.js:369-414 |
Static scroll restoration tests that failed locally. |
tests/wallet-nav.spec.js:369-383 |
Wallet discovery test that failed locally. |
| File | Lines |
|---|---|
js/pages/admin/ai-lab.js |
4613 |
js/shared/saved-assets-browser.js |
1531 |
js/shared/wallet/wallet-controller.js |
1460 |
workers/auth/src/lib/admin-mfa.js |
961 |
workers/auth/src/routes/ai/images-write.js |
761 |
workers/ai/src/lib/invoke-ai-video.js |
984 |
tests/workers.spec.js |
12497 |
tests/auth-admin.spec.js |
6004 |
No application code, tests, layouts, styles, configs, migrations, package files, or assets were modified during this audit. Only audit documentation files were created.