feat(migrations): create apify_scraper_runs ownership map (chat#1840)

Closed
SW
4mo ago
+29-0

Part of recoupable/chat#1840 item 1 (account-scope the scrape-results endpoint). Hard dependency: this migration must merge + apply before the api PR that reads/writes the table. Contract: docs#262.

What

public.apify_scraper_runs — ownership map written at scrape start by POST /api/socials/{id}/scrape, read by the GET /api/apify/runs/{runId} validator:

columntypenotes
run_idTEXT PKApify run id — natural key, one owner per run
account_idUUID NOT NULLaccount whose key started the run
social_idUUIDscraped social profile (audit, denormalized)
created_attimestamptz default now()
  • Loose ids, no FKs — same rationale as email_send_log: an ownership log shouldn't cascade-delete with accounts; a dangling row just degrades that run to admin-only polling.
  • Index on account_id for audits; reads are by PK.
  • RLS enabled, no policies (service-role access only), matching neighboring service-written tables.

Why

Apify run ids carry no account scope, so the results endpoint is admin-only — agents can start scrapes they can never read (7/7 Forbidden polls in the issue's evidence). This table gives the endpoint an ownership chain to authorize against.

šŸ¤– Generated with Claude Code


Summary by cubic

Create public.apify_scraper_runs to map Apify run IDs to the owning account, enabling account-scoped access for GET /api/apify/runs/{runId} (chat#1840). Must deploy before the API that reads/writes this table.

  • Migration
    • New table: run_id TEXT PK, account_id UUID NOT NULL, social_id UUID, created_at timestamptz default now().
    • Index on account_id; reads by PK.
    • RLS enabled with no policies (service-role only). No FKs to avoid cascade deletes.