6fbbd753d98644c031a5b208c63f04d0ff042906
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
mailAudit.md §9.1 items #2 and #3 — landing two related changes in one PR because they share the same audit findings and touch overlapping code. Test-user exclusion (lifecycle-email.processor.ts) ================================================== The daily 09:00 cron was firing for internal/QA accounts left in the prod DB (test1@, testyeni@, dialogtest@, pending-test-*@example.com, stripe-test-*@otoyedekparca.co, admin@, adm1in@). On 2026-06-04 09:00 the last 5 trial-ending mails went to test users alone. Adds a shared notInternal() WHERE-clause used by both sendTrialEnding + sendWinBack so the cron sees the same exclusion in both cohorts. Patterns are anchored to in-house domains (@sase.tr / @example.com / @otoyedekparca.co) so a legitimate `test@gmail.com` user isn't accidentally muted. List-Unsubscribe header (novu.ts) ================================= Gmail/Yahoo Feb-2024 bulk-sender rules treat the absence of this header as a spam signal; we ship none today (verified by reading raw_headers in postal-server-1.raw-2026-06-04). triggerNovu() now attaches a per-call `overrides.email.headers` containing: List-Unsubscribe: <mailto:unsubscribe@sase.tr?subject=unsubscribe:WORKFLOW> (+ `<https://…>` and `List-Unsubscribe-Post: One-Click` when UNSUBSCRIBE_URL_BASE env is set — gated until the HTTPS endpoint ships) Auth flows (email-verification, password-reset) opt out via NO_UNSUBSCRIBE_WORKFLOWS so a privacy-proxy pre-fetching the unsub link can't consume the one-time token. Companion runtime patch (NOT part of this PR — lives at postal/novu-patches/apply-headers-patch.sh on the host): Novu OSS v3.15.0 NodemailerProvider.createMailData drops options.headers before calling nodemailer.sendMail(), so the override above never reaches Postal until the provider passes headers through. The host-side patch re-injects them after each Novu redeploy. Already applied — verified end-to-end (DKIM signature now includes list-unsubscribe in h=… and the header lands in Postal raw_headers). Sibling out-of-PR changes done today (in mailAudit.md §9.1): - DMARC pct=25 → pct=50, +ruf=mailto:dmarc@sase.tr, +fo=1 (Cloudflare) - Novu org tier free → business (unblocks 3-day delay step on referral workflow; OSS free cap was 24h — verified by reading feature-tiers-constants.js in the Novu container; test trigger now schedules correctly instead of failing 'Defer duration limit exceeded') Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sase
VIN/şase numarası sorgulama ve otomotiv yedek parça katalog platformu (Türkiye). Site: https://sase.tr · Staging: https://dev.sase.tr
Stack
| Katman | Teknoloji |
|---|---|
| Monorepo | pnpm 10 + Turborepo |
| Backend | NestJS 10, TypeScript 5.7, Node 22 |
| DB | PostgreSQL 17 + Drizzle ORM |
| Cache / Queue | Redis 7 + BullMQ |
| Auth | Better Auth (cookie session) |
| Frontend | Vite 6, React 19, TanStack Router + Query |
| UI | Tailwind v4, shadcn/ui (Radix) |
| Ödeme | Stripe (kart) |
| Postal | |
| Storage | MinIO (S3) |
| Analitik | PostHog |
| Test | Vitest, Playwright |
| Deploy | GitHub Actions → SSH → PM2 |
Yapı
ss/
├── apps/
│ ├── api/ NestJS (port 4000, /api)
│ └── web/ Vite + React (port 3000)
├── packages/
│ ├── shared/ Tipler, Zod şemaları
│ ├── config/ Env şeması (Zod)
│ └── ui/ Paylaşılan shadcn bileşenleri
├── docker/ docker-compose + nginx
├── scripts/ Deploy + bakım scriptleri
└── docs/ Detay dökümantasyon (INDEX.md)
Komutlar
pnpm dev # tüm app'ler (Turbo)
pnpm build
pnpm test # Vitest
pnpm lint # Biome
pnpm typecheck
# DB (apps/api/)
pnpm db:push # şemayı push
pnpm db:studio # Drizzle Studio
pnpm db:generate # migration üret
# Tek app
pnpm dev --filter=api
pnpm dev --filter=web
VIN Decode Akışı
Corgi (offline WMI) → PartsCatalogs API → PL24 API → EMEX scraper → NHTSA
Birden fazla araç eşleşmesi gelirse frontend seçim modalı gösterir.
Katalog Mimarisi
- PL24 P5 Modern (REST/JSON) — VW Group, BMW, Mercedes, Renault, Toyota...
- PL24 P4 Legacy (HTML scrape) — Ford, PSA, Hyundai/Kia, Nissan, Opel, Volvo
- PartsCatalogs (REST + Playwright JWT) — geniş VIN kapsamı
- EMEX (Playwright scrape,
emexdwc.ae) — async BullMQ worker
EMEX & PartsCatalogs Türkçeleştirme
EMEX ve PartsCatalogs kaynakları kategori/parça isimlerini İngilizce (zaman zaman Rusça) döner. Çeviri akışı:
TranslationsService(apps/api/src/translations/) — Redis cache → DB lookup (emex_category_translations) → orijinal döndür. Dictionary tabanlı word-by-word replace devre dışı (yarı-İngilizce çıktı yaratıyordu).- Hot path (
categories.service.ts) — EMEX/PCAT insert noktalarındatranslateMany()ile bulk lookup yapılır; cache miss varsa orijinal yazılır, sonraki bootstrap pass'inde LLM ile çevrilir. - Bootstrap script (
scripts/emex-translate-bootstrap.ts) — DB'deki tüm uniquename_originaldeğerlerini OpenRouter üzerinden DeepSeek V3 ile çevirir,emex_category_translationstablosuna yazar. - Backfill script (
scripts/emex-backfill-tr-names.ts) — translation tablosuna göre mevcutcategories.nameveparts.namedeğerlerini günceller, Redis cache flush eder.
# 1) Tüm yeni terimleri çevir (~$0.50, ~30 dk)
pnpm exec tsx scripts/emex-translate-bootstrap.ts --dry-run
pnpm exec tsx scripts/emex-translate-bootstrap.ts
# 2) DB kayıtlarını güncelle
pnpm exec tsx scripts/emex-backfill-tr-names.ts --dry-run
pnpm exec tsx scripts/emex-backfill-tr-names.ts
# 3) API restart (yeni hot-path translateMany için)
pm2 restart sase-api
Env: OPENROUTER_API_KEY (apps/api/.env).
Test Bilgileri
- Admin:
admin@sase.tr/Sase2026 - Test VIN (VW):
WVWZZZ1JZ3W597935 - Login:
POST /api/auth/sign-in/email→ cookiebetter-auth.session_token
Daha Fazla
docs/INDEX.md— kapsamlı proje rehberi (rotalar, API, DB şeması, bileşenler)CLAUDE.md— Claude Code için proje rehberi
Description
Languages
TypeScript
74.8%
HTML
20.2%
JavaScript
4%
Shell
0.5%
PLpgSQL
0.2%
Other
0.2%