Formbricks CE turned out to gate person-based targeting (setUserId/attributes
→ 403 enterprise) — the exact flexibility surveys need. PostHog already holds
the person properties, so surveys move back there in API mode: posthog-js
evaluates eligibility (event triggers, targeting flags like
subscription_status=active, wait periods, per-distinct_id dedup) via
getActiveMatchingSurveys, and we render the popover ourselves — zero PostHog
branding, sase.tr dark-theme styling.
- lib/surveys.ts: display manager + capture payload builders that mirror
posthog-js's own "survey shown/dismissed/sent" shapes exactly
($survey_response_<qid>, $set $survey_dismissed/<id>[/iter], seenSurvey_*,
lastSeenSurveyDate) so the PostHog Surveys results UI works unchanged
- components/survey-popover.tsx: single_choice (+Diğer), open text, rating/NPS
- posthog.ts: capture/pageview/identify now schedule survey checks; register
deploy_env (dev.sase.tr ships the key now → staging traffic is filterable)
- remove @formbricks/js, its CSP entries and build args
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Site-wide live-chat widget served from the self-hosted Chatwoot at
destek.sase.tr, with verified user identity and vehicle context.
- apps/web: lib/chatwoot.ts loads the SDK lazily (mirrors the PostHog
init pattern), init in main.tsx, identify logged-in users in __root
via a server-computed HMAC, and attach the viewed vehicle (VIN/brand/
model) as contact custom attributes on the vehicle detail page.
- apps/api: GET /api/chatwoot/identity (AuthGuard-protected) returns
HMAC-SHA256(user.id) so the widget can use verified identity.
- env: VITE_CHATWOOT_BASE_URL + VITE_CHATWOOT_WEBSITE_TOKEN (build-time,
wired through docker-compose.coolify.yml build args + Dockerfile ARG)
and CHATWOOT_HMAC_TOKEN (api runtime). All optional — widget and
endpoint no-op when unset.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pixel ID 1904240520247944 (sase.tr) created on ad account
act_1227112768351770. Lazy-injected like PostHog so it stays off
when VITE_META_PIXEL_ID is unset. Tracks PageView on every route
change, CompleteRegistration on email/Google signup, and
InitiateCheckout on Stripe button click (value in TRY).
Coolify env: set VITE_META_PIXEL_ID=1904240520247944 before next
deploy so it gets baked into the Vite build.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
EMEX-decoded vehicles surfaced empty category pages on prod because two
runtime prerequisites were absent from the production image:
1. `scripts/emex-vin-scraper.js` was never copied — the build stage's
`COPY . .` brings it in but the production stage only cherry-picks
`apps/api/dist`, `drizzle`, and `start.sh`. Every EMEX leaf hit
therefore failed with "Scraper file not found at: /app/scripts/…"
and the category page rendered "Bu kategori icin parca bulunamadi."
2. `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium-browser` was
exported in the Dockerfile but never reached `chromium.launch()` —
that env var is consumed by `playwright install`, not at runtime.
Playwright fell back to its bundled headless-shell cache path
(`/root/.cache/ms-playwright/chromium_headless_shell-*/…`) which
does not exist on the alpine image, so even with the scraper file
present the browser pool init would have kept failing.
Fix:
- Dockerfile: `COPY --from=build /app/scripts ./scripts`.
- `emex.browser.ts` + `parts-catalogs-auth.service.ts`: read
`process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` and pass it as
`executablePath` to `chromium.launch()` when set.
Verified on prod container: `ls /app/scripts` → missing pre-fix; the
binary at `/usr/bin/chromium-browser` exists, so the env-var hand-off
will resolve cleanly once the new image lands.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add multi-stage Dockerfile (node:22-alpine, pnpm, Chromium for Playwright)
- Add docker-compose.coolify.yml with api, worker, redis services
- Add @nestjs/serve-static for serving Vite frontend from NestJS
- Add .dockerignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>