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

This commit is contained in:
2026-10-25 23:58:39 +00:00
parent 9b21220280
commit cf0fec973c
24 changed files with 38866 additions and 3 deletions

View 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 $$;

File diff suppressed because it is too large Load Diff