forked from mirror/crumbs-original
Implement 4 user preferences (default note mode, default note color, hide footer, sidebar default state) with offline-first localStorage backed by server-side key-value storage. - Add user_preferences table (EAV pattern with unique user_id+key index) - Create server service with get/upsert operations - Add GET/PUT /api/preferences endpoints - Build Svelte 5 runes-based client store (.svelte.ts) - Wire preferences into app layout (footer toggle, sidebar state) - Wire default note mode/color into NoteEditor for new notes - Add Preferences tab as first item in Settings navigation - Add 7 unit tests and 4 E2E tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
114 lines
5.8 KiB
SQL
114 lines
5.8 KiB
SQL
CREATE TABLE `api_keys` (
|
|
`id` text PRIMARY KEY NOT NULL,
|
|
`user_id` integer NOT NULL,
|
|
`name` text NOT NULL,
|
|
`key_hash` text NOT NULL,
|
|
`key_prefix` text NOT NULL,
|
|
`created_at` integer NOT NULL,
|
|
`last_used_at` integer,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE `note_collaborators` (
|
|
`note_id` text NOT NULL,
|
|
`user_id` integer NOT NULL,
|
|
`added_by` integer NOT NULL,
|
|
`added_at` integer NOT NULL,
|
|
FOREIGN KEY (`note_id`) REFERENCES `notes`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
|
|
FOREIGN KEY (`added_by`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE UNIQUE INDEX `note_collaborators_unique` ON `note_collaborators` (`note_id`,`user_id`);--> statement-breakpoint
|
|
CREATE INDEX `note_collaborators_user_id_idx` ON `note_collaborators` (`user_id`);--> statement-breakpoint
|
|
CREATE TABLE `note_user_state` (
|
|
`note_id` text NOT NULL,
|
|
`user_id` integer NOT NULL,
|
|
`pinned` integer DEFAULT false NOT NULL,
|
|
`archived` integer DEFAULT false NOT NULL,
|
|
`sort_order` integer DEFAULT 0 NOT NULL,
|
|
FOREIGN KEY (`note_id`) REFERENCES `notes`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE UNIQUE INDEX `note_user_state_unique` ON `note_user_state` (`note_id`,`user_id`);--> statement-breakpoint
|
|
CREATE TABLE `user_preferences` (
|
|
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
`user_id` integer NOT NULL,
|
|
`key` text NOT NULL,
|
|
`value` text NOT NULL,
|
|
`updated_at` integer NOT NULL,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE UNIQUE INDEX `user_preferences_user_key_unique` ON `user_preferences` (`user_id`,`key`);--> statement-breakpoint
|
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
|
CREATE TABLE `__new_attachments` (
|
|
`id` text PRIMARY KEY NOT NULL,
|
|
`user_id` integer DEFAULT 0 NOT NULL,
|
|
`note_id` text NOT NULL,
|
|
`filename` text NOT NULL,
|
|
`mime_type` text NOT NULL,
|
|
`size` integer NOT NULL,
|
|
`path` text NOT NULL,
|
|
`thumbnail_path` text,
|
|
`featured` integer DEFAULT false NOT NULL,
|
|
`created_at` integer NOT NULL,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
|
|
FOREIGN KEY (`note_id`) REFERENCES `notes`(`id`) ON UPDATE no action ON DELETE cascade
|
|
);
|
|
--> statement-breakpoint
|
|
INSERT INTO `__new_attachments`("id", "user_id", "note_id", "filename", "mime_type", "size", "path", "thumbnail_path", "featured", "created_at") SELECT "id", "user_id", "note_id", "filename", "mime_type", "size", "path", "thumbnail_path", "featured", "created_at" FROM `attachments`;--> statement-breakpoint
|
|
DROP TABLE `attachments`;--> statement-breakpoint
|
|
ALTER TABLE `__new_attachments` RENAME TO `attachments`;--> statement-breakpoint
|
|
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
|
CREATE TABLE `__new_notes` (
|
|
`id` text PRIMARY KEY NOT NULL,
|
|
`user_id` integer DEFAULT 0 NOT NULL,
|
|
`title` text DEFAULT '' NOT NULL,
|
|
`content` text DEFAULT '' NOT NULL,
|
|
`color` text DEFAULT 'default' NOT NULL,
|
|
`pinned` integer DEFAULT false NOT NULL,
|
|
`archived` integer DEFAULT false NOT NULL,
|
|
`trashed` integer DEFAULT false NOT NULL,
|
|
`trashed_at` integer,
|
|
`checklist_mode` integer DEFAULT false NOT NULL,
|
|
`sort_order` integer DEFAULT 0 NOT NULL,
|
|
`created_at` integer NOT NULL,
|
|
`updated_at` integer NOT NULL,
|
|
`version` integer DEFAULT 1 NOT NULL,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
INSERT INTO `__new_notes`("id", "user_id", "title", "content", "color", "pinned", "archived", "trashed", "trashed_at", "checklist_mode", "sort_order", "created_at", "updated_at", "version") SELECT "id", "user_id", "title", "content", "color", "pinned", "archived", "trashed", "trashed_at", "checklist_mode", "sort_order", "created_at", "updated_at", "version" FROM `notes`;--> statement-breakpoint
|
|
DROP TABLE `notes`;--> statement-breakpoint
|
|
ALTER TABLE `__new_notes` RENAME TO `notes`;--> statement-breakpoint
|
|
CREATE INDEX `notes_user_id_idx` ON `notes` (`user_id`);--> statement-breakpoint
|
|
CREATE INDEX `notes_trashed_archived_idx` ON `notes` (`trashed`,`archived`);--> statement-breakpoint
|
|
CREATE INDEX `notes_updated_at_idx` ON `notes` (`updated_at`);--> statement-breakpoint
|
|
CREATE TABLE `__new_sync_log` (
|
|
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
`user_id` integer DEFAULT 0 NOT NULL,
|
|
`note_id` text NOT NULL,
|
|
`operation` text NOT NULL,
|
|
`timestamp` integer NOT NULL,
|
|
`client_id` text NOT NULL,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
|
|
FOREIGN KEY (`note_id`) REFERENCES `notes`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
INSERT INTO `__new_sync_log`("id", "user_id", "note_id", "operation", "timestamp", "client_id") SELECT "id", "user_id", "note_id", "operation", "timestamp", "client_id" FROM `sync_log`;--> statement-breakpoint
|
|
DROP TABLE `sync_log`;--> statement-breakpoint
|
|
ALTER TABLE `__new_sync_log` RENAME TO `sync_log`;--> statement-breakpoint
|
|
CREATE INDEX `sync_log_timestamp_idx` ON `sync_log` (`timestamp`);--> statement-breakpoint
|
|
CREATE TABLE `__new_tags` (
|
|
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
`user_id` integer DEFAULT 0 NOT NULL,
|
|
`name` text NOT NULL,
|
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
);
|
|
--> statement-breakpoint
|
|
INSERT INTO `__new_tags`("id", "user_id", "name") SELECT "id", "user_id", "name" FROM `tags`;--> statement-breakpoint
|
|
DROP TABLE `tags`;--> statement-breakpoint
|
|
ALTER TABLE `__new_tags` RENAME TO `tags`;--> statement-breakpoint
|
|
CREATE UNIQUE INDEX `tags_name_user_unique` ON `tags` (`name`,`user_id`); |