Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma strängvärde byggs med konkatenering i stället för att matcha mönstret.
82 lines
3.3 KiB
SQL
82 lines
3.3 KiB
SQL
-- Migration: api_v1_async_operations
|
|
--
|
|
-- Substrate for the v1 async-operation lifecycle. Distinct from
|
|
-- `pending_operations` (which is the "stage and wait for human approval"
|
|
-- substrate used by the MCP write tools) — this table tracks long-running
|
|
-- jobs initiated by v1 callers that the API needs to report progress + final
|
|
-- status against, without blocking the request cycle.
|
|
--
|
|
-- Response contract (per the Phase 4 plan):
|
|
-- POST returns 202 with { operation_id, status: 'queued', poll_url, webhook_event }
|
|
-- GET /v1/operations/{id} returns { operation_id, type, status, progress, result, error, started_at, completed_at }
|
|
--
|
|
-- Used by:
|
|
-- - POST /fiscal-periods/{id}/close
|
|
-- - POST /fiscal-periods/{id}/year-end
|
|
-- - POST /fiscal-periods/{id}/currency-revaluation
|
|
-- - POST /imports/sie (future PR)
|
|
-- - POST /imports/bank (future PR)
|
|
-- - POST /salary-runs/{id}/generate-agi (future PR)
|
|
--
|
|
-- Phase 4 PR-2 ships this with synchronous execution inside the POST handler
|
|
-- (status flips queued → running → succeeded/failed in one request cycle).
|
|
-- A future PR can introduce a Vercel cron worker that picks up `queued` rows
|
|
-- and processes them out-of-band; the row format remains stable.
|
|
|
|
CREATE TABLE IF NOT EXISTS public.operations (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Tenancy
|
|
company_id uuid NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
|
|
user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
|
|
-- Operation identity
|
|
operation_type text NOT NULL,
|
|
-- Free-form tag for which v1 surface initiated this op (e.g.
|
|
-- 'fiscal_periods.close', 'fiscal_periods.year_end', 'imports.sie').
|
|
-- The set of accepted values is open by design — adding a new async
|
|
-- endpoint should not require an enum migration.
|
|
|
|
-- Lifecycle
|
|
status text NOT NULL DEFAULT 'queued'
|
|
CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
|
|
started_at timestamptz,
|
|
completed_at timestamptz,
|
|
|
|
-- Payload
|
|
params jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
progress jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
result jsonb,
|
|
error jsonb,
|
|
|
|
-- Audit
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE public.operations ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Members of the company can read their company's operations. Only the
|
|
-- service role writes (via the v1 wrapper); no anon/authenticated INSERT/
|
|
-- UPDATE/DELETE policy is exposed.
|
|
CREATE POLICY "operations_select"
|
|
ON public.operations FOR SELECT
|
|
USING (company_id IN (SELECT public.user_company_ids()));
|
|
|
|
CREATE TRIGGER operations_updated_at
|
|
BEFORE UPDATE ON public.operations
|
|
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
|
|
|
|
-- Indexes:
|
|
-- - Polling: GET /v1/operations/{id} is point-lookup on PK.
|
|
-- - Listing by company + recency for future GET /v1/operations endpoint.
|
|
-- - Worker queries (future cron): pick up oldest `queued` ops per company.
|
|
CREATE INDEX idx_operations_company_created
|
|
ON public.operations (company_id, created_at DESC);
|
|
|
|
CREATE INDEX idx_operations_status_queued
|
|
ON public.operations (created_at)
|
|
WHERE status = 'queued';
|
|
|
|
NOTIFY pgrst, 'reload schema';
|