Monorepo Approach
Goal: keep client, server, jobs, and docs in one repo for atomic changes, shared contracts, and simple CI/CD.
Why monorepo (now)
- Atomic PRs: UI ↔ API ↔ jobs change together.
- Shared contracts: one source of truth for DTOs, error codes, OpenAPI.
- One local stack: DB/Redis/S3 once; run all services with a single command.
- Simple releases: path-filtered CI so only affected parts ship.
When to split later
- Team > 6–8 backend/ML engineers working in parallel.
- Different deploy cadences (e.g., GPU stylization daily vs API weekly).
- Reg/PII isolation requirements.
- CI times > ~15 min even with caching.
Repo layout (baseline)
otherwhere/
├─ apps/
│ ├─ mobile/ # React Native (iOS)
│ ├─ admin/ # (optional) Next.js mod/admin
│ └─ docs/ # Docusaurus (Cloudflare Pages)
├─ server/ # Fastify monolith (REST + WS + jobs)
│ ├─ src/
│ │ ├─ app.ts # bootstrap
│ │ ├─ config/ # env, flags
│ │ ├─ plugins/ # auth, swagger, rate-limit…
│ │ ├─ lib/ # db, redis, s3, apns, logger
│ │ ├─ modules/ # auth, profiles, avatars, feed, matches, story, intents, reveal, safety, labels, analytics
│ │ ├─ ws/ # chat service
│ │ ├─ jobs/ # BullMQ processors
│ │ ├─ middleware/ # errors, request-id
│ │ └─ test/ # http/ws tests
│ ├─ prisma/ # migrations (or sql/)
│ ├─ openapi/ # generated json
│ └─ scripts/ # seed, smoke
├─ workers/
│ └─ avatar-python/ # PyTorch stylization worker
├─ packages/
│ ├─ shared-types/ # DTOs, error codes, analytics events
│ ├─ eslint-config/
│ └─ tsconfig/
├─ infra/
│ ├─ docker-compose.dev.yml # postgres, redis, minio
│ └─ (iac later)
├─ .github/workflows/ # CI per surface
├─ pnpm-workspace.yaml
└─ README.md
Workspaces & path filters
Use pnpm workspaces; CI runs only where files changed.
# example path filters in GitHub Actions
on:
push:
branches: [main]
paths:
- "apps/docs/**"
- ".github/workflows/docs.yml"
Module contract (server)
Each feature in server/src/modules/<feature>/:
routes.ts— Fastify routes (wire Zod schemas)schemas.ts— Zod request/response DTOs (→ OpenAPI)service.ts— business logicrepo.ts— DB access only
Local dev flow
docker compose -f infra/docker-compose.dev.yml up -d
pnpm -w install
# server
cd server && pnpm dev
# mobile
cd apps/mobile && pnpm start
# docs
cd apps/docs && pnpm start
Shared contracts
packages/shared-types/exports DTOs, error codes, analytics events.servergenerates OpenAPI from Zod → copied intoapps/docs/static/api/(build step).- Mobile imports types from
shared-typesto avoid drift.
Conventions
- TypeScript strict, Zod validation, explicit error codes.
- Conventional commits; trunk-based flow.
- Feature flags in
server/src/config/flags.ts. - PR checklist: schemas, tests, analytics, docs, rollback notes.