The record
What answers underneath the API — Postgres functions, edge functions, and scheduled work.
The API at https://api.intern.kim/v1 is the surface a caller is meant to use.
Underneath it is Postgres, and a good deal of internkim is written there rather
than in the web app: a tool like attendance_add resolves the caller, decides
whether they may write, and either writes or turns the request into something an
administrator was asked, all inside one function.
That has a cost. A rule written in SQL is invisible to the TypeScript above it, so the two drift unless the rule is stated once. A tool schema that demands a field the function does not refuses the call before the record sees it.
The lists of functions are generated from a database with every migration applied, so they say what is actually there.
What the tables mean
The decisions behind the schema, and the rules a caller keeps
Every RPC
Every function PostgREST exposes, and who may call it
Edge functions
The Deno functions beside the record, and which verify a JWT
Scheduled work
What pg_cron runs with no caller
Reading the tables
Callable by
The EXECUTE privilege, which is only the first gate. Row level security still
applies to every table a function touches, and most functions gate themselves
besides: member_leave_days_set raises unless public.is_company_admin()
holds, whoever called it.
Security
An invoker function runs as the caller, so row level security answers for it.
A definer function runs as its owner and can see past those policies. That is
how a function returns one person's leave balance without opening the whole
table, and it means the function's own body is all that stands between a caller
and everything it can reach.
The schema of record is supabase/migrations, and
What the tables mean explains the tables.
Running it locally
The local stack is the Supabase CLI's native runtime, with no Docker. tools/with-local-plane
starts it, holds it for one command at a time and stops it after fifteen idle minutes.
tools/with-local-plane supabase db reset # schema and fixtures
tools/with-local-plane supabase test db # pgTAP
cd web && ../tools/with-local-plane bun run dev # the web app against itThe reset alone gives a company to sign into, as [email protected] with
seed-password. Fixtures live only in supabase/seed.dev.sql, so a reset wipes
anything that file does not carry. Run supabase test db after every schema change:
SQL function bodies resolve at call time, so a rename in the migration that created a
function breaks it silently, and pgTAP is what notices. A migration that creates a
table must also grant it, because anon, authenticated and service_role start with
no privileges on a fresh database.