|
|
||
|---|---|---|
| .. | ||
| dashboard-network | ||
| frontend-client | ||
| mcp-server | ||
| shared | ||
| website-backend-users | ||
| website-frontend-users | ||
| README.md | ||
| services.yaml | ||
user-data
Parent feature: cross-domain, cross-corp visitor flow on the lilith-platform.live mesh.
Absorbs what used to be @features/analytics/ and adds two missing layers — a
server-side cookie-free visitor identity and a first-class corp/domain taxonomy
— so a visitor's journey across adulttherapytour.com → maisonsansonnet.com → transquinnftw.com becomes a single SQL join. Deployed surface: quinn.data
(data.transquinnftw.com).
Shape
| Path | Package | Role |
|---|---|---|
shared/ |
@lilith/analytics-client |
Browser client core — batch queue, attribution, device collector. No React dep. |
frontend-client/ |
@lilith/analytics-client-react |
React provider + hooks (useAnalytics, useFunnelEvents, usePageViewTracking). |
website-backend-users/ |
@lilith/analytics-website-backend |
Stateless BFF proxy. Forwards /track/* to the collector (or quinn-api relay) and /api/* (after composition) to quinn-api analytics query surface. Both dev and prod use quinn-api + the prod lilith_analytics DB (no dev DB). Does NOT do identity — that lives in the collector. |
website-frontend-users/ |
@lilith/analytics-website-users |
Dashboard SPA at data.transquinnftw.com/. Cross-Corp Flow tab is TODO. |
beacon/beacon.js |
(single static file, no package) | ~4 KB cookie-free IIFE for static-HTML sites. Served by quinn.data nginx at https://data.transquinnftw.com/beacon.js. Staged into the SPA dist by quinn.data/deploy.sh step 1a. |
Identity & dimensioning — lives in the collector, NOT here
The identity hash and corp/domain resolution run inside the @analytics collector
(or via quinn-api public analytics relay in consolidated paths)
at ~/Code/@applications/@analytics/services/collector/src/tracking/:
identity.service.ts—visitorIdDaily(ip, ua, lang) = sha256(daily_salt ‖ ip ‖ ua ‖ lang). Salt rotates at 00:00 UTC, stored invisitor_salts, purgeable after 7 days.domain-resolver.service.ts— Origin →domainsrow →(corp_id, domain_id). Cached in-process; reloaded on cache miss.- Both are wired into
TrackingService.trackView()and stamp everyraw_eventsrow.
Schema lives in @applications/@analytics/services/api/migrations/1747200000000-AddVisitorIdentityAndCorpDomain.ts. Seed mirror: @applications/@analytics/infrastructure/seed-cross-domain.sql.
This split is intentional: identity logic has exactly one consumer (the collector),
so publishing it as a @lilith/* package would be premature abstraction.
Visitor identity model
- No cookies. No localStorage. No fingerprint canvas.
visitor_id_daily = sha256(salt_today ‖ X-Real-IP ‖ User-Agent ‖ Accept-Language).- Same visitor → same id across all our domains within a UTC day.
- Salt rotates at 00:00 UTC; older salts are purged → historical re-identification is mathematically impossible.
- Tab-scoped
sessionId(client-side, in-memory) is preserved for per-tab funnels.
Corp / domain taxonomy
Every event row carries corp_id and domain_id. Seed:
| corp slug | legal_name |
|---|---|
lilith-apps-ehf |
Lilith Apps ehf |
att |
Adult Therapy Tour |
sansonnet |
Maison Sansonnet |
transquinnftw |
transquinnftw |
Seeded domains include adulttherapytour.com, adulttherapy.tours, apa.singles,
fuckatapa.com, fuckmeatamericanpsychiatricassociation.com, maisonsansonnet.com,
transquinnftw.com, tqftw.com, atlilith.com, trustedmeet.com. See the
migration file for the full list.
Instrumented sites
| Site | Instrumentation | Domain row |
|---|---|---|
| Landing | React provider (AnalyticsProvider) |
atlilith.com, trustedmeet.com |
| Provider website (transquinnftw.com) | React provider | transquinnftw.com |
ATT canonical (adulttherapytour.com) |
<script> beacon in 4 HTMLs under adult-therapy-tours/web/ |
adulttherapytour.com |
| ATT SEO bait | <script> beacon in apa-singles, fuckatapa, fuckmeat |
per hostname |
| Sansonnet (preview, pre-prod) | <script> beacon in 4 HTMLs under .project/previews/cocotte-umbrella/sites/sansonnet/ |
maisonsansonnet.com |
Not yet instrumented: futa-singles SEO surface (no live domain yet), cocotte
brand under the sansonnet umbrella.
Known gaps
- The rich dashboard query surface (sessions/metrics, engagement/pages, funnels, etc.) is now implemented inside quinn-api (using direct SQL against the prod lilith_analytics DB). The old separate Nest @analytics query API (:4003) is no longer used by the website analytics BFF/dashboard.
- CORS for
/beacon.jsconsumers — verify on canary that the collector at:4001accepts POSTs from the new origins (adulttherapytour.com,apa.singles,fuckatapa.com,fuckmeatamericanpsychiatricassociation.com,maisonsansonnet.com). The existing analytics-client atatlilith.comandtransquinnftw.comalready works, suggesting the collector emitsAccess-Control-Allow-Origin: *— but confirm before declaring done. - Cross-Corp Flow dashboard tab is not yet built (deferred to a follow-on objective).
- Pre-existing typecheck error in
tracking.controller.tsline 59 (doNotTracktype mismatch inClientDeviceDto) — unrelated to this work but blockstsc --noEmiton the collector. Skipped in this objective.
Privacy posture
- No cookies, no localStorage, no fingerprinting.
- IP is processed (for the daily hash) but never stored — only the 32-byte sha256 digest persists alongside events.
device-enrichment.serviceseparately stores anipHashfor geo/bot detection; that is unchanged and unrelated tovisitor_id_daily.