Files
helix/drizzle/0000_giant_mother_askani.sql
Rene De Ren c3d978a7eb feat: initial HELIX scaffold — R&D showcase platform
SvelteKit 2 + Svelte 5 + TypeScript site. SQLite via Drizzle. Gitea OAuth
for authoring (RnD org-gated). Pure SVG + CSS DNA helix on landing.

What lands
- Landing hero with animated two-strand SVG helix + tagline
- /projects + /projects/[slug] (markdown body, dashboard embed allowlist)
- /posts + /posts/[slug]
- Auth-gated /projects/new + /posts/new forms
- Gitea OAuth flow (state, code exchange, org-membership check, sessions)
- Sliding-window cookie sessions (SHA-256 hashed token storage)
- Dockerfile + docker-compose with named-volume SQLite
- Idempotent seed (EVOLV + HELIX projects, welcome post)

Stack notes
- Tailwind v3 (Node 18 compat; v4 needs Node 20+)
- drizzle-orm 0.45+ (patched, no SQL-identifier escape vuln)
- marked for markdown; iframe embeds gated by DASHBOARD_ALLOWED_HOSTS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:01:12 +02:00

80 lines
2.8 KiB
SQL

CREATE TABLE `post_tags` (
`post_id` text NOT NULL,
`tag_id` text NOT NULL,
PRIMARY KEY(`post_id`, `tag_id`),
FOREIGN KEY (`post_id`) REFERENCES `posts`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`tag_id`) REFERENCES `tags`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `posts` (
`id` text PRIMARY KEY NOT NULL,
`slug` text NOT NULL,
`title` text NOT NULL,
`summary` text DEFAULT '' NOT NULL,
`body_md` text NOT NULL,
`author_id` text,
`published_at` integer,
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
`updated_at` integer DEFAULT (unixepoch()) NOT NULL,
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
CREATE UNIQUE INDEX `posts_slug_unique` ON `posts` (`slug`);--> statement-breakpoint
CREATE TABLE `project_links` (
`id` text PRIMARY KEY NOT NULL,
`project_id` text NOT NULL,
`kind` text NOT NULL,
`label` text NOT NULL,
`url` text NOT NULL,
`position` integer DEFAULT 0 NOT NULL,
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `project_tags` (
`project_id` text NOT NULL,
`tag_id` text NOT NULL,
PRIMARY KEY(`project_id`, `tag_id`),
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`tag_id`) REFERENCES `tags`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `projects` (
`id` text PRIMARY KEY NOT NULL,
`slug` text NOT NULL,
`title` text NOT NULL,
`summary` text NOT NULL,
`body_md` text DEFAULT '' NOT NULL,
`cover_url` text,
`author_id` text,
`status` text DEFAULT 'published' NOT NULL,
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
`updated_at` integer DEFAULT (unixepoch()) NOT NULL,
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
CREATE UNIQUE INDEX `projects_slug_unique` ON `projects` (`slug`);--> statement-breakpoint
CREATE TABLE `sessions` (
`id` text PRIMARY KEY NOT NULL,
`user_id` text NOT NULL,
`expires_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `tags` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `tags_name_unique` ON `tags` (`name`);--> statement-breakpoint
CREATE TABLE `users` (
`id` text PRIMARY KEY NOT NULL,
`gitea_id` integer NOT NULL,
`username` text NOT NULL,
`name` text,
`email` text,
`avatar_url` text,
`role` text DEFAULT 'editor' NOT NULL,
`created_at` integer DEFAULT (unixepoch()) NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `users_gitea_id_unique` ON `users` (`gitea_id`);