77 lines
3.4 KiB
SQL
77 lines
3.4 KiB
SQL
CREATE SCHEMA "ai";
|
|
--> statement-breakpoint
|
|
CREATE TABLE "ai"."bot_status" (
|
|
"id" serial PRIMARY KEY,
|
|
"name" text NOT NULL,
|
|
"focus" text,
|
|
"recent" text,
|
|
"last_active" timestamp with time zone,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT "bot_status_name_check" CHECK (length(btrim("name")) > 0)
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "ai"."news_items" (
|
|
"id" serial PRIMARY KEY,
|
|
"date" date NOT NULL,
|
|
"title" text NOT NULL,
|
|
"url" text NOT NULL,
|
|
"note" text,
|
|
"section" text DEFAULT 'ai' NOT NULL,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT "news_items_section_check" CHECK ("section" IN ('ai','software')),
|
|
CONSTRAINT "news_items_title_check" CHECK (length(btrim("title")) > 0)
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "ai"."usage_entries" (
|
|
"id" serial PRIMARY KEY,
|
|
"provider" text NOT NULL,
|
|
"date" date NOT NULL,
|
|
"metric" text NOT NULL,
|
|
"value" double precision NOT NULL,
|
|
"unit" text,
|
|
"source" text DEFAULT 'manual' NOT NULL,
|
|
"note" text,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT "usage_entries_provider_check" CHECK ("provider" IN ('claude','chatgpt','gemini','api')),
|
|
CONSTRAINT "usage_entries_source_check" CHECK ("source" IN ('scheduled','ccusage','export','manual')),
|
|
CONSTRAINT "usage_entries_metric_check" CHECK (length(btrim("metric")) > 0)
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE UNIQUE INDEX "bot_status_name_key" ON "ai"."bot_status" ("name");--> statement-breakpoint
|
|
CREATE UNIQUE INDEX "news_items_url_key" ON "ai"."news_items" ("url");--> statement-breakpoint
|
|
CREATE INDEX "news_items_date_idx" ON "ai"."news_items" ("date");--> statement-breakpoint
|
|
CREATE UNIQUE INDEX "usage_entries_day_key" ON "ai"."usage_entries" ("provider","metric","date","source");--> statement-breakpoint
|
|
CREATE INDEX "usage_entries_provider_idx" ON "ai"."usage_entries" ("provider","metric","date");--> statement-breakpoint
|
|
-- Hand-written below this line (not generated by drizzle-kit).
|
|
-- updated_at triggers, same as every other core table.
|
|
DO $$
|
|
DECLARE t text;
|
|
BEGIN
|
|
IF to_regprocedure('meta.touch_updated_at()') IS NOT NULL THEN
|
|
FOREACH t IN ARRAY ARRAY['news_items','bot_status','usage_entries'] LOOP
|
|
EXECUTE format('CREATE TRIGGER touch_updated_at BEFORE UPDATE ON ai.%I FOR EACH ROW EXECUTE FUNCTION meta.touch_updated_at()', t);
|
|
END LOOP;
|
|
END IF;
|
|
END $$;
|
|
--> statement-breakpoint
|
|
-- Privacy: like tasks and health, readable/writable by the app role only (no personal_ro).
|
|
-- News is public on the site, but bot_status and usage_entries are personal, and the
|
|
-- owner-only checks live in the app. Grants only run on prod, where migrations run as `personal`.
|
|
REVOKE ALL ON SCHEMA ai 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 ai TO personal_app;
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA ai TO personal_app;
|
|
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA ai TO personal_app;
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE personal IN SCHEMA ai
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO personal_app;
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE personal IN SCHEMA ai
|
|
GRANT USAGE, SELECT ON SEQUENCES TO personal_app;
|
|
END IF;
|
|
END $$;
|