This page summarizes how the LTL codebase is organized and the conventions that keep it consistent. The canonical, full-detail source is the design document in the LTL repository.
Repository Layout
LTL is an npm-workspaces monorepo:
ltl/
├── apps/
│ └── mobile/ # Expo app
├── packages/
│ ├── shared/ # Shared TypeScript types (incl. generated DB types)
│ ├── ui/ # Component library
│ └── prompts/ # Prompt library
├── supabase/
│ ├── migrations/ # SQL migrations
│ ├── functions/ # Edge Functions (Deno)
│ └── seed/ # Seed data (prompt library)
└── docs/ # Design document and runbooks
The dependency flow is one-way: shared types feed both the app and the backend functions.
Tooling and Quality Gates
Three checks run locally before a pull request and in CI on every PR:
npm run typecheckacross all workspaces (TypeScript strict, noanyin new code).npm run lint(ESLint flat config at the repo root).npm run format:check(Prettier;npm run formatauto-fixes).
Dependencies
Any expo-* or react-native-* package must be added with npx expo install <pkg>, never plain npm install. Expo pins exact peer-dependency versions per SDK, and a plain install grabs latest, which diverges and fails at runtime with opaque errors. Run npx expo install --check from the app workspace to audit drift; CI does the same. Repo-root devDependencies that are not part of the Expo runtime (ESLint, Prettier, TypeScript) can use a normal install.
Supabase Workflow
The local stack boots with the Supabase CLI, which applies every migration on start. Environment variables are read from the app workspace’s local env file rather than the repo root. Database types are regenerated from the local or linked schema after each migration, with named aliases kept in a separate file so they survive regeneration.
Code Style
- TypeScript strict throughout; functional components with hooks only.
- All dates as ISO 8601 strings.
- UUIDs from a crypto source on the client and
gen_random_uuid()in Postgres. - Comments explain non-obvious why, never restate the code.
Load-Bearing Constraints
These come straight from the product principles and are enforced in code:
- Grief-sensitive UX: nothing may punish a user for stepping away. Streak logic softens on memorialization. Memorial prompts must pass the next-week and stranger tests.
- The deceased’s voice is frozen: content authored before memorialization is never editable by anyone; the schema enforces this with an
is_frozenflag. - Offline-first: every core read path works from SQLite without a network; writes queue and sync.
- Death-transition integrity: Path A and Path B transitions never run client-only; server-side Edge Functions enforce cooldown, notification fan-out, and objection handling, and every state change appends to the immutable audit log.
Conventions
- Commits follow
<type>(<scope>): <subject>, with typesfeat,fix,refactor,docs,chore. mainis protected; work lands through prefixed branches and pull requests.- No AI attribution of any kind in commits, PRs, or files; the owner is the sole author.