Devine is a Bun-run Next.js 16 App Router app that turns daily.dev reading activity into a rubber duck companion, quests, power-ups, and privacy-safe share snapshots.
If context is compacted, re-read this file before touching code. Run the verification gate before marking any implementation task complete.
| Concern | Source |
|---|---|
| Product, users, acceptance criteria | docs/business/ |
| Architecture, stack, modules, data, security | docs/technical-specs/ |
| Coding rules | docs/CODING_STANDARD.md |
| Work model and card ownership | docs/TASK_BREAKDOWN.md |
| Deployment and operations | docs/DEPLOYMENT_PLAN.md |
| Domain language | docs/GLOSSARY.md |
| API contracts | docs/api-specs/ |
This manual restates load-bearing rules. If it conflicts with the source docs, fix this file.
| Layer | Technology |
|---|---|
| Runtime | Bun 1.3.1, Node.js 24 APIs where Vercel requires them |
| Framework | Next.js 16.0.4 App Router, React 19.2.0 |
| Language | TypeScript 6.0.3 strict mode |
| Styling | Tailwind CSS 4.1.17 |
| Animation | motion 12.39.0 |
| Validation | Zod 4.4.3 |
| Database | Neon Postgres 18 through Drizzle ORM 0.45.2 |
| Tests | Bun test, Vitest-compatible unit style, Playwright 1.60.0 |
| Quality | oxlint 1.65.0, oxfmt 0.51.0, tsc --noEmit |
| Hosting | Vercel with Neon Postgres |
app/ Next.js routes, layouts, route handlers, server actions
app/(marketing)/ Landing page at /
app/auth/ Register, login, logout, account auth actions
app/dashboard/ Auth-required dashboard and dashboard mutations
app/settings/ Token connection, demo mode, reset demo state
app/share/[snapshotId]/ Public share snapshot route
app/api/ REST contracts for health, reset, daily.dev, share snapshots
features/<slice>/ Vertical slices with domain, application, infrastructure, presentation, tests
features/activity/ Activity normalization and recording
features/auth/ Registration, login, sessions, roles, logout
features/dailydev/ daily.dev API client and response mapping
features/demo/ Demo personas and simulation actions
features/operations/ Health checks and reset orchestration
features/powerups/ Inventory, active effects, power-up use
features/quests/ Quest generation, progress, rewards
features/scoring/ Energy, health, seniority, tag normalization
features/share/ Share snapshot creation and public projection
features/speech/ Deterministic speech templates
features/users/ User domain boundary
components/ Shared route components and reusable UI primitives
components/ui/ Presentation-only primitives
lib/db/ Drizzle client, schema, migrations, seeds, repositories
lib/security/ Cross-cutting security primitives
tests/e2e/ Playwright golden paths
docs/ Business, technical, API, workflow docs
scripts/ Repository helper scripts
| Module | Owns | Public contract |
|---|---|---|
| Dashboard UI | Routes and typed view model composition | app/(marketing), app/dashboard, app/settings, components/* |
| Auth | Users, sessions, roles, logout | registerUser, loginUser, logoutUser, requireUser, requireSuperadmin |
| daily.dev integration | API calls and DTO mapping | validateDailyDevToken, fetchDailyDevProfile, fetchDailyDevFeed, fetchDailyDevBookmarks |
| Token security | Encrypted PAT lifecycle | encryptToken, decryptToken, deleteDailyDevConnection |
| Activity ingestion | Normalized events | normalizeActivityEvent, recordActivity |
| Scoring | Pure energy, health, seniority, tags | calculateDailyEnergy, calculateHealth, processMissedDays, calculateSeniorityScore, normalizeTag |
| Quests | Quest generation, progress, rewards | generateQuests, calculateQuestProgress, claimQuestReward |
| Power-ups | Inventory and effects | addPowerUp, usePowerUp, consumeMatchingEffect |
| Demo mode | Persona state and simulation actions | getDemoPersona, applyDemoAction, resetDemoState |
| Persistence | All tables and direct database access | lib/db/schema.ts, client.ts, repositories/*, migrate.ts, seed.ts |
| Share snapshots | Static public projections | createShareSnapshot, getPublicShareSnapshot, softDeleteShareSnapshot |
| Operations | Health and reset state | GET /api/health, non-production POST /api/admin/reset-state |
Hard domain states:
- Roles are
userandsuperadmin. - User modes are
demoandconnected. - Activity types are
read,upvote,bookmark,comment, andshare. - Activity sources are
dailydev_api,in_app,manual, anddemo. - Quest statuses are
active,completed, andclaimed. - Health states are
thriving,stable,tired,sick,critical, andhibernating. - Seniority levels are
ignorant_copaster,code_monkey,grounded_scholar, andtech_philosopher. - Demo personas are
copaster,code_monkey,scholar, andphilosopher. - Public share IDs are URL-safe
public_idvalues such asdevine_abc123, never internal UUIDs.
- Cards come from
docs/TASK_BREAKDOWN.mdand cite acceptance criteria underdocs/business/. - TL cards establish API specs, scaffold, guardrails, seeds, and release checks.
- Backend cards implement persistence, domain engines, server actions, and route handlers against approved contracts.
- Frontend cards own routes, components, loading states, error states, visual polish, and manual UI verification.
- Wiring cards prove frontend and backend behavior end-to-end in the running app.
- US-21 recovery implementation is optional follow-up, but contracts remain documented.
- Put new product behavior in
features/<slice>/with domain, application, infrastructure, presentation, and tests layers. - Keep domain rules in
features/<slice>/domain/and independent of React, Next page modules, Drizzle, cookies, environment variables, and network clients. - Keep route handlers and server actions thin: validate input, authorize caller, call public feature APIs, map results.
- Put all direct database access, Drizzle clients, schema, migrations, seeds, and repositories under
lib/db/. - Use repositories, ports, or infrastructure adapters outside
lib/db/; do not importdbelsewhere. - Import migrated feature modules through public entry points such as
@/features/authand@/features/share, not private implementation files. - Keep slice tests under
features/<slice>/tests/; keeptests/e2e/for cross-slice browser flows. - Keep
components/ui/presentation-only. They must not fetch data or mutate state. - Keep application source files under 300 lines. Split proactively at 250 lines.
- Split large files into a sibling feature folder or focused module. Keep entry points thin and avoid generic
utilsdumps. - Put every atomic multi-step write in one transaction.
- Do not add queues, caches, Redis, background workers, tRPC, BetterAuth, image generation services, or AI chat for MVP code.
| Do | Do not |
|---|---|
| Use Bun for installs and scripts | Do not introduce npm, pnpm, yarn, or another lockfile |
| Use exact pinned dependency versions | Do not add caret or tilde dependency ranges |
| Use Server Actions plus REST route handlers | Do not add tRPC for MVP contracts |
| Use Zod at system boundaries | Do not over-validate trusted internal calls |
| Use Drizzle migrations through the ledger | Do not apply raw SQL files manually |
Use bun run format:write for formatting |
Do not hand-format around oxfmt |
| Use demo mode for reliable fallback | Do not make daily.dev availability required for demos |
| Use Vercel dashboard for production deploy visibility | Do not use containers or custom server deployment |
Before any implementation task is complete, run this ordered gate:
bun run type-check
bun run lint
bun run format
bun run test
bun run test:e2e
bun run buildbun run complete-check runs the same gate in order. For UI or frontend work, also start the app with bun run dev and manually verify the golden path, loading, empty, and error states in a browser.
- Search before writing new code.
- Read the closest existing route, module, repository, component, and test.
- Reuse existing types, schemas, repositories, services, and UI primitives.
- Verify acceptance criteria and source docs before changing contracts.
- Update source docs when route contracts, folder responsibilities, security rules, environment variables, or verification commands change.
| Element | Pattern | Example |
|---|---|---|
| Folders | lowercase kebab-case | dailydev-integration |
| Next framework files | fixed lowercase names | page.tsx, layout.tsx, actions.ts, route.ts |
| React components | PascalCase | DuckAvatar |
| Type aliases | PascalCase | HealthResponse |
| Functions and variables | camelCase | validateDailyDevToken |
| Drizzle table exports | camelCase | dailyDevConnections |
| Database tables and columns | snake_case | daily_dev_profile_id |
| Static quest keys | snake_case | feed_the_duck |
| Public share IDs | URL-safe string | devine_abc123 |
- Keep strict TypeScript clean.
- Do not use
any, uncheckedas, or non-null assertions. - Give exported non-component functions explicit return types.
- Use literal unions and discriminated unions for finite domain states and expected outcomes.
- Derive request and response types from Zod schemas with
z.inferwhere possible.
- Return discriminated result unions for expected validation, auth, user-facing, and integration failures.
- Throw only for impossible invariants and missing required server configuration.
- Map service results to HTTP status codes or form state at boundaries.
- Do not leak raw exception messages, secrets, or environment values to public responses.
- Use
Response.jsonwith explicit response shapes in route handlers.
- Put slice tests in
features/<slice>/tests/and E2E tests intests/e2e/. - Use Arrange, Act, Assert form.
- Test every acceptance-criterion path that changes behavior.
- Cover success, expected failure, authorization boundaries, privacy projection, idempotency, and persistence side effects.
- Mock only external boundaries such as daily.dev, time, and database clients at the deepest practical boundary.
- Do not mock intermediate services to test their callers.
- All primary keys are UUID strings generated by the application or database.
- Store timestamps as
timestamptzin UTC. - Mutable tables include
created_atandupdated_at; append-only event tables includecreated_atonly. - Run migrations with
bun run db:migrate. - Run seeds with
bun run db:seed:devorbun run db:seed:qa. - Migration runners must resolve migrations relative to their module and use
DATABASE_URL. - Never hardcode absolute migration paths, inline connection strings, or arbitrary seed file paths.
- Reset accepts only
devorqaseeds.
- Passwords are Argon2id hashes with versioned parameters. Never store or log plaintext passwords.
- Sessions use signed JWTs in httpOnly cookies plus
sessionstable validation. - Session claims are
userId,username,role,sessionId,iat,exp, andtokenVersion. - Cookies are
SameSite=Lax, 7-day expiry, andSecurein production. - daily.dev Personal Access Tokens are integration credentials, not login credentials.
- Store daily.dev tokens encrypted server-side with AES-GCM and
DAILYDEV_TOKEN_ENCRYPTION_KEY. - Never expose tokens, encrypted-token internals, database URLs, auth headers, passwords, or session secrets to the browser, logs, public JSON, or share snapshots.
- Read environment variables through one server-only Zod-validated config module.
- Client code may read only safe
NEXT_PUBLIC_*values. - Enforce owner scope on every private mutation.
- Superadmins may provision and reset judge demo accounts, but may not bypass token secrecy or public share privacy.
GET /api/healthis public and secret-free.POST /api/admin/reset-statemust be absent in production and bearer-protected outside production.- Public share snapshots may expose only seniority level, seniority score, health state, top tags, speech bubble, generated date, and powered-by attribution.
| Variable | Rule |
|---|---|
APP_ENV |
development, test, qa, or production |
DATABASE_URL |
Required server-side for Drizzle, migrations, and seeds |
DAILYDEV_TOKEN_ENCRYPTION_KEY |
Required base64 256-bit AES-GCM key |
SESSION_SECRET |
Required high-entropy JWT signing secret |
RESET_STATE_SECRET |
Required only outside production when reset API is enabled |
ENABLE_RESET_API |
true only outside production, absent or false in production |
DEFAULT_SEED |
Optional local helper, normally dev or qa |
DAILYDEV_SERVER_TOKEN |
Optional, non-personal fallback only |
NEXT_PUBLIC_APP_URL |
Required public base URL, not secret |
In production, APP_ENV=production, ENABLE_RESET_API is absent or false, RESET_STATE_SECRET is absent, and reset-state is not registered.
- Use Conventional Commits with imperative summaries, such as
feat: add dailydev token validation route. - Use prefixes such as
feat:,fix:,test:,docs:,refactor:, andchore:. - Do not require AI co-author trailers.
- Do not commit secrets,
.env.local, credentials, generated test artifacts, or unrelated local files. - Vercel deploys automatically when
mainis updated. - Before schema-changing deployment work, create a Neon branch or snapshot and coordinate timing with the project owner.
| Violation | Why |
|---|---|
any, unchecked casts, or non-null assertions |
Type gaps become correctness and privacy bugs |
| Business logic in route handlers or server actions | Boundaries must stay thin and testable |
| React imports in domain modules | Domain behavior must be testable without rendering |
Direct db imports outside lib/db/ |
Data access must stay behind repositories and services |
| Cross-module private imports | Feature modules must remain movable and reviewable |
| Broad CORS headers | Sessions and tokens are same-origin assets |
dangerouslySetInnerHTML for user or API content |
React escaping is the XSS control |
| Plaintext token, password, or authorization logging | The app handles credentials and personal daily.dev access |
| Reset endpoint in production | Production data must never be reset |
| Public share raw activity, user IDs, profile IDs, comments, emails, or article lists | Share pages expose only allowlisted aggregates |
| Queues, caches, Redis, workers, BetterAuth, tRPC, image generation, or AI chat | Explicit MVP non-goals |
| Hardcoded migration paths, raw SQL migration application, or arbitrary seed paths | Bypasses Drizzle ledger and breaks deploy portability |
| Commented-out code, dead code, TODO, or FIXME markers | Partial work must not hide in merged code |
After compaction or handoff, verify these invariants before editing:
- Bun is the only package and script runner.
-
bun run complete-checkis the full merge gate. - Source files stay under 300 lines and split at 250.
- Domain logic stays in
features/<slice>/domain/, independent of React. - Database access stays behind
lib/db/repositories, feature ports, or infrastructure adapters. - Users have roles
userorsuperadmin. - User modes transition between
demoandconnectedonly. - Health states include
hibernating, not permanent death. - Revive Feather applies only when health is 0 through 9 and sets recovery to the documented path.
- Power-ups affect energy or health, never seniority or stored activity history.
- Missed-day processing runs on dashboard open, not a worker.
- daily.dev failures are recoverable and demo mode keeps working.
- Tokens are AES-GCM encrypted server-side and never serialized to clients.
- Public share pages read only public projection fields by
public_id. - Reset-state is absent in production and accepts only
devorqaoutside production. - Conventional Commits are used without required AI co-author trailers.
bun install --frozen-lockfile
bun run dev
bun run type-check
bun run lint
bun run format
bun run format:write
bun run test
bun run test:e2e
bun run build
bun run complete-check
bun run db:migrate
bun run db:seed:dev
bun run db:seed:qa
curl "$NEXT_PUBLIC_APP_URL/api/health"
curl -X POST "$NEXT_PUBLIC_APP_URL/api/admin/reset-state" -H "Authorization: Bearer $RESET_STATE_SECRET" -H "Content-Type: application/json" -d '{"seed":"dev"}'