The database is the map. All coordinates areDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/astrxnomo/manizalesdepie/llms.txt
Use this file to discover all available pages before exploring further.
geography(point, 4326) columns managed by PostGIS. Row-level security (RLS) policies guard every table; security_invoker views ensure those policies apply even through view queries. The migration that creates the full schema is supabase/migrations/20260813000000_init.sql.
PostGIS columns serialise as WKB hex strings through PostgREST — they are not usable as map coordinates directly. Always read site and work order locations through the
site_public and work_order_public views, which project longitude and latitude as numeric columns. Both views are declared security_invoker = on, which means RLS policies on the underlying tables apply to whoever is querying the view.Enums
The schema defines nine PostgreSQL enum types. Enum values are never deleted once inserted — existing rows would fail validation — so the application layer is responsible for ignoring values that are no longer shown in the UI.| Enum | Values |
|---|---|
user_role | visitor, contributor, curator |
municipality | manizales, villamaria |
site_type | collection_point, shelter, blood_donation, vet_clinic, water_point, medical_post, census_point† |
site_status | open, full, closed, unknown |
item_mode | needed, not_accepted, sufficient |
work_order_category | debris_removal, animal_rescue, structural_risk, supplies, water, other |
work_order_status | unclaimed, claimed, attended†, closed_completed, closed_by_others, closed_rejected |
resource_type | dump_truck, pickup, tools, warehouse, free_transport, machinery, home_stay†, other |
confirmation_result | still_valid, changed, no_longer_valid |
20260813000000_init.sql: census_point in 20260814040000_site_type_census_point.sql; attended in 20260815020000_work_order_update_kinds.sql; home_stay in 20260814130000_resource_offer_public.sql.
The item_mode enum captures a three-way state for items at a site. The not_accepted value is the most operationally important: the Red Cross explicitly asks people not to donate used clothing, and that refusal has to be visible on the map card.
The work_order_status enum follows the Crisis Cleanup lifecycle. Closing reasons are deliberately honest: closed_by_others records that the job was already done on arrival — useful information rather than a failure. The application derives a simpler rollup (untouched, onTheWay, partial, advanced, reopened, done, dismissed) for public display; see lib/labels.ts.
Tables
The schema creates ten tables. All writes to the mapped entities go through the server-side data layer using the service role; no directINSERT or UPDATE policy is granted to anon or authenticated roles at the table level, which prevents a second, ungated write path from being opened accidentally.
| Table | Description |
|---|---|
profile | User record linked to auth.users; holds role, full_name, and whatsapp. Created automatically by the handle_new_user trigger on every new auth sign-up. |
neighborhood | 114 official barrios of Manizales plus Villamaría with a centroid geography column. Sourced from the SIG Alcaldía de Manizales open data portal (Acuerdo Municipal 589 de 2004). |
site | Aid locations — shelters, collection points, blood donation centres, medical posts, census points. Carries published, confirmed_at, expires_at, and an optional merged_into_id for duplicate resolution. |
site_item | Items a site needs, refuses (not_accepted), or already has enough of. Each row has a priority for ordering and a unique constraint on (site_id, label, mode). |
work_order | Community needs (debris removal, structural risk, supplies) with an approx_location that is deliberately block-level, not exact. Status is derived by the sync_work_order_state trigger from the update thread. |
work_order_update | Append-only thread entries for a work order: on_the_way, helped, still_needed, not_real. The trigger reads these to derive work_order.status. |
resource_offer | Neighbour-offered resources: trucks, tools, home stays. Carries a whatsapp contact (required) and optional available_from / available_until. |
animal_report | Lost, found, or sighted animals with a photo URL, species, description, and contact. The location is the last-seen point (nullable) — a lost animal has no fixed location. |
neighborhood_need | Curator-declared per-barrio priority levels (critical, high, normal). Drives the Frentes panel layer when a curator has entered data. |
Key triggers
set_neighborhood_from_location fires BEFORE INSERT OR UPDATE on site, work_order, and resource_offer. It uses a PostGIS point-in-polygon query against the neighborhood table to stamp neighborhood_id automatically from the row’s coordinate. The application never writes neighborhood_id directly — the trigger derives it, and it stays out of update payloads so the trigger cannot be bypassed by passing the old value.
This trigger runs even when rows are loaded via direct database import (MCP spreadsheet loads), which is the reason the logic lives in the database rather than in the DAL.
sync_work_order_state fires AFTER INSERT OR DELETE on work_order_update. It reads the full update thread for the work order and derives work_order.status from the entries. The application never sets work_order.status directly — if a feature ever needs to set it, it is the feature that is wrong. Closing a work order is exclusively a curator’s action (closed_completed, closed_by_others, closed_rejected), and sync_work_order_state freezes every closed state against later entries.
handle_new_user fires AFTER INSERT on auth.users and creates a matching profile row. It is declared SECURITY DEFINER so it runs with the function owner’s rights rather than the triggering user’s.
Security model
Every table has RLS enabled. The security model has three tiers:-
Public reads — published rows on
site,work_order,resource_offer, andanimal_reportare readable by anyone (including anonymous visitors). The product’s core value — finding a shelter — never requires an account. -
Curator reads — the
is_curator()function (aSECURITY DEFINERSQL function that checksprofile.role) is used in every read policy. A curator sees unpublished rows in addition to published ones, which is what makes thepublished = falsetoggle reversible without a direct database query. -
Sensitive data — contact details on
work_order(exact address, contact name, phone) are projected into the public view and visible to anyone. The fields are optional and the report form warns that anything entered will be publicly visible.
published = false in seed data. The application itself publishes reports immediately (open publication policy), but the seed data is loaded unpublished on purpose: seed coordinates are approximate and unverified, and sending someone to the wrong shelter during an emergency is worse than having no pin at all.
The site_public and work_order_public views project only safe columns and are declared security_invoker = on:
security_invoker = on, the view would execute with the definer’s rights and quietly bypass every RLS policy on site. The flag is load-bearing, not a style choice.