| title | Repository Structure | |||||
|---|---|---|---|---|---|---|
| category | architecture | |||||
| tags |
|
|||||
| sources |
|
|||||
| updated | 2026-04-15 |
Turborepo monorepo. All services in one repo with path-filtered CI/CD for independent deploys. src/packages/types is consumed everywhere — this is the primary reason for monorepo over polyrepo.
Why monorepo over polyrepo:
- Shared TypeScript types are required.
src/packages/typesconsumed by web + tRPC routers. Polyrepo would need versioned npm publishes on every change. - Cross-service changes ship atomically. A generation feature touches web → api → worker → postprocess. One PR, one review.
- Turborepo path filtering gives polyrepo-level deploy isolation. Each service deploys independently via GitHub Actions path filters.
- Go + Rust coexist cleanly.
src/services/is independent of npm workspaces. No toolchain conflicts. - Stage of company. Polyrepo overhead only pays off with dedicated per-service teams.
When to revisit (not V1): Series A+ with dedicated teams per service, or security requirements to restrict repo access per service.
qvora/
├── .github/
│ ├── copilot-instructions.md ← Auto-loaded by GitHub Copilot (THIS FILE)
│ ├── workflows/
│ │ ├── ci.yml ← Lint + typecheck + test on every PR
│ │ ├── deploy-web.yml ← Trigger: src/apps/web/**, src/packages/**
│ │ ├── deploy-api.yml ← Trigger: src/services/api/**
│ │ ├── deploy-worker.yml ← Trigger: src/services/worker/**
│ │ ├── deploy-postprocess.yml ← Trigger: src/services/postprocess/**
│ │ └── deploy-db.yml ← Trigger: supabase/migrations/** → supabase db push
│ ├── CODEOWNERS
│ └── pull_request_template.md
│
├── src/ ← All source code
│ ├── apps/
│ │ └── web/ ← Next.js 15 App Router → Vercel
│ ├── packages/
│ │ ├── types/ ← Shared TypeScript types
│ │ ├── ui/ ← shadcn/ui component copies
│ │ └── config/ ← Biome + TS base configs
│ └── services/
│ ├── api/ ← Go Echo v4 → Railway
│ ├── worker/ ← Go asynq → Railway
│ └── postprocess/ ← Rust Axum + ffmpeg-sys → Railway
│
├── supabase/
│ └── migrations/
│ ├── 001_initial_schema.sql
│ ├── 002_postprocess_callbacks.sql
│ └── 003_mux_webhook_events_and_reconcile.sql
│
├── wiki/ ← LLM wiki (this system)
├── docs/ ← Source documents ingested into wiki
├── turbo.json
├── biome.json
├── lefthook.yml
└── package.json (pnpm workspaces)
src/apps/web/
├── app/
│ ├── layout.tsx ← Root layout + ClerkProvider
│ ├── page.tsx ← Marketing / home
│ ├── globals.css ← @theme {} Tailwind v4 tokens ONLY
│ ├── (auth)/ ← Route group (no URL segment)
│ │ ├── sign-in/[[...sign-in]]/
│ │ └── sign-up/[[...sign-up]]/
│ ├── (onboarding)/ ← Post-signup wizard
│ │ ├── page.tsx ← Step 1: org + workspace
│ │ └── brand/page.tsx ← Step 2: brand kit
│ ├── (dashboard)/ ← Authenticated shell
│ │ ├── layout.tsx
│ │ ├── briefs/
│ │ │ ├── page.tsx ← Brief list (S-01)
│ │ │ └── [id]/
│ │ │ ├── page.tsx ← Brief detail + angles (S-03/04)
│ │ │ └── generate/page.tsx ← Generation settings (S-06)
│ │ ├── assets/page.tsx ← Asset library (S-07)
│ │ ├── exports/page.tsx ← Exports list (S-09)
│ │ ├── brand/page.tsx ← Brand kit (S-10)
│ │ └── settings/page.tsx ← Org + billing (S-11)
│ └── api/
│ ├── trpc/[trpc]/route.ts ← tRPC HTTP handler
│ └── generation/[jobId]/stream/route.ts ← SSE stream (NOT tRPC)
├── middleware.ts ← clerkMiddleware() export
└── next.config.ts
src/services/api/
├── cmd/api/main.go
├── internal/
│ ├── domain/ ← Business logic (extracted from handlers, Phase 8)
│ │ ├── signal/ ← connections, metrics, fatigue, recommendations, gdpr, oauth, sync
│ │ ├── brief/ ← brief extraction, angles, hooks
│ │ ├── asset/ ← asset library logic
│ │ ├── media/ ← mux, R2 upload helpers
│ │ └── identity/ ← workspace, subscription, trial
│ ├── handler/ ← Echo route handlers (thin delegates to domain/*)
│ ├── middleware/ ← Clerk JWT, rate-limit, tier enforcement
│ └── db/ ← sqlc-generated Go types
├── db/
│ ├── queries/ ← .sql files → sqlc input
│ └── migrations/ ← NOT used (supabase/migrations/ is source of truth)
├── go.mod
└── sqlc.yaml
src/services/worker/
├── cmd/worker/main.go
└── internal/task/ ← Task handlers: brief:extract, generation:video, etc.
├── video_provider.go ← VideoProvider interface + FalProvider (Phase 8)
├── avatar_provider.go← AvatarProvider interface + HeyGenV3 + Tavus
└── generate.go ← HandleGenerate(rdb, VideoProvider) — provider-injected
src/services/postprocess/
├── src/
│ ├── main.rs
│ ├── handler.rs ← Axum route handlers
│ ├── processor.rs ← ffmpeg-sys operations
│ ├── model.rs
│ ├── mux.rs
│ └── error.rs
└── Cargo.toml
Scope is locked to: watermark, captions, transcode, reframe. Do not expand Rust beyond CPU-bound video processing.
Consumed by src/apps/web and tRPC routers. Primary reason for monorepo. Contains:
- Generation job status enums
- Brief, angle, hook, asset type definitions
- Stripe tier enum
- Zod schemas shared between frontend and BFF
- Is there a
src/ai/directory for Vercel AI SDK prompt templates separate fromsrc/apps/web? - Where does the Playwright scraping Modal code live? (Not yet in repo structure)
- [[system-architecture]] — runtime topology for these services
- [[stack-overview]] — tooling for each directory
- [[sprint-plan]] — which pieces were built in which sprint