Skip to content
This repository was archived by the owner on Sep 25, 2026. It is now read-only.

Phase 1: Foundation — Next.js + auth + multi-tenant data model + Redis/BullMQ + /health + tests + CI - #5

Open
tommyqhoang wants to merge 28 commits into
mainfrom
phase-1-foundation
Open

tommyqhoang wants to merge 28 commits into
mainfrom
phase-1-foundation

Conversation

@tommyqhoang

Copy link
Copy Markdown
Contributor

Phase 1: Foundation

Lays the groundwork for CustomerETA per the roadmap in readme.md:

  • Next.js + auth — app scaffold, registration/login/logout, password reset, custom session creation
  • Multi-tenant data model — Prisma schema with tenant scoping
  • Redis + BullMQ — queue infrastructure with globalThis singletons (Prisma, Redis, Resend)
  • /health endpoint
  • Tests — unit/component suite (42 tests green)
  • CI — lint, typecheck, and tests run against Postgres + Redis services
  • railway.toml config; todo.md Foundation tasks marked done

Commits (26)

See the commit list below — all Phase 1 Foundation work, TDD-style with self-review reports per task.

🤖 Generated with Claude Code

tommyqhoang and others added 28 commits July 28, 2026 21:59
…ables)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nd error

If sendVerificationEmail() throws after the User/Business/Membership
transaction has already committed, the account was still created. Treat
that as a successful registration (return {}) instead of a generic
account-creation failure, since retrying would only hit the
duplicate-email branch and strand the user with no way to get a fresh
verification email. Fail loud via captureServerError + logger.error so
the failed send is still visible, just not surfaced as user-facing
account-creation failure.
…t-password page

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…s/BullMQ + /health + tests + CI

Merges Tasks 1-18 of the Phase 1 implementation plan
(docs/superpowers/plans/2026-07-28-phase1-foundation.md).
Task 19 (Railway staging deploy) and Task 20 (mark todo.md) follow.
Verified: typecheck clean, lint 0 errors, 42 unit/component tests pass, prod build green.
…nt/gitignore

Local verification of the merged branch surfaced that `eslint .` walked into
`.claude/worktrees/phase-1-foundation/.next/**` (leftover minified build
output from running `pnpm build` inside the worktree), producing ~1100 spurious
errors. The root eslint ignore was `.next/**` (root-relative), so it did not
catch the nested worktree's build output. CI was unaffected (fresh checkout
has no .claude/worktrees), but the trap is latent for anyone using local
worktrees.

- .gitignore: add .claude/worktrees/ (local worktree state, never committed)
- eslint.config.mjs: use **/.next/** (any depth) and ignore .claude/**
Tasks 1-18 verified green on local main (typecheck clean, lint 0 errors,
42 unit/component tests pass, production build succeeds). Phase 1 boxes
checked off in todo.md except the two Railway live-deploy boxes, which
remain pending: a direct push to main is blocked by branch protection
(enforce_admins=true + required PR + ci status check), so the code must
reach origin/main via a PR before Railway can deploy from main.

railway.toml is committed so the deploy config is ready the moment the
branch lands.
The queue smoke test used a fixed jobId plus job.waitUntilFinished(QueueEvents).
Locally a stale completed job masked the bug: add() returned the old job and
waitUntilFinished resolved instantly without the worker ever running. On CI's
fresh Redis service, add() enqueued a real job, but if the worker finished before
the QueueEvents stream subscribed, the completion event was missed and the
promise hung until the 15s timeout.

Signal completion from inside the processor (race-free, no QueueEvents), await the
worker 'ready' event before enqueueing, and use a unique jobId so a stale job can
never mask the real path. Validated locally against a fresh redis:7 container.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant