- Tiered find-or-create inside postgresClient.transaction (Pitfall 2 — campaigns.campaign_key has no UNIQUE constraint): Tier 1 Message-ID, Tier 2 attachment-hash/URL-domain + subject + sender + 24h, Tier 3 sender + normalized subject + client + 24h (CAMP-01) - Match path bumps report_count/last_seen_at and links reports.campaign_id without creating a second campaign; no-match path inserts a new campaigns row keyed by the strongest available tier signal (CAMP-02) - skipIfAlreadyGrouped short-circuits before the transaction (D-08); the /analyze route path always re-runs full tiered matching - Every tier query excludes the report's own id (r.id != $n) so a self-match against a report's own messages/indicators can never double-increment its already-linked campaign on re-run - D-07 doc comment states the Tier-3-only automatic-path limitation: parseAndStoreMessage is not wired into the webhook/cron path this phase |
||
|---|---|---|
| .. | ||
| hooks | ||
| services | ||
| types | ||
| utils | ||
| auth-client.ts | ||
| auth-utils.ts | ||
| auth.ts | ||
| bootstrap.ts | ||
| permissions.test.ts | ||
| permissions.ts | ||
| status-registry.ts | ||
| utils.ts | ||