docs: add repository index (PROJECT_INDEX.md + PROJECT_INDEX.json)

Token-efficient session bootstrap: module map, entry points, routes,
jobs, deps, test/deploy conventions. Regenerate via /sc:index-repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 19:25:35 +03:00
parent 8b7dc83bd2
commit a237e55874
2 changed files with 215 additions and 0 deletions

127
PROJECT_INDEX.json Normal file
View File

@@ -0,0 +1,127 @@
{
"project": "sase-v2 (sase.tr)",
"description": "Turkish B2B SaaS: VIN decode + OEM parts-catalog platform for parts dealers & repair shops",
"generated": "2026-06-10",
"generator": "/sc:index-repo",
"humanReadable": "PROJECT_INDEX.md",
"stack": {
"packageManager": "pnpm@10.29.3",
"node": "22 (alpine in Docker)",
"monorepo": "pnpm workspaces + turbo",
"language": "TypeScript",
"lint": "biome"
},
"workspaces": {
"apps/api": { "name": "api", "framework": "NestJS ^10.4", "role": "REST API :4000 + BullMQ worker (worker.ts)" },
"apps/web": { "name": "web", "framework": "React ^19 + TanStack Router ^1.120 + Vite", "role": "SPA dashboard + marketing pages" },
"packages/shared": { "name": "@sase/shared", "role": "zod schemas, types, constants (plans, error-codes, regex), utils (vin-validator, formatters, currency)" },
"packages/config": { "name": "@sase/config", "role": "shared config" },
"packages/ui": { "name": "@sase/ui", "role": "shadcn-style component library" }
},
"entryPoints": {
"api": "apps/api/src/main.ts",
"worker": "apps/api/src/worker.ts",
"web": "apps/web/src/main.tsx",
"migrations": "apps/api/src/database/migrate.ts"
},
"apiModules": {
"vehicles": "VIN decode orchestration; fallback chain Corgi→PartsCatalogs→PL24→EMEX→NHTSA; slim response + Redis candidate stash (vin-cache-keys.ts)",
"integrations/pl24": "PartsLink24 — shared P4 core + brand services: pl24.service, pl24-psa, pl24-volvo, pl24-ford, pl24-hyundai-kia, pl24-opel, pl24-ford-legacy, pl24-auth, parsers/",
"integrations/emex": "emexdwc.ae scrape — HTTP (undici ProxyAgent) primary, Playwright fallback (emex.browser.ts), emex-tree.parser",
"integrations/parts-catalogs": "PartsCatalogs API (pcat)",
"integrations/p": "OEM cross-reference 'P' — TecDoc-derived MySQL (P_DB_* env): p.controller, p-source-db.service",
"integrations/corgi": "offline WMI lookup (instant)",
"integrations/vin-api": "NHTSA fallback decoder",
"integrations/catalog-source-db": "upstream source-DB bridge",
"catalog": "catalog browse — catalog/pcat-catalog/emex-catalog controllers+services",
"categories": "category tree: partCount rollup, lazy drill/heal, PSA parent gates",
"parts": "part listings",
"brands": "brand canonicalization (case-insensitive lookup)",
"auth": "better-auth cookie sessions",
"users": "user management",
"referrals": "referral program",
"payments": "Stripe",
"subscriptions": "subscription lifecycle",
"plans": "plan definitions",
"jobs": "BullMQ — queues: catalog-prefetch, emex-scrape, translation, lifecycle-email, subscription-expiry, query-cleanup; processors mirror queues; prefetch-worker.service",
"posthog": "server-side feature-flag eval + kill-source-* switches",
"meta-capi": "Meta Conversions API (event_id dedup, fail-open)",
"notifications": "Novu lifecycle triggers",
"email": "Postal HTTP API ops mail",
"chatwoot": "support-desk integration",
"analytics": "product analytics endpoints",
"telemetry": "OpenTelemetry → OTLP exporters",
"common": "shared infra incl. catalog-degradation → Sentry (fingerprinted, Redis-deduped)",
"redis": "ioredis provider",
"storage": "S3/MinIO",
"translations": "OpenAI-backed translation",
"admin": "admin endpoints",
"internal-admin": "internal admin",
"blog": "blog content",
"changelog": "changelog content",
"demo": "public demo flow",
"contact": "contact form",
"config": "configuration.ts + env.validation.ts (zod; empty-string trap)",
"database": "Drizzle provider; schema split: core, pl24, emex, parts-catalogs, relations"
},
"webRoutes": {
"public": ["index", "pricing", "blog", "blog_/$slug", "demo", "demo_/categories_/$categoryId", "about", "contact", "kvkk", "privacy", "terms"],
"auth": ["login", "register", "forgot-password", "reset-password", "email-verified"],
"dashboard": [
"index", "search", "history", "settings", "billing", "changelog",
"vehicles_/$id", "vehicles_/$id/categories_/$categoryId",
"catalog/index", "catalog_/$brandName", "catalog_/$brandName_/$modelId", "catalog_/$brandName_/$modelId/categories_/$categoryId",
"catalog_/pcat/$catalogId[/_$modelId/_$carId[/groups/$groupId]]",
"catalog_/emex/$catalogCode[/_$vehicleId[/groups/$groupId]]",
"oem.$code", "subscription", "service-test"
],
"admin": ["admin/index", "admin/users", "admin/analytics", "admin/referrals", "admin/copy-logs"]
},
"webLib": ["api-client", "auth-client", "posthog", "surveys", "meta-pixel", "faro", "sentry", "chatwoot", "i18n", "vehicle", "toast", "user-settings", "keys", "category-icons", "emex-group-hierarchy", "recently-used-brands"],
"configFiles": {
"turbo.json": "task pipeline",
"biome.json": "lint/format",
"docker-compose.coolify.yml": "prod/staging: api + worker + sase-redis; env vars must be referenced as ${VAR} per service block",
"Dockerfile": "multi-stage node:22-alpine + Chromium; runtime imports must be in dependencies",
"ecosystem.config.js": "PM2",
"apps/api/src/config/env.validation.ts": "zod env gate"
},
"database": {
"primary": "PostgreSQL via drizzle-orm ^0.41",
"migrations": "apps/api/drizzle/ — 14 SQL files (00000013) + meta/_journal.json; custom SHA256-tracked runner (src/database/migrate.ts)",
"schemas": ["core", "pl24", "emex", "parts-catalogs", "relations"],
"secondary": "MySQL (mysql2) — TecDoc-derived 'P' OEM cross-ref db",
"cache": "Redis (sase-redis container) — BullMQ + VIN candidate stash + dedup"
},
"tests": {
"api": { "framework": "vitest", "count": 30, "pattern": "*.spec.ts", "run": "pnpm --filter api test" },
"web": { "framework": "vitest (no Playwright e2e)", "count": 24, "pattern": "*.test.ts(x)", "run": "pnpm --filter web test" },
"qa": "qa/post-deploy smoke checks"
},
"keyDependencies": {
"api": ["@nestjs/* ^10.4", "drizzle-orm + postgres", "better-auth", "bullmq + ioredis", "stripe", "posthog-node", "openai", "undici", "@sentry/nestjs", "@opentelemetry/*", "mysql2", "zod"],
"web": ["react ^19", "@tanstack/react-router + react-query", "zustand", "posthog-js", "@grafana/faro-web-sdk", "@sentry/react", "remotion", "better-auth", "zod"]
},
"commands": {
"install": "pnpm install",
"dev": "pnpm dev",
"build": "pnpm build",
"lint": "pnpm lint",
"typecheck": "pnpm typecheck",
"test": "pnpm test",
"dbMigrate": "pnpm --filter api db:migrate",
"dbStudio": "pnpm --filter api db:studio"
},
"deployment": {
"platform": "Coolify (cool.semih.ai)",
"staging": { "branch": "dev", "fqdn": "dev.sase.tr", "rule": "verify every change here first" },
"production": { "branch": "main", "fqdn": "sase.tr", "rule": "promote only after dev verified" },
"policy": "never edit on server/container; push-to-deploy via Gitea webhooks"
},
"docs": {
"assistant": ["CLAUDE.md", "AGENTS.md"],
"internal": "docs/ (INDEX.md, 00-testing.md, design-specs/, pl24-catalog/, product/, clarification/)",
"rootReports": ["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", "MANIFEST-FN-403.md", "RECOVERY-FN-412.md", "SCOPING-FN-411.md", "SASE_PRD_Hesap_Paylasimi_Onleme_v1.1.md"],
"bizWorkspace": "/home/s/ss/INDEX.md"
}
}

88
PROJECT_INDEX.md Normal file
View File

@@ -0,0 +1,88 @@
# 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`