| name | Lifetide local integration and auth-shell testing |
| description | How to set up the local Lifetide Next.js app against the Docker Postgres
container and run the lint/type/build/test suite without a real Supabase
auth backend.
|
Devin Secrets Needed
- None for the local-only path documented here. The app needs these env values
(they are not sensitive for local testing):
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/lifetide
DIRECT_URL=postgresql://postgres:postgres@localhost:5432/lifetide
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=dummy-anon-key
SUPABASE_SERVICE_ROLE_KEY=dummy-service-role
Required local services
- Docker Compose:
docker compose up -d from the repo root starts
lifetide-postgres on localhost:5432 with database lifetide.
One-time environment
- Copy
.env.example to .env (or create .env with the values above).
npm install triggers prisma generate.
npx prisma migrate deploy applies migrations.
npx tsx prisma/seed.ts seeds the default privacy policy version.
Running the command suite
Vitest/Prisma will not see .env unless it is sourced with set -a:
set -a && source .env && set +a
npm run lint
npm run typecheck
npm run build
npm run test
npm run test:integration
npm run test:e2e
npx prisma migrate status
Auth limits
- A real Supabase auth backend is not started by the compose file. The dummy
NEXT_PUBLIC_SUPABASE_* values are enough for the app to boot and for
middleware.ts/requireUser() to redirect anonymous users, but you cannot
complete the OTP email login flow or reach /onboarding or /settings/privacy
through the browser UI.
- To verify onboarding/consent/RLS logic, run
test:integration or call the
extracted services (completeOnboardingForUser, setConsent, getConsentStatus)
directly against the Postgres container.
Browser UI checks
- Start the dev server:
npm run dev.
- Visit
http://localhost:3000/dashboard and http://localhost:3000/onboarding
anonymously; both should redirect to http://localhost:3000/login.
/login should render an email input, an invite-code input, and a
发送登录链接 button.
- Submitting an invalid invite code (e.g.
ABC) shows a red
登录失败,请检查邮箱和邀请码。 message.
S02 interview E2E
npm run db:reset then npx tsx prisma/seed.ts resets the database and seeds the
default privacy policy.
- The interview fixture seam is at
/interview/fixture and only works when the
server has LIFETIDE_E2E_FIXTURE=true and LIFETIDE_E2E_SECRET=test-secret.
- Playwright config already sets the fixture env and starts
npm run build && npm run start; run with
NODE_ENV=production npx playwright test tests/e2e/interview.spec.ts --headed
for a recorded visible-browser run.
S03 evidence/hypothesis/amendment tooling
- Migrations
20260810093440_add_model_config_prompt_version_call_log,
20260810102143_add_safety_check_log, and
20260810140732_add_evidence_hypothesis_amendment_conflict create the new
EvidenceItem, PersonaHypothesis, PersonaAmendment, and ConflictRecord
tables.
- Tests for this slice run with
LIFETIDE_AI_PROVIDER=fixture (the integration
tests set this in beforeEach).
- Key integration suites:
npx vitest run -c vitest.integration.config.ts tests/integration/persona-tools.test.ts
npx vitest run -c vitest.integration.config.ts tests/integration/evidence-extractor.test.ts
- To run a manual fixture-provider chain against the DB, use a vitest spec under
tests/integration (not tsx directly), because the source files import
server-only and the vitest integration config sets the react-server
resolution condition.
S04 async snapshot/reconcile flow
S04-T02 attachment upload backend
- New migrations create
source_documents and document_chunks (see 20260811113240_add_source_documents).
uploadDocument -> enqueueParseDocument -> processParseDocument -> deleteDocument is the main flow.
- Text/Markdown files are chunked by paragraph; PDF/DOCX/image parsers return empty text in the MVP.
- With dummy Supabase keys,
getStorageProvider() falls back to a local filesystem provider under the OS temp directory.
tests/integration/documents.test.ts verifies upload, background-job parsing, chunking, user isolation, signed URL ownership, idempotent re-parse, and soft delete.
- To exercise the loop manually, write a temporary integration spec under
tests/integration (not tsx directly) because the source files import server-only.
uploadDocumentAction / getDocumentStatusAction / deleteDocumentAction require requireUser(). In local dummy-auth mode they can only be invoked through a real Supabase session or a dedicated E2E fixture route; the integration-level service functions cover the backend behavior.
- Key commands:
npx vitest run -c vitest.integration.config.ts tests/integration/documents.test.ts
S06-T04 real-LLM / QuestionCard testing
- The branch
devin/S06-T04-question-card extends QuestionCard to support
single_choice, multi_choice, scale, short_answer, textarea, date, and
file_select.
- For fixture E2E use
LIFETIDE_E2E_FIXTURE=true and LIFETIDE_E2E_SECRET=test-secret;
Playwright sets the cookies automatically. Add LIFETIDE_AI_PROVIDER=fixture to
the dev server for a pure fixture run, but note that the default fixture provider
does not register fixtures unless the test or integration runner calls
setFixture or LIFETIDE_E2E_FIXTURE triggers ensureDefaultFixtures.
- To test with a real LLM, do not set
LIFETIDE_AI_PROVIDER. Make sure the
DB contains a default ModelConfig (e.g. Deepseek openai_compatible) and the
PromptVersion rows exist (npx tsx prisma/seed-prompts.ts seeds 16 active
versions after npm run db:reset).
- If
DEEPSEEK_API_KEY is invalid you will get HTTP 401 from
https://api.deepseek.com/v1/chat/completions. The openai_compatible branch
in src/lib/ai/provider-factory.ts must use openai.chat(model_id) rather than
the OpenAI Responses API; the S06-T04 branch already contains this fix.
- Run the backend pipeline directly in a temporary
tests/integration/*.test.ts
file so server-only resolution works (tsx alone fails without the
react-server condition that vitest.integration.config.ts sets).
- Key commands:
npx vitest run -c vitest.integration.config.ts tests/integration
NODE_ENV=production npx playwright test tests/e2e/interview.spec.ts --headed
NODE_ENV=production npx playwright test tests/e2e/question-card-interactions.spec.ts
NODE_ENV=production npx playwright test tests/e2e/interview.spec.ts --headed
S06-T09 boat movement per question
- Branch
devin/S06-T09-boat-movement changes projectSeaChartState to derive
boat_position from wave.exploration_question_count + deepening_question_count within the current phase (dawn 10%, day 35%, dusk
60%, night 85%, return 95%). Standard waves move ~6.25% screen width per
answer.
sea-scene.ts tweens the boat to the new boat_target, spawns white wake
ellipses at 25% tween progress, and disables particles under reduced motion
or low FPS.
InterviewContainer.tsx progress pill uses state.boat_position.x.
/interview/fixture does not exercise multi-wave phase transitions in
E2E because the fixture evidence-extraction dimensions do not match the
wave-planner target paths, so shouldEndExploration is not satisfied. Use a
temporary tests/integration/sea-chart-projector-phases.test.ts to verify
phase boundary math directly.
- Key E2E checks:
- Progress percentage in the header increases with each answer.
- Boat stays visibly on the water band in SeaMap screenshots.
- Reduced motion / 375×667 viewport keeps question text ≥14 px and still
advances the progress pill.