Commit Graph

30 Commits

Author SHA1 Message Date
semih
56a8ea09be feat(pl24): günlük HTTP bütçesi, kullanıcı rezervi ve proxy_logs telemetrisi
Some checks are pending
QA Gate (P0/P1) / Test affected app (pull_request) Waiting to run
Faz 1 / adım 2 (analiz: /home/s/ss/plv2.md, bulgular consumers_jobs-03/06/07,
deploy_ops-13).

SORUN: İki PL24 hesap banı da günde 5-7 bin kategori yazan (≈10 bin+ istek)
otomatik drill dalgalarının ardından geldi; gerçek kullanıcı decode'u ≤14/gün.
Mevcut korumaların hepsi iş-seviyesinde (iş/dk, iş/gün) — HTTP isteği sayan
hiçbir tavan yoktu. Üstelik PL24 çağrıları `proxy_logs`'a hiç yazılmıyordu
(yalnız pcat/emex), bu yüzden hacim ancak ban'dan SONRA, DB satır sayılarından
geriye dönük çıkarılabildi. Kill switch de yalnız decodeVin'i kapatıyordu; drill,
backfill ve katalog gezinmesi "kapalı" kaynağa istek atmaya devam ediyordu.

DEĞİŞİKLİK:
- Yeni `PL24BudgetService`: tüm PL24 upstream trafiği için tek geçit.
  - Günlük sayaç `pl24:http:<gün>` (Redis, 8 gün TTL); tavan `PL24_HTTP_DAILY_MAX`
    (varsayılan 1200).
  - Kullanıcı rezervi `PL24_HTTP_USER_RESERVE` (varsayılan %40): backfill tavanın
    %60'ında durur, kullanıcı decode'u sonuna kadar akar — kaçak bir backfill
    müşteriyi asla aç bırakamaz. Lane ayrımı mevcut `isBackfillContext()` ile.
  - Reddedilen çağrı ağa hiç çıkmaz ve telemetriye yazılmaz.
  - Redis düşerse fail-open (auth/katalog telemetri yüzünden bloklanmaz).
- Telemetri: `ProxyServiceLeg` += `pl24_http`, `pl24_auth`. Login, authorize ve
  tüm katalog fetch'leri `proxy_logs`'a yazıyor (provider dataimpulse/none,
  sessionKey=hesap, status, süre, 403/429 → banned, taşıma hatası sınıflandırma).
  Artık "hangi gün kaç istek attık, ilk 401/403 ne zaman başladı" sorusu
  ban'dan ÖNCE yanıtlanabilir.
- Kill switch yayıldı: `kill-source-pl24` artık `budgetedFetch` içinde, yani
  decode + drill + backfill + browse + görsel indirme dahil TÜM katalog trafiğini
  kapatıyor (eskiden yalnız decodeVin).
- `fetchWithRetry` 401 çaresi netleşti: yalnız servis token'ı tazelenir; oturumun
  kendisi gerekirse auth katmanında düşürülür.

Test: yeni `pl24-budget.service.spec.ts` (9 test: tavan, kullanıcı rezervi,
reddedilen çağrının ağa çıkmaması, Redis fail-open, telemetri biçimi/leg ayrımı,
ban sinyali, taşıma hatası sınıflandırma). Etkilenen paketler: 197 test geçti.
tsc + biome temiz.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 13:13:05 +03:00
ed45021d71 feat(flags): server-side feature flags + upstream kill switches + live backfill config
Add server-side PostHog feature-flag evaluation to the API and wire three
high-leverage uses. The flags live in PostHog (project 127747), dormant and
fail-open, so this commit is a no-op until POSTHOG_PERSONAL_API_KEY is set and
a switch is flipped.

Phase 1 - upstream kill switches:
  PostHogService gains local flag evaluation (onlyEvaluateLocally +
  sendFeatureFlagEvents:false -> zero decode latency, no VIN leak) and
  isSourceLive(). Guards at each source's decode entry (parts-catalogs, emex,
  pl24 whole-source + per-brand via LEGACY_ARCH_SOURCE_TAG) let a flailing
  upstream be disabled from the PostHog UI in ~5s instead of a
  code-fix -> dev -> prod redeploy. Fail-open: any unresolved flag keeps the
  source live, so a PostHog outage can never black out decoding.

Phase 2 - guarded rollout primitive:
  isEnabled()/variant() with VIN bucketing, ready to ramp a new decode/parser
  path 0->100% behind a decode-*-v2 flag (recipe in feature-flags-strategy.md).

Phase 4 - remote-config ops tuning:
  prefetch-worker reads cfg-backfill-tuning to retune backfill
  batchSize/maxBacklog/businessHoursOnly live; malformed/missing -> the
  compiled-in constants.

POSTHOG_PERSONAL_API_KEY wired into the api + worker compose blocks (empty ->
flags inert, no added latency). Tests updated for the new constructor params.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 00:21:52 +03:00
20cd4fda01 feat(catalog): wire Fiat (p5fiat) browse — families→models two-step + de routing
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Fiat catalog browse returned 0 models because the generic single-endpoint P5
model-list flow can't express Fiat's two-level hierarchy and the drill defaulted
to the tr account (Fiat is licensed only on de-708171).

- fetchVehicleList: dispatch fiatp_parts/fiatt_parts to new fetchFiatVehicleList,
  which expands modelOverview (34 families) → models?modelFamily=N (model codes +
  year ranges) into flat catalog vehicles whose catalogPath is the maingroups
  endpoint. Verified live: 34 families → 123 models, end-to-end drill to parts+image.
- fetchMainGroups / fetchP5Restrictions: account-aware (resolveAccount → de + DE
  proxy for Fiat; tr unchanged for every other P5 brand) so browse maingroups no
  longer hit the tr demo/empty page.
- web: case-insensitive "/maingroup" gate so Fiat (lowercase /mdl/maingroups,
  already a maingroups endpoint) skips the empty restriction selector and loads
  categories directly.
- formatFiatYear: "(2016,2020)" → "2016-2020"; +unit tests.

Subgroups/parts/images already resolve account→de for Fiat (unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 19:52:14 +03:00
67513b356a chore(debug): revert p5fiat model-list probe
Finding: /p5fiat/extern/vehicle/models IS the endpoint (de-licensed, demo:false) but
returns 'Cannot parse null string' regardless of manufacturer/make/brand param — needs
an undiscoverable param from the P5 SPA session (launchCatalog.do flow). Requires a real
PL24 web-UI network capture to resolve. Turkish Tofaş NM4/Egea is not in this catalog
anyway, so catalog-browse value is European-Fiat-only. Kept the generic P5 endpoint
self-discovery fallback. Fiat VIN-decode (European) is unaffected and still works.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 18:19:30 +03:00
ca535c6fcf chore(debug): TEMP probe p5fiat models manufacturer param 2026-06-05 18:15:30 +03:00
1995ab6035 chore(debug): TEMP probe p5fiat model-list endpoints + launchCatalog 2026-06-05 18:11:23 +03:00
0e1c0a55d0 style(catalog): biome format fetch options in P5 endpoint fallback
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:02:27 +03:00
d918869742 fix(catalog): self-discover P5 model-list endpoint for unmapped backends
fetchVehicleList fell back to /extern/vehicle/modelfamilies for any backend
not in BACKEND_MODEL_PATH; p5fiat (Fiat) isn't mapped, so it returned 0
models and Fiat seeded nothing (0 catalog_vehicles on dev+prod). When the
primary path yields nothing, try the other known P5 listing endpoints and
use the first that returns models, logging which one worked so it can be
pinned. Only runs on the empty path → mapped backends unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:01:50 +03:00
0d64e22c8d feat(pl24): enrich P5 decode for non-VAG OEMs (SEV-2)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
parseVehicleResponse only read VAG/BMW vinfoBasic labels, so Jaguar/Land Rover/Toyota/MAN/Suzuki dropped engine+transmission and Mitsubishi's model showed an internal chassis code.

- engine/transmission: read brand labels (JLR Motor Tipi/Vites Kutusu, Toyota ENGINE 1/ATM,MTM + parens engine code, MAN Yedek motor/Şanzıman, Suzuki Motor No./Şanzıman numarası). - Mitsubishi model: prefer Araç/description (L200), not the internal Model code (KB4T 2500DIESEL...). - value normalize: unescape literal \- + collapse whitespace (was prNr-only) → fixes 'XJ 2010 \- 2019', '2005\-07', 'COROLLA   (TUP)'. VAG/BMW/Mercedes/Fiat unchanged. 40/40 pl24 specs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 10:48:39 +03:00
d575893447 fix(pl24): Mercedes year from 'Teslimat tarihi' (delivery date)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
p5daimler vinfoBasic has no model_yili/üretim tarihi — only "Teslimat tarihi"
(delivery). The parser ignored it, so year fell to the VIN 10th-char and was
wrong (WDD…1… → 2001 even for 2009/2015/2018 cars). Add "teslimat_tarihi" to the
date-year fallback. Live-verified: C 180→2009, E 250 BlueTEC→2015, E 350→2018.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:22:38 +03:00
94faa6cdcd fix(pl24): cleaner BMW model — append chassis only, drop redundant line token
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
"Seri" is "{line} {chassis} [{variant}]" and the trim already implies the line
("520i"→5, "X3 sDrive20i"→X3), so append only the chassis(+variant): "520i G30",
"X3 sDrive20i G01" (was "520i 5 G30" / the redundant "X3 sDrive20i X3 G01").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:55:22 +03:00
d3ff19ad6a fix(pl24): enrich BMW decode — chassis/generation, body, drive from vinfoBasic
BMW (p5bmw) decode was weak: model was just the trim ("520i") with no
chassis/generation, body_type empty, because BMW has NO prNr segment and keeps
that data in distinct vinfoBasic labels the shared parser ignored. Live-verified
fields: "Seri"="5 G30" (chassis), "Karoseri"="Limousine" (body), "Tahrik"="RWD".

- model: fold the generation ("Seri"/"Model tanimi") into the model when present
  and not already included → "520i 5 G30" (disambiguates E60/F10/G30 for parts).
- bodyType: fall back to vinfoBasic "Karoseri" when there's no prNr K8*.
- series: read "Seri"; driveType: read "Tahrik".
Year already comes from "Üretim tarihi" (P5 year fallback). VW/Audi (prNr) and
Mercedes ("Piyasa adı", no seri/karoseri) verified unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:47:00 +03:00
9809012be5 fix(pl24): correct p5fiat vinfoBasic label/value extraction
The Fiat vinfoBasic record carries the row under `values` like p5vwag, but the
inner field names are swapped: p5fiat uses values.key=<label>,
values.description=<value> (vwag uses values.description=<label>,
values.value=<value>). The first pass read values.description as the label, so
model fell back to the numeric description code ("319") and year to 0. Detect
the shape via values.key. Live-verified: ZFA Panda→"Panda POP 1.2 8V 69CV 5M E6"
/2014, Grande Punto/2009, 500L/2015. Spec fixture corrected to the real shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:12:22 +03:00
4a115db885 fix(pl24): wire Fiat as P5-modern /p5fiat (was dead LEGACY_FIAT /fca)
Fiat (fiatp_parts/fiatt_parts) was misconfigured as LEGACY_FIAT basePath /fca,
which 404s on every request — PL24 Fiat decode was dead. Live discovery
(de-708171) shows Fiat is a standard P5 Modern catalog at /p5fiat: directAccess
+ maingroups/subgroups/parts/images all match the existing P5 flow. Only the
vinfoBasic record shape differs ({key,description} vs {values:{description,value}}).

- types: fiatp_parts/fiatt_parts -> P5_MODERN, apiPath/basePath /p5fiat
- parseVehicleResponse: parse the p5fiat vinfoBasic shape; friendly model from
  "Model bilgisi"; year from MY / production date

Covers European (ZFA) Fiats + some commercial Tofas (fiatt). Turkish Tofas
passenger VINs (NM4, incl. Egea) are not in this catalog. de account separation
(resolveAccount Rule 1) unchanged; de auth handshake proxied, catalog data not.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:58:03 +03:00
45953f6dd5 fix(pl24): correct Opel/Vauxhall + Hyundai/Kia VIN decode via thin brand services
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Same shared-core + thin-brand pattern (P4BrandHooks). Both decoded with polluted models (Opel kept
the platform code "…: P10"; Hyundai kept the VIN breadcrumb), wrong VIN-char years, empty transmission.
Fix reads the vin-group info grid + title:
- Opel: model from <title> (segment after the platform code), year from Model yili, transmission from
  Şanzıman kodu, engine from Motor tipi. Verified 6/6 prod (ASTRA-J/2014, CORSA-D/2011, INSIGNIA-A, AGILA-A…).
- Hyundai/Kia: model from <title>, build-year from Üretim tarihi, transmission/body from the
  ENGLISH-labelled grid (plain lowercase — tr-locale would map I→ı and miss "TRANSMISSION").
  Verified (GETZ 02/2004/5 SPEED MT, RIO / STONIC 17/2019…).

Nissan deferred: both prod Nissan VINs are unresolvable upstream (PL24 returns "Model seçimi", no
model) — nothing to parse. Engine/categories/drill unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:49:34 +03:00
836b7c43a6 fix(pl24): correct Ford VIN decode (model/build-year/transmission from info grid) via thin brand service
Ford decoded with a polluted model ("Ford Nutzfahrzeuge {VIN}: Transit Connect - TC7…", from the
page title), a wrong VIN-char year, and empty transmission. The clean data is in the vin-group info
grid (Araç Hattı=model line, Üretim tarihi=build date, Vites Kutusu=transmission, Motor Tipi=engine,
Gövde Tarzı=body). New thin PL24FordService supplies parseFordVinInfo via the shared P4 brand hook;
orchestrator routes LEGACY_FORD to it. Engine/categories/drill unchanged.

Verified live vs 9 prod Ford VINs: 7 now decode clean model + correct build-year + transmission
(Transit Connect/2006, Mondeo/1997 CD4E Otomatik, Focus/2000, …) — VIN-char years were off by up to a
decade and transmission was empty for all. 2 VINs are upstream gaps (no Araç Hattı → unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:38:22 +03:00
50fd0b0e26 fix(pl24): correct Volvo/Polestar VIN decode (model from vinInfoTable) via thin brand service
Volvo decoded as "Volvo {VIN}" with no real model: the generic Ford-shaped
parseP4VehicleResponse reads window.vehicles/<title>/<h1>, but Volvo ships model/year/type in a
<table id="vinInfoTable"> caption/value grid (Model="V60 Cross Country (19-)", Model yili=2021,
Türü="V60 CC II"). 9 vehicles affected (3 dev + 6 prod).

- Add a per-brand vehicle-info hook (P4BrandHooks.parseVehicleInfo) to the shared P4 engine
  (PL24FordLegacyService); brand values win, generic fills gaps. Backward-compatible: no hook → identical.
- New thin PL24VolvoService supplies parseVolvoVinInfo (vinInfoTable parser); orchestrator routes
  LEGACY_VOLVO decode to it. Categories/drill unchanged (shared engine).

Verified live vs 6 prod Volvo VINs: all decode real models (S80/S60/S40/V40/EX40·XC40/V60 CC) +
correct years; drill intact (motor → 7 subgroups). First step of the per-brand split
(shared core + thin brand services).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:12:29 +03:00
223c4bc12f fix(pl24): correct PSA VIN decode via FI/VIN-indexed flow + cycle-correct model year
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
PSA (Peugeot/Citroën/DS) VIN decode was systemically broken: the catalog
vin-group page returns all families unfiltered, so decode fell back to the first
family/salesType (a manual base variant) — yielding "{Brand} {VIN}" model names,
empty transmission, wrong model year, and manual-only parts trees (automatic
gearbox parts missing). Reported for a 1999 Peugeot 106 automatic shown as a 2029
manual with no automatic parts.

- New self-contained PL24PsaService: consumes PL24's FI flow (vin.action →
  hintstoken → FI page → json-vin-main-groups → json-vin-illustrations →
  vin-image-board). Reads model/year/transmission from the FI identification
  table; builds the VIN-indexed parts tree (correct per actual VIN). Does not
  touch Ford/Volvo/Nissan/Opel/Hyundai-Kia/Fiat.
- Orchestrator + categories.service route PSA VIN decode/drill to the new service.
- Cycle-correct extractModelYear in @sase/shared (X→1999, not 2029): resolve the
  30-yr VIN year code to the most-recent plausible year (≤ now+1); dedupe 6 copies.

Validated live against 13 already-decoded PSA VINs: 12/13 full trees with real
model/year/transmission; automatics correctly detected (106 BVA, 206 AL4, 3008 BVA8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 12:27:04 +03:00
1e3953417e perf(backfill): stop the prefetch worker from throttling itself (Tier 1)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
The worker's own upstream fetches called touchActivity(), setting the
prefetch:activity:<source> cooldown key (TTL 300s) that checkCooldown then
honoured — so after each fetch the worker paused itself for up to ~5 minutes
(re-checking every 60s, ~5 empty cycles per key). At ~1 fetch / 5 min the
3387-job backlog needed ~6 days to drain.

- Wrap each worker job in an AsyncLocalStorage backfill context; touchActivity
  skips the cooldown key when invoked from the worker, so the cooldown reflects
  only real user requests (worker yields to users, never to itself).
- Cooldown TTL 300s -> 90s (a request 5 min ago isn't "active").
- checkCooldown pauses for the key's actual remaining TTL (one wait) instead of
  a fixed 60s re-check loop.

No extra upstream load — only removes the worker's self-imposed idle time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 18:23:54 +03:00
5e9d9050b9 fix(pl24): stop .action shadowing PSA illustration/parts dispatch
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
isP4LegacyPath matched any ".action" path, shadowing the PSA
json-illustrations.action / image-board.action dispatch in
fetchSubGroupsByPath and fetchPartsByPath. Every PSA (Citroen/Peugeot/DS)
drill below main-group level fell through to the Ford/Fiat legacy parser,
which cannot parse PSA JSON, so it returned empty. PSA vehicles decoded
since the catalog module landed (72c0de6) showed categories but 0 parts
(41/43 affected). Exclude /psa/ from isP4LegacyPath so these paths reach
fetchPsaIllustrations / fetchPsaParts. Heals existing vehicles on demand;
no re-decode needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 00:28:41 +03:00
543be19261 fix(pl24): read MAN category names from mainGroupDescription/groupDescription
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
MAN truck (p5man) main-vin and sub-vin endpoints return human-readable
names in values.mainGroupDescription and values.groupDescription. Our
parsers only checked the standard caption/description fields used by
VW/Renault/etc., so MAN categories were stored with raw numeric codes
("0", "1", ..., layoutIds like "2884606") as names.

After this change, the user sees proper Turkish names like
"MOTOR, SOĞUTMA SİSTEMLERİ" and "ANTEN". Existing brands fall through
the same field chain as before — captionMatch[2] takes precedence,
keeping their behavior unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 09:10:18 +03:00
Semih
7ffff32cac chore(pl24): remove [imgdbg] diagnostic log
Diagnostic served its purpose: confirmed that PL24 bomOverviewlist
URLs (e.g. illustrationId=4336125, "Alternatöre genel bakış" with
PR-code filters) return only a records array with no images field —
upstream genuinely has no schema illustration for these overview
tables. Frontend UX for this case is handled separately.
2026-05-14 20:47:03 +00:00
Semih
7f0f17580e chore(pl24): log full response shape when images field is missing (temp diagnostic) 2026-05-14 20:33:24 +00:00
Fusion
f4fea1e429 feat(FN-094): add comment line for deployment verification
Some checks failed
Sync dev → Gitea / Mirror dev to Gitea (push) Has been cancelled
- Added a comment line to main.ts for deployment verification purposes
2026-05-11 02:07:03 +00:00
Sase Dev
72c0de65de docs: update INDEX.md + add catalog module, Ford/PSA legacy catalog, shared vehicles
- CatalogModule: VIN-less PL24 catalog browser (brands, models, categories, parts)
  - Supports P5 Modern (REST) and P4 Legacy (Ford, PSA) catalog architectures
  - Ford variant selector (model-year/engine/gearbox), PSA variant selector (body/engine/gearbox)
  - New API endpoints: ford-config, psa-bodies, psa-engines, psa-gearboxes, brands/:name/catalogs
- Shared vehicles: vehicles table decoupled from users via userVehicles junction table
- PL24 Ford Legacy service: comprehensive HTML-scraping for Ford/PSA/Hyundai/Kia/Nissan/Opel/Volvo
- PL24 types and service updated for P4 Legacy brand support
- Categories/parts service updated for dual FK (vehicleId + catalogVehicleId) pattern
- Catalog browser frontend routes and components
- docs/INDEX.md: updated with all new endpoints, components, hooks, routes (2026-03-02)
- docs/pl24-catalog/: per-brand catalog exploration docs
- scripts/migration-shared-vehicles.sql, pl24-catalog-explorer.js, posthog-dashboards.sh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 00:31:15 +00:00
Sase Dev
f1a27810db feat: add parts catalogs integration, catalog prefetch worker, and vehicle select modal
Integrate external parts catalogs API with auth service, add BullMQ-based
catalog prefetch worker for background data caching, expand vehicles service
with shared vehicle support, and add vehicle select modal to frontend.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:14:36 +00:00
Sase Dev
f3f3f57756 feat: propagate PL24 part metadata, improve auth UX with Google sign-in prominence
- Add unavailable/remark/modelCodes/presel fields to categories and parts DB schema
- Pass PL24 unavailable flag through pipeline instead of filtering out records
- Show unavailable categories/parts at reduced opacity in grid, tree, and parts panel
- Display part remark and model codes as secondary info in parts table
- Move Google sign-in button above email form on login/register pages with branded icon
- Add public email existence check endpoint for better login error messages
- Update INDEX.md documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 11:11:28 +00:00
Sase Dev
4a06ba5fdb feat: Ford legacy support, EMEX browser pooling, collapsible sidebar
- Add PL24 Ford legacy service for fordt_parts architecture
- Refactor EMEX to use persistent browser pool instead of per-call instances
- Make vehicle decode resilient: fallback to PL24 when Corgi doesn't recognize VIN
- Add collapsible sidebar with persistent user preference
- Improve brand access guard and categories service
- Add debug/test scripts for VIN e2e testing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:25:06 +00:00
Sase Dev
996d614d50 feat: admin user creation, Vite migration, dialog fix, pl24 integration
- Add POST /admin/users endpoint with password hashing and role support
- Add user creation dialog to admin users page
- Migrate web from Next.js to Vite + TanStack Router
- Fix Dialog component positioning for Tailwind CSS v4
- Add @source directive for @sase/ui package scanning
- Add pl24 integration parsers and vehicle decode flow
- Backup old Next.js app to apps/web-nj

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:24:58 +00:00
Sase Dev
56a3c8bfaa feat: sase.tr v2 full application implementation
Complete rewrite of sase.tr VIN lookup platform with modern stack:

Backend (NestJS 10 + Drizzle ORM + PostgreSQL + Redis + BullMQ):
- 34 DB models (core + PL24 + EMEX schemas)
- Auth via Better Auth (email/password + social)
- Brands, Plans, Subscriptions, Payments (iyzico + EFT)
- VIN decode orchestration (Corgi + PL24 + EMEX + NHTSA)
- Interactive schema viewer backend (MinIO storage)
- EMEX scraping integration (Puppeteer + BullMQ workers)
- Translation module (EN→TR automotive dictionary)
- Admin dashboard API (stats, user mgmt, payment approval)
- Rate limiting, Helmet security, file upload validation

Frontend (Next.js 15 + Tailwind v4 + shadcn/ui + TanStack Query + Zustand):
- 20 routes: auth, dashboard, VIN search, schema viewer, admin
- Interactive schema viewer with zoom/pan/hotspot highlighting
- Subscription management with brand selector
- Payment flow (iyzico 3D Secure + EFT with receipt upload)
- i18n support (TR/EN)
- Error boundaries, loading skeletons, 404 page

Infrastructure:
- 85 tests (52 backend + 33 frontend, Vitest)
- CI/CD (GitHub Actions: lint, typecheck, test, build, deploy)
- Zero-downtime deploy script (PM2)
- Env validation script

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 02:03:56 +00:00