Files
jakeandClaude Opus 5.5 8df985ce38 feat: run the full app locally without OAuth apps (#532)
* feat: run the full app locally without OAuth apps or third-party keys

- compose.yml: Postgres plus an Upstash-compatible Redis REST shim; the
  top of apps/web/.env.example now works as-is against it
- Dev-only email/password sign-in (Better Auth, NODE_ENV=development) with
  a small form on the login page; OAuth is no longer required in dev
- `pnpm db:seed`: free and pro dev users with tracked domains in each
  verification state and a few notifications; refuses non-local databases
  unless --force
- Email: without RESEND_API_KEY in dev, render to apps/web/public/_dev-emails/
  and log a link instead of throwing; contact sync no-ops
- Blob: without credentials in dev, store files in apps/web/public/_dev-blob/
  via the files-sdk fs adapter
- drizzle.config also reads apps/web/.env.local, so `pnpm db:migrate` works
  with the env file the README tells you to create
- Logger treats an empty LOG_LEVEL (as copied from .env.example) as unset
  instead of crashing
- README: local setup walkthrough and an optional-services table

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LBbE72EGVdtZGj8LSCuZF

* chore: hash seed passwords with @better-auth/utils instead of better-auth

The seed script only needs `hashPassword`, which `better-auth/crypto`
re-exports from `@better-auth/utils/password`. Depend on that small package
directly so `@domainstack/db` no longer pulls in all of better-auth.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LBbE72EGVdtZGj8LSCuZF

* fix: address review findings on local dev setup

- compose: bind Postgres and the Redis REST shim to 127.0.0.1, pin
  serverless-redis-http to 0.0.10, and wait for a healthy Redis
- `pnpm db:seed --force` now reaches the script (root task forwards args)
- Seed output never prints a real CRON_SECRET; README notes substituting it
- Dev email outbox: unique UUID filenames, written to apps/web/.dev-emails/
  (outside public/, so the dev server never serves confirmation links),
  inline logo rewritten to the hosted image, and write failures returned in
  Resend's `{ data: null, error }` shape instead of thrown
- Disable email/password sign-up; dev accounts come from the seed
- Dev sign-in form recovers when `signIn.email` throws
- Blob dev-fallback test now uploads and checks the file on disk

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LBbE72EGVdtZGj8LSCuZF

* chore: restore generated next-env.d.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LBbE72EGVdtZGj8LSCuZF

* fix: correct `--force` passthrough for `pnpm db:seed`

- Remove the trailing `--` from the root `db:seed` turbo task; Turbo forwards extra args to the underlying script automatically, so the double-dash was being consumed rather than passed through
- Update the README command example and seed script header comment to use `pnpm db:seed -- --force` (the correct pnpm arg-separator syntax)
- Reformat the optional-services table with aligned column padding

* fix: keep text-only emails in the dev outbox

Render `react`, then `html`, then escaped `text` (Resend's accepted bodies)
instead of writing an empty file for text-only payloads. An email with no
body now fails through the existing Resend-style error path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LBbE72EGVdtZGj8LSCuZF

* test: mock the dev sign-in form in the login content test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: drop the local email outbox

Without RESEND_API_KEY, sends fail as they did before; writing emails to disk
in development was more machinery than the local setup needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-01 18:20:06 -04:00

48 lines
1.1 KiB
YAML

# Local services for `pnpm dev`. See README "Development".
#
# docker compose up -d # start
# docker compose down -v # stop and wipe data
name: domainstack
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_USER: domainstack
POSTGRES_PASSWORD: domainstack
POSTGRES_DB: domainstack
ports:
# Loopback only: the dev credentials below are checked in
- "127.0.0.1:5432:5432"
volumes:
- postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U domainstack"]
interval: 2s
timeout: 5s
retries: 15
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 2s
timeout: 5s
retries: 15
# Upstash-compatible REST API in front of Redis, for @upstash/redis
redis-http:
image: hiett/serverless-redis-http:0.0.10
environment:
SRH_MODE: env
SRH_TOKEN: dev-token
SRH_CONNECTION_STRING: redis://redis:6379
ports:
- "127.0.0.1:8079:80"
depends_on:
redis:
condition: service_healthy
volumes:
postgres: