All checks were successful
Deploy production / deploy (push) Successful in 1m19s
Vault files stay the source of truth (bind-mounted read-write at /notes): atomic writes chowned to the vault owner, hash-checked saves (409 on a newer file), deletes to .trash. notes.* is a full-text/link index kept current by a recursive watcher plus a 60s rescan; live updates over the owner-only /ws/notes channel (paths and hashes only). Wikilinks, embeds, backlinks, tags, callouts, image paste. Owner-only everywhere (404).
48 lines
2.1 KiB
SQL
48 lines
2.1 KiB
SQL
CREATE SCHEMA "notes";
|
|
--> statement-breakpoint
|
|
CREATE TABLE "notes"."files" (
|
|
"path" text PRIMARY KEY,
|
|
"kind" text NOT NULL,
|
|
"folder" text NOT NULL,
|
|
"title" text NOT NULL,
|
|
"ext" text NOT NULL,
|
|
"size" bigint NOT NULL,
|
|
"mtime" timestamp with time zone NOT NULL,
|
|
"hash" text NOT NULL,
|
|
"tags" text[] DEFAULT '{}'::text[] NOT NULL,
|
|
"frontmatter" jsonb,
|
|
"body" text,
|
|
"search" tsvector,
|
|
"indexed_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "notes"."links" (
|
|
"src_path" text,
|
|
"seq" integer,
|
|
"target" text NOT NULL,
|
|
"target_key" text NOT NULL,
|
|
"embed" boolean DEFAULT false NOT NULL,
|
|
CONSTRAINT "links_pkey" PRIMARY KEY("src_path","seq")
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE INDEX "files_search_idx" ON "notes"."files" USING gin ("search");--> statement-breakpoint
|
|
CREATE INDEX "files_tags_idx" ON "notes"."files" USING gin ("tags");--> statement-breakpoint
|
|
CREATE INDEX "files_folder_idx" ON "notes"."files" ("folder");--> statement-breakpoint
|
|
CREATE INDEX "files_kind_idx" ON "notes"."files" ("kind");--> statement-breakpoint
|
|
CREATE INDEX "links_target_key_idx" ON "notes"."links" ("target_key");--> statement-breakpoint
|
|
ALTER TABLE "notes"."links" ADD CONSTRAINT "links_src_path_files_path_fkey" FOREIGN KEY ("src_path") REFERENCES "notes"."files"("path") ON DELETE CASCADE ON UPDATE CASCADE;--> statement-breakpoint
|
|
-- Privacy: notes are always private. Like tasks and health, only the app role can read or write
|
|
-- (no personal_ro); the owner-only checks live in the app. The tables are only a search/link
|
|
-- index rebuilt from the Obsidian vault files. Grants only run on prod (migrations as `personal`).
|
|
REVOKE ALL ON SCHEMA notes 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 notes TO personal_app;
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA notes TO personal_app;
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE personal IN SCHEMA notes
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO personal_app;
|
|
END IF;
|
|
END $$;
|