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

127 lines
4.6 KiB
Markdown

# 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
```bash
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.ts` → `DASHBOARD_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)
```bash
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`](https://gitea.wbd-rd.nl/RnD/helix).
## License
Internal — Waterschap Brabantse Delta R&D.