Files
helix/README.md
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

4.6 KiB

HELIX

EVOLV and every R&D strand, one helix.

The R&D showcase platform of Waterschap Brabantse Delta. EVOLV at its core, every innovation along the strands.

HELIX collects projects, innovations, and updates from across the R&D team in one place — with deep links to repos, dashboards, and demos. Sign-in is gated to the RnD Gitea organisation; viewing is open.

Stack

  • SvelteKit 2 + Svelte 5 + TypeScript
  • Tailwind v4 (CSS-first design tokens)
  • SQLite (single file) + Drizzle ORM
  • Gitea OAuth2 for authoring (no passwords stored)
  • Pure SVG + CSS helix animation — no WebGL

Local development

nvm use            # picks up .nvmrc → Node 20
cp .env.example .env
# Fill in GITEA_CLIENT_ID and GITEA_CLIENT_SECRET (see "Gitea OAuth setup" below)

npm install
npm run db:generate    # produces drizzle/0000_*.sql from the schema
npm run db:migrate     # applies migrations to ./helix.db
npm run db:seed        # adds example projects + posts so the landing page isn't empty
npm run dev            # http://localhost:3000

Gitea OAuth setup

HELIX uses your existing Gitea identity. Create an OAuth2 application once:

  1. Open https://gitea.wbd-rd.nl/-/user/settings/applications
  2. Click Create new OAuth2 application
  3. Application name: HELIX (local) (or HELIX (production))
  4. Redirect URI:
    • local: http://localhost:3000/auth/gitea/callback
    • prod: https://<your-helix-host>/auth/gitea/callback
  5. Click Create application
  6. Copy the Client ID and Client Secret into your .env:
    GITEA_CLIENT_ID=...
    GITEA_CLIENT_SECRET=...
    

GITEA_ALLOWED_ORG=RnD restricts authoring (sign-in) to members of the RnD organisation. Leave it empty to allow any authenticated Gitea user.

Adding a dashboard embed allowlist host

src/lib/config.tsDASHBOARD_ALLOWED_HOSTS controls which Grafana / dashboard origins can be embedded inline on a project page. Add a hostname (no scheme, no path) and redeploy. Hosts not on the list render as a "Open in new tab" card instead — never blindly iframed.

Production deploy (Docker)

cp .env.example .env       # fill in Gitea OAuth + ORIGIN
docker compose up -d --build

The SQLite database lives in the helix-data named volume at /data/helix.db. Back it up with docker compose exec helix sqlite3 /data/helix.db .dump.

Project layout

helix/
├── src/
│   ├── lib/
│   │   ├── components/         # Helix.svelte, ProjectCard, PostCard, Nav, Footer, DashboardEmbed
│   │   ├── server/
│   │   │   ├── db/             # Drizzle schema + client (better-sqlite3)
│   │   │   ├── auth.ts         # session token + cookie helpers
│   │   │   └── gitea.ts        # OAuth2 dance + user fetch
│   │   ├── config.ts           # site name, tagline, dashboard allowlist
│   │   └── markdown.ts         # marked wrapper + slug/id helpers
│   ├── routes/
│   │   ├── +page.svelte        # landing (helix hero + recent projects/posts)
│   │   ├── projects/           # /projects, /[slug], /new
│   │   ├── posts/              # /posts, /[slug], /new
│   │   ├── login/              # sign-in page (kicks off Gitea OAuth)
│   │   ├── logout/+server.ts   # POST → invalidates session
│   │   └── auth/gitea/         # OAuth start + callback
│   ├── app.html
│   ├── app.css                 # Tailwind v4 entry + design tokens
│   ├── app.d.ts                # Locals types
│   └── hooks.server.ts         # session hydration
├── drizzle/                    # generated migrations
├── scripts/
│   ├── migrate.js              # run pending migrations
│   └── seed.js                 # idempotent example data
├── static/favicon.svg
├── Dockerfile
├── docker-compose.yml
├── drizzle.config.ts
├── svelte.config.js
├── vite.config.ts
├── tailwind.config.ts (none — Tailwind v4 uses @theme in app.css)
├── tsconfig.json
└── package.json

How to post

After signing in (top-right → Sign in → Gitea), use:

  • + New in the nav (or /projects/new) — a project: title, summary, markdown body, links
  • /posts/new — a shorter update / write-up

Both are auth-gated. Anyone in RnD on Gitea can post.

Contributing

This is internal R&D — open a PR against main on gitea.wbd-rd.nl/RnD/helix.

License

Internal — Waterschap Brabantse Delta R&D.