notes: private Obsidian vault tracker at /trackers/notes
All checks were successful
Deploy production / deploy (push) Successful in 1m19s
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).
This commit is contained in:
47
drizzle/20261026012817_notes/migration.sql
Normal file
47
drizzle/20261026012817_notes/migration.sql
Normal file
@@ -0,0 +1,47 @@
|
||||
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 $$;
|
||||
41215
drizzle/20261026012817_notes/snapshot.json
Normal file
41215
drizzle/20261026012817_notes/snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user