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>
This commit is contained in:
Rene De Ren
2026-05-20 11:01:12 +02:00
commit c3d978a7eb
59 changed files with 8140 additions and 0 deletions

20
scripts/migrate.js Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env node
/**
* Runs all pending Drizzle migrations against DATABASE_URL.
*
* node scripts/migrate.js
*/
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
const url = process.env.DATABASE_URL ?? './helix.db';
const sqlite = new Database(url);
sqlite.pragma('journal_mode = WAL');
sqlite.pragma('foreign_keys = ON');
const db = drizzle(sqlite);
migrate(db, { migrationsFolder: './drizzle' });
console.log(`[helix] migrations applied → ${url}`);
sqlite.close();