{ "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 (0000–0013) + 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" } }