AI tracker: /trackers/ai with public news, owner-only bots and usage; ai schema (news_items, bot_status, usage_entries); idempotent import scripts; preflight ai grants check
Some checks failed
Deploy production / deploy (push) Has been cancelled
Some checks failed
Deploy production / deploy (push) Has been cancelled
This commit is contained in:
76
drizzle/20261025235015_ai_tracker/migration.sql
Normal file
76
drizzle/20261025235015_ai_tracker/migration.sql
Normal file
@@ -0,0 +1,76 @@
|
||||
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 $$;
|
||||
Reference in New Issue
Block a user