worldwide todo list: public todo list of 68 real, sourced problems (planet to street) at /projects/worldwide-todo. worldtodo schema (categories, tasks, change_requests), idempotent seed on deploy, public add/edit/delete requests with Turnstile + salted daily-rotating IP-hash rate limit, owner-only review queue (approve, edit & approve, reject) with live updates over /ws/worldtodo(-owner), JSON API, detail pages with OSM map and history; listed in projects, header, /start and sitemap
Some checks failed
Deploy production / deploy (push) Failing after 9s
Some checks failed
Deploy production / deploy (push) Failing after 9s
This commit is contained in:
95
drizzle/20261026012608_worldtodo/migration.sql
Normal file
95
drizzle/20261026012608_worldtodo/migration.sql
Normal file
@@ -0,0 +1,95 @@
|
||||
CREATE SCHEMA "worldtodo";
|
||||
--> statement-breakpoint
|
||||
CREATE TYPE "worldtodo"."req_kind" AS ENUM('add', 'edit', 'delete');--> statement-breakpoint
|
||||
CREATE TYPE "worldtodo"."req_status" AS ENUM('pending', 'approved', 'rejected');--> statement-breakpoint
|
||||
CREATE TYPE "worldtodo"."scale" AS ENUM('planet', 'region', 'country', 'city', 'street');--> statement-breakpoint
|
||||
CREATE TYPE "worldtodo"."status" AS ENUM('open', 'in_progress', 'done');--> statement-breakpoint
|
||||
CREATE TABLE "worldtodo"."categories" (
|
||||
"slug" text PRIMARY KEY,
|
||||
"label" text NOT NULL,
|
||||
"icon" text NOT NULL,
|
||||
"colour" text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "worldtodo"."change_requests" (
|
||||
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "worldtodo"."change_requests_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
|
||||
"kind" "worldtodo"."req_kind" NOT NULL,
|
||||
"task_id" bigint,
|
||||
"payload" jsonb DEFAULT '{}' NOT NULL,
|
||||
"applied" jsonb,
|
||||
"task_updated_at" timestamp with time zone,
|
||||
"reason" text NOT NULL,
|
||||
"display_name" text,
|
||||
"status" "worldtodo"."req_status" DEFAULT 'pending'::"worldtodo"."req_status" NOT NULL,
|
||||
"owner_note" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"decided_at" timestamp with time zone,
|
||||
CONSTRAINT "change_requests_reason_check" CHECK (char_length("reason") BETWEEN 10 AND 1000),
|
||||
CONSTRAINT "change_requests_display_name_check" CHECK (char_length("display_name") <= 40),
|
||||
CONSTRAINT "change_requests_task_check" CHECK ((("kind" = 'add') = ("task_id" IS NULL)))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "worldtodo"."tasks" (
|
||||
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "worldtodo"."tasks_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
|
||||
"slug" text NOT NULL,
|
||||
"title" text NOT NULL,
|
||||
"description" text NOT NULL,
|
||||
"scale" "worldtodo"."scale" NOT NULL,
|
||||
"category" text NOT NULL,
|
||||
"location_name" text NOT NULL,
|
||||
"country_code" text,
|
||||
"lat" double precision,
|
||||
"lon" double precision,
|
||||
"status" "worldtodo"."status" DEFAULT 'open'::"worldtodo"."status" NOT NULL,
|
||||
"source_urls" text[] NOT NULL,
|
||||
"source_date" text,
|
||||
"confidence" text DEFAULT 'high' NOT NULL,
|
||||
"verification_note" text,
|
||||
"as_of" date NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"deleted_at" timestamp with time zone,
|
||||
"search" tsvector GENERATED ALWAYS AS (to_tsvector('simple', title || ' ' || description || ' ' || location_name)) STORED,
|
||||
CONSTRAINT "tasks_title_check" CHECK (char_length("title") BETWEEN 5 AND 140),
|
||||
CONSTRAINT "tasks_description_check" CHECK (char_length("description") <= 2000),
|
||||
CONSTRAINT "tasks_lat_check" CHECK ("lat" BETWEEN -90 AND 90),
|
||||
CONSTRAINT "tasks_lon_check" CHECK ("lon" BETWEEN -180 AND 180),
|
||||
CONSTRAINT "tasks_sources_check" CHECK (cardinality("source_urls") >= 1),
|
||||
CONSTRAINT "tasks_confidence_check" CHECK ("confidence" IN ('high','medium'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX "change_requests_status_idx" ON "worldtodo"."change_requests" ("status","created_at");--> statement-breakpoint
|
||||
CREATE INDEX "change_requests_task_idx" ON "worldtodo"."change_requests" ("task_id","status");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "tasks_slug_key" ON "worldtodo"."tasks" ("slug");--> statement-breakpoint
|
||||
CREATE INDEX "tasks_search_idx" ON "worldtodo"."tasks" USING gin ("search");--> statement-breakpoint
|
||||
CREATE INDEX "tasks_scale_status_idx" ON "worldtodo"."tasks" ("scale","status") WHERE deleted_at IS NULL;--> statement-breakpoint
|
||||
ALTER TABLE "worldtodo"."change_requests" ADD CONSTRAINT "change_requests_task_id_tasks_id_fkey" FOREIGN KEY ("task_id") REFERENCES "worldtodo"."tasks"("id");--> statement-breakpoint
|
||||
ALTER TABLE "worldtodo"."tasks" ADD CONSTRAINT "tasks_category_categories_slug_fkey" FOREIGN KEY ("category") REFERENCES "worldtodo"."categories"("slug");
|
||||
--> statement-breakpoint
|
||||
-- Hand-written below this line (not generated by drizzle-kit).
|
||||
-- updated_at trigger on tasks, same as the other core tables.
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regprocedure('meta.touch_updated_at()') IS NOT NULL THEN
|
||||
CREATE TRIGGER touch_updated_at BEFORE UPDATE ON worldtodo.tasks
|
||||
FOR EACH ROW EXECUTE FUNCTION meta.touch_updated_at();
|
||||
END IF;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
-- Grants: app role read/write only (like ai and movies; no personal_ro: change requests may
|
||||
-- carry a display name). Prod only, where migrations run as `personal`. Rows are seeded by
|
||||
-- scripts/seed-worldtodo.ts on every deploy.
|
||||
REVOKE ALL ON SCHEMA worldtodo FROM PUBLIC;
|
||||
--> statement-breakpoint
|
||||
DO $$
|
||||
BEGIN
|
||||
IF current_user = 'personal' AND EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'personal_app') THEN
|
||||
GRANT USAGE ON SCHEMA worldtodo TO personal_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA worldtodo TO personal_app;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA worldtodo TO personal_app;
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE personal IN SCHEMA worldtodo
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO personal_app;
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE personal IN SCHEMA worldtodo
|
||||
GRANT USAGE, SELECT ON SEQUENCES TO personal_app;
|
||||
END IF;
|
||||
END $$;
|
||||
40822
drizzle/20261026012608_worldtodo/snapshot.json
Normal file
40822
drizzle/20261026012608_worldtodo/snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user