Loading...
Loading...
Standard for exposing business logic as a uniform, agent-operable API. Postgres business actions live under a dedicated `api` schema with a fixed success envelope ({data, effects, warnings}), RFC 7807 errors, mandatory Idempotency-Key on mutations, SECURITY DEFINER auth, and preview/confirm for heavy ops. Use when creating or exposing a business action / RPC / api endpoint / MCP tool, or when reviewing one. Forward-only from 2026-06-16.
npx skill4agent add jpborrelli/wachines-plugin-ironman rpc-api-contractWhy this exists (canon): the blocker to exposing our logic to agents was never "Postgres vs TypeScript" — it was the lack of a uniform contract (inconsistent naming, heterogeneous return types, no envelope, uneven idempotency). This skill is the operating procedure; the full rationale and the LaPyme benchmark live in the company brain page+estrategia/caso-lapyme. We assemble public conventions: Google AIP (resource-oriented + custom methods), RFC 7807/9457 (errors), Stripe / IETF Idempotency-Key, PostgREST api-schema.productos/profundizacion-tecnica/rpc-contract
rpc_*fn_ web UI · WhatsApp agent · MCP · cron ← channels (each a thin adapter)
│ all call the same core
▼
schema `api` = business actions (this contract) ← single definition
▼
public / private / <domain> schemas = internal logic, triggers, helpersapi.*api.*mcp.*api.*apiapi.<verb>_<noun>crear_actualizar_confirmar_anular_revertir_listar_obtener_calcular_…_previewfn_voidapi.*jsonb{ "data": { "...": "the affected resource(s): ids, amounts, state" },
"effects": { "...": "what the command changed, grouped by domain" },
"warnings":[ { "code": "STOCK_NEGATIVO", "message": "..." } ] }data{}nulleffectsreferences/<project>.mdeffectsoksuccessRETURNS voidapi.*RAISE EXCEPTIONRESOURCE_NOT_FOUND: educador % no existeapplication/problem+json{type, title, status, detail, code}MAYUS_SNAKELIQUIDACION_PERIODO_CERRADOp_idempotency_keyINSERT … ON CONFLICTIF EXISTS[IDEMPOTENT: ON CONFLICT (...)][NOT IDEMPOTENT: caller guarantees single invocation]SECURITY DEFINERSET search_path = ''establecimiento_idid_hubCOMMENT ON FUNCTIONapi.*effectsdb-reviewer…_previeweffectsconfirmar_…api.*_v2apiapi_v1create or replace function api.crear_<noun>(
p_body jsonb,
p_idempotency_key text
) returns jsonb
language plpgsql
security definer
set search_path = ''
as $$
declare
v_actor <type> := <resolve from session, NOT from p_body>; -- R6
v_id <type>;
v_effects jsonb := '{}'::jsonb;
begin
-- validate (read-only) → RAISE 'CODE: detalle' on failure (R4)
insert into <domain>.<table> (...)
values (...)
on conflict (<idempotency unique key>) do nothing -- R5
returning id into v_id;
if v_id is null then
select id into v_id from <domain>.<table> where <idempotency key> = ...;
end if;
-- collect side-effects into v_effects, grouped by domain (R3)
return jsonb_build_object(
'data', jsonb_build_object('<noun>_id', v_id, 'estado', '...'),
'effects', v_effects,
'warnings', '[]'::jsonb
);
end; $$;
comment on function api.crear_<noun>(jsonb, text) is
'Crea <noun>. [IDEMPOTENT: ON CONFLICT (<key>)]. effects: {<dominios>}.';effectsapireferences/<project>.mdreferences/perennia-backoffice.mdreferences/gestionganadera.mddb-reviewersupabase-postgres-best-practicesapi.*