feat(phase6a): behavioral insight pipeline ingestion + tagging + compression

- prisma: sessions_meta, compressed_sessions, ingestion_watermarks
- worker: PostHog client (eu.i.posthog.com), heuristic filter
- worker: BullMQ insight-pipeline queue (ingest 5min / tag 2min / compress 3min)
- worker: tagger (bug_suspected, ux_friction, upgrade_hesitation, etc.) + severity scoring
- worker: rrweb -> semantic timeline transform + 8-pattern PII sanitization
- worker: fingerprint hash + MinIO upload (bucket: insight-compressed)
- web: /insights pipeline dashboard + session timeline viewer
- sidebar: Insights nav entry

LLM (Phase 6b), insight inbox, cost dashboard, GitHub loop deferred to later phases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Semih
2026-05-13 20:58:36 +00:00
parent 608ab0e6c7
commit 1a7a1b5787
17 changed files with 3790 additions and 0 deletions

View File

@@ -110,3 +110,69 @@ model AuditLog {
@@index([actorUserId])
@@index([projectKey])
}
// ---------- Phase 6a: Behavioral Insight Pipeline ----------
model SessionMeta {
id String @id
projectKey String
userIdHash String?
isAuthenticated Boolean @default(false)
subscriptionTier String?
startedAt DateTime
durationMs Int
pageviewCount Int @default(0)
clickCount Int @default(0)
errorCount Int @default(0)
rageClickCount Int @default(0)
deadClickCount Int @default(0)
network5xxCount Int @default(0)
network4xxCount Int @default(0)
startUrl String?
promotionReasons String[]
tags String[]
severity String?
score Int?
rawMetadataUrl String?
status String @default("pending_signal")
fingerprint String?
processedAt DateTime?
createdAt DateTime @default(now())
compressed CompressedSession?
@@index([status, createdAt])
@@index([fingerprint])
@@index([projectKey, status])
@@index([userIdHash, startedAt])
@@map("sessions_meta")
}
model CompressedSession {
sessionId String @id
fingerprint String
semanticTimelineMinioKey String
tokenCountInput Int
tokenCountEstOutput Int
compressionRatio Float?
sanitizationMatchCount Int @default(0)
sanitizationBreakdown Json?
isBundle Boolean @default(false)
bundleSessionIds String[]
readyForAnalysisAt DateTime @default(now())
createdAt DateTime @default(now())
session SessionMeta @relation(fields: [sessionId], references: [id], onDelete: Cascade)
@@index([fingerprint])
@@map("compressed_sessions")
}
model IngestionWatermark {
projectKey String @id
lastPolledAt DateTime
posthogCursor String?
updatedAt DateTime @updatedAt
@@map("ingestion_watermarks")
}