# Project Index: sase.tr (sase-v2) Generated: 2026-06-10 · regenerate via `/sc:index-repo` · machine-readable twin: `PROJECT_INDEX.json` Turkish B2B SaaS: VIN decode + OEM parts-catalog platform for parts dealers & repair shops. pnpm 10.29.3 workspaces + Turbo · Node 22 · TypeScript · Biome. ## Structure ``` apps/api NestJS 10 backend — REST API (:4000) + separate BullMQ worker apps/web React 19 + TanStack Router/Query + Vite SPA (Remotion video, i18n) packages/shared @sase/shared — zod schemas, types, constants (plans, error-codes), utils (vin-validator, formatters) packages/config @sase/config — shared config packages/ui @sase/ui — shadcn-style components scripts/ one-off ops/debug (emex scrapers, backfills, deploy.sh, pl24-catalog-explorer) qa/post-deploy post-deploy smoke checks docs/ internal docs — see docs/INDEX.md (testing, design-specs, pl24-catalog, product) docker/ local dev compose (minio, nginx) ``` ## Entry Points - `apps/api/src/main.ts` — API bootstrap (also serves built web via ServeStatic; no nginx in prod) - `apps/api/src/worker.ts` — BullMQ worker process (separate container) - `apps/api/src/database/migrate.ts` — custom SHA256-tracked migration runner over `apps/api/drizzle/` (14 SQL migrations + `meta/_journal.json`) - `apps/web/src/main.tsx` — SPA bootstrap (`routeTree.gen.ts` generated by `tsr generate`) ## API Modules (`apps/api/src/`) - **vehicles/** — VIN decode orchestration; fallback chain Corgi → PartsCatalogs → PL24 → EMEX → NHTSA; slim decode response + Redis candidate stash (`vin-cache-keys.ts`) - **integrations/pl24/** — PartsLink24: shared P4 core + per-brand services (`psa`, `volvo`, `ford`, `hyundai-kia`, `opel`, `ford-legacy`) + `parsers/` - **integrations/emex/** — emexdwc.ae scrape: HTTP via undici ProxyAgent, Playwright fallback (`emex.browser.ts`), tree parser - **integrations/parts-catalogs/** — PartsCatalogs API ("pcat") - **integrations/p/** — OEM cross-reference ("P", TecDoc-derived MySQL db; `P_DB_*` env) - **integrations/corgi/**, **vin-api/** — offline WMI lookup; NHTSA fallback - **integrations/catalog-source-db/** — upstream source-DB bridge - **catalog/** — catalog browse endpoints (`catalog`, `pcat-catalog`, `emex-catalog` controllers/services) - **categories/**, **parts/**, **brands/** — category tree (partCount rollup, lazy drill/heal), parts, brand canonicalization - **auth/** (better-auth cookie sessions), **users/**, **referrals/** - **payments/** (Stripe), **subscriptions/**, **plans/** - **jobs/** — BullMQ queues + processors: `catalog-prefetch`, `emex-scrape`, `translation`, `lifecycle-email`, `subscription-expiry`, `query-cleanup` - **posthog/** — server-side flag eval + `kill-source-*` switches · **meta-capi/** — Meta Conversions API - **notifications/** (Novu), **email/** (Postal), **chatwoot/** - **analytics/**, **telemetry/** (OTel → OTLP), **common/** (incl. catalog-degradation → Sentry), **redis/**, **storage/** (S3/MinIO), **translations/** (OpenAI), **admin/**, **internal-admin/**, **blog/**, **changelog/**, **demo/**, **contact/** - **config/** — `env.validation.ts` zod gate (beware `""` vs undefined), `configuration.ts` - **database/** — Drizzle provider + `schema/` split: `core`, `pl24`, `emex`, `parts-catalogs`, `relations` ## Web (`apps/web/src/`) - **routes/** — public: `index`, `pricing`, `blog`, `demo`, `about/contact/kvkk/privacy/terms` · `_auth/`: login, register, forgot/reset password, email-verified · `dashboard/`: `search` (main VIN flow), `vehicles_/$id[/categories_/$categoryId]`, catalog trees (`catalog_/$brandName/...`, `catalog_/pcat/...`, `catalog_/emex/...`), `oem.$code` (cross-ref), `subscription`, `billing`, `history`, `settings`, `service-test` (admin), `admin/*` (users, analytics, referrals, copy-logs) - **lib/** — `api-client`, `auth-client`, `posthog`, `surveys` (API-mode survey renderer), `meta-pixel`, `faro`, `sentry`, `chatwoot`, `i18n`, `vehicle` - **stores/** (zustand), **components/**, **remotion/**, **messages/** (i18n), **hooks/** ## Configuration - `turbo.json`, `biome.json`, `tsconfig.json` — build/lint/typecheck pipeline - `docker-compose.coolify.yml` — prod/staging: `api` + `worker` + `sase-redis` (Coolify env reaches a service ONLY if its `environment:` block references `${VAR}`) - `Dockerfile` — multi-stage node:22-alpine + Chromium (runtime imports MUST be in `dependencies`) - `ecosystem.config.js` — PM2 config ## Tests - API: 30 `*.spec.ts` (Vitest) → `pnpm --filter api test` - Web: 24 `*.test.ts(x)` (Vitest only; **no Playwright e2e**) → `pnpm --filter web test`; plus per-package `index.spec.ts` - `qa/post-deploy/` smoke checks ## Key Dependencies NestJS 10 · drizzle-orm 0.41 + postgres · better-auth · bullmq + ioredis · stripe · posthog-node · openai (translations) · undici (proxied fetch — global fetch lacks `dispatcher`) · Sentry + OpenTelemetry · mysql2 (P/TecDoc) ·· React 19 · TanStack Router/Query · zustand · posthog-js · @grafana/faro · remotion · zod throughout. ## Quick Start 1. `pnpm install` 2. `pnpm dev` (turbo: api :4000 + web :3000) 3. `pnpm lint` / `pnpm typecheck` / `pnpm test` 4. DB: `pnpm --filter api db:migrate` (custom runner) · `db:studio` · `db:seed` ## Deployment (Coolify — NEVER edit on server) - Push `dev` → auto-deploys staging **dev.sase.tr** — verify every change here first - Merge to `main` → auto-deploys prod **sase.tr** (only after dev verified) ## Docs Map - `CLAUDE.md` / `AGENTS.md` — assistant instructions · `docs/INDEX.md` — internal docs index - Root reports: `upstream-prob.md`, `undecoded-vin-rca.md`, `posthog-max-leverage.md`, `posthog-feature-roadmap.md`, `katalogayapi.md`, `knowledge.md`, `ralpRapor.md`, `emex-hierarchy-plan.md`, `MANIFEST*.md`, `RECOVERY-FN-412.md`, `SCOPING-FN-411.md`, `SASE_PRD_Hesap_Paylasimi_Onleme_v1.1.md` - Business/ops workspace knowledge base: `/home/s/ss/INDEX.md`