Commit Graph
5 Commits
Author SHA1 Message Date
Matthew Meszaros f48d51bf16 feat: AI contact research agent that gathers cited web findings per contact with sync and background-batch runs - contact_research_runs table plus a strict save_research schema (every signal and public_artifact must carry a url, confidence high/medium/low, signals<=5 hooks<=3, reject-and-reprompt once then fail), a text/template runtime prompt injecting org voice, contact record, objective, and 5-search/6-fetch budgets, a research service that drives search_web/fetch_url through the provider loop and charges 2 credits on save (billable even for nothing_found, refund-free since charged only on save, balance and abuse-cap pre-checked so a capped org never does free work), POST/GET /contacts/:id/research plus a 500-cap /contacts/research/batch draining through a bounded pool of 4 workers over FOR-UPDATE-SKIP-LOCKED claims (no new Kafka), an org-scoped AI_RESEARCH_PROGRESS realtime event gated to view_contacts, APIPermAIResearch bit 23, a ContactEdit Research tab and a ContactsTable bulk Research action, and docs; also org-scopes every credit and research idempotency key so a client-supplied Idempotency-Key can never replay across tenants 2026-07-13 19:34:11 +02:00
Matthew Meszaros 3076cff5d6 feat: add api request ids 2026-05-30 04:26:12 +00:00
Matt b633e326e5 feat(throttle): per-day creation throttles for campaigns/mailboxes/orgs
The HardCap* constants stop "you have 5000 campaigns on this org"; the
throttles in this commit stop "you created 1000 campaigns today on a
fresh unlimited account." Different shape, different abuse, different
mechanism — Redis-backed per-(scope, resource, UTC-day) counters that
reset by key design at midnight UTC, no scheduled job needed.

New service internal/app/dailythrottle:
  - CheckAndIncrement(scope, resource, ceiling) atomically bumps the
    counter and returns errx.TooManyRequests when the post-increment
    value exceeds the ceiling.
  - 25h TTL so the key always expires after the day rolls over even
    if the process restarts before midnight.
  - Fail-open when the cache is absent (jobs/tests) so creation paths
    that haven't been wired with a cache still work.

Caps (config.DailyThrottleNew*):
  - 20 new campaigns/org/day
  - 5  new mailboxes/org/day
  - 3  new workspaces/owner/day

Wired into three creation paths:
  - campaign.Create — scoped on the orgID when present
  - email.OAuthFinish + email.OnboardSMTPIMAP — scoped on the orgID;
    fires only at actual create, not OAuthStart, so retrying a failed
    OAuth flow doesn't burn the day's budget.
  - organization.Create — scoped on the owner uuid (the org doesn't
    exist yet)

Adds errx.TooManyRequests (HTTP 429) since no caller had one before.

emailService gains WireThrottle alongside the existing WireWebhooks
pattern so jobs / tests can build the service without a cache. Same
treatment in main.go.
2026-05-28 13:34:01 +02:00
Máté Mészáros (Laptop) 6adb4cdd5a Organization, Subscription, Inqueries, limits. 2026-01-27 05:55:48 +01:00
Matthew Meszaros 772c19820d New Repository: Add Backend Code 2026-01-17 14:11:14 +00:00