docs: add specification, reference docs, workplan, and agent guidance

Adds all Phase 0 content that was created but never committed:
- CLAUDE.md and SCOPE.md — agent and developer orientation
- specs/TailwindForInteractionHubs_v0.2.md — IHF Tailwind coding guide
- docs/ — five IHP v1.5 reference guides (overview, data, controllers, realtime, ihf-mapping)
- workplans/IHUB-WP-0001 — Phase 1 implementation plan (12 tasks, state-hub synced)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-27 02:07:13 +01:00
parent 75b88ee760
commit 8b6ce5bbc8
9 changed files with 2181 additions and 0 deletions

243
docs/ihp-overview.md Normal file
View File

@@ -0,0 +1,243 @@
# IHP Framework Overview
> Reference notes for implementing the Interaction Hub Framework (IHF) using IHP.
> Based on IHP v1.5.0 (released March 2026).
---
## What IHP Is
**IHP** (Integrated Haskell Platform) is a batteries-included, full-stack web framework built on Haskell and Nix. Its goal is rapid application development with robust, type-safe code.
- **Language:** Haskell (GHC 9.10 default; GHC 9.12 experimental in v1.5)
- **Paradigm:** Functional, strongly typed, server-rendered with optional realtime
- **Creator:** [digitally induced](https://github.com/digitallyinduced) (Hamburg). Open-sourced 2020, in production since 2017
- **Current version:** v1.5.0 (March 25, 2026) — largest release to date (1,051 commits)
- **License:** MIT
### v1.5 Headline Changes
| Change | Impact |
|--------|--------|
| `postgresql-simple``hasql` driver | Up to 50% lower query latency |
| Dev server RAM: 4 GB → 500800 MB | Practical on smaller machines |
| Session middleware 3×, URL gen 5×, rendering 2× faster | Overall snappier |
| `typedSql` quasiquoter | Compile-time SQL type checking against live dev DB |
| `fetchPipelined` | Multiple queries in one network round-trip |
| Composite primary key support | Needed for join-table models |
| Integration test mode | Temporary Postgres DB per test run |
| 15+ modules on Hackage separately | `ihp-mail`, `ihp-datasync`, etc. |
### Design Philosophy
- Type errors at compile time, not runtime
- Single command (`devenv up`) starts a fully self-contained environment — Postgres included, managed by Nix. No Docker, no Kubernetes required
- Optimized for AI-assisted development — the type system automatically verifies generated code
---
## Core Architecture
### MVC-Influenced Structure
| Layer | IHP Location | Role |
|-------|-------------|------|
| Model | `Application/Schema.sql` + generated types | Schema, query builder, relationships |
| Controller | `Web/Controller/<Name>.hs` | Action handlers, parameter binding, DB calls |
| View | `Web/View/<Name>/<Action>.hs` | HSX templates, `View` typeclass |
| Routing | `Web/Routes.hs` + `Web/FrontController.hs` | URL ↔ action mapping |
| Types | `Web/Types.hs` | All controller action constructors |
| Helpers | `Application/Helper/Controller.hs`, `Application/Helper/View.hs` | Shared logic |
Multi-application support: a single project can contain multiple sub-apps (`Web/`, `Admin/`). `new-application admin` generates an `Admin/` subtree with routes auto-prefixed `/admin/`.
### Type-Safe URL / Action System
The IHP router always maps HTTP requests to **data constructors** defined in `Web/Types.hs`:
```haskell
data WidgetsController
= WidgetsAction
| NewWidgetAction
| ShowWidgetAction { widgetId :: !(Id Widget) }
| CreateWidgetAction
| EditWidgetAction { widgetId :: !(Id Widget) }
| UpdateWidgetAction { widgetId :: !(Id Widget) }
| DeleteWidgetAction { widgetId :: !(Id Widget) }
deriving (Eq, Show, Data)
```
- URLs generated from values, not strings: `pathTo ShowWidgetAction { widgetId = someId }`
- Compile-time guarantee: broken links are type errors, not 404s
- `urlTo` generates absolute URLs (protocol + domain)
### Routing
Defined in `Web/Routes.hs`, registered in `Web/FrontController.hs`.
**AutoRoute** (most common): `instance AutoRoute WidgetsController` — IHP generates RESTful routes from action name prefixes:
| Prefix | HTTP Method |
|--------|------------|
| `Delete` | DELETE |
| `Create`, `Update` | POST/PATCH |
| anything else | GET |
**Custom routes:** implement `CanRoute` (attoparsec parser URL → action) and `HasPath` (reverse). `customRoutes` overrides individual AutoRoute entries. Supports SEO slugs like `/widgets/my-slug`.
HTTP method override for HTML forms: pass `_method=DELETE` (or `PATCH`) as a hidden field.
---
## Development Workflow
### Installation
```bash
# 1. Install Determinate Nix (with Flakes + lazy-trees)
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
# 2. Install ihp-new
nix profile install nixpkgs#ihp-new
# 3. Install direnv and hook into shell
nix profile add nixpkgs#direnv
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc # or zshrc
```
### Creating a Project
```bash
ihp-new my-project
cd my-project
devenv up
```
First startup: 1015 minutes (downloads GHC, Postgres, all Haskell deps via Nix binary cache). Subsequent starts are fast (under 30s).
### Dev Server
`devenv up` starts everything:
- Application server on `http://localhost:8000`
- IHP IDE + Schema Designer on `http://localhost:8001`
- Postgres (managed by Nix; no system Postgres needed)
- Live reloading (typically sub-50ms after save)
### Project File Structure
```
my-project/
├── Application/
│ ├── Schema.sql # Single source of truth for all DB types
│ ├── Migration/ # <timestamp>-description.sql files
│ ├── Helper/
│ │ ├── Controller.hs # Shared controller helpers
│ │ └── View.hs # Shared view helpers
│ └── Script/ # One-off scripts / cron job binaries
├── Web/
│ ├── Types.hs # ALL controller action constructors
│ ├── Routes.hs # AutoRoute instance declarations
│ ├── FrontController.hs # WAI entry; dispatch; auth init; default layout
│ ├── Controller/ # One file per controller
│ ├── View/ # One dir per controller, one file per action
│ │ └── Layout.hs # Default layout (Html -> Html)
│ └── Component/ # Server-Side Components (optional)
├── Config/
│ ├── Config.hs # Env vars, secrets, feature flags
│ └── nix/
│ └── hosts/
│ └── production/ # Declarative NixOS server config
├── Test/ # Integration tests
├── static/ # CSS, JS, images
├── flake.nix # Nix flake — all deps declared here
├── App.cabal # Cabal package definition
├── Main.hs # Entry point
└── Makefile # Build targets
```
### Adding Dependencies
In `flake.nix`:
```nix
ihp = {
enable = true;
projectPath = ./.;
packages = [ pkgs.imagemagick ]; # native deps
haskellPackages = p: [
p.ihp
p.aeson
p.your-library
];
};
```
### Code Generators
Navigate to `http://localhost:8001/Generators` or right-click a table in Schema Designer → "Generate Controller". Scaffolds controllers, views, routes, and type entries to match the table's fields. Also available: Migration, Job, Mail, Script generators.
### Testing
v1.5: integration test mode creates a temporary Postgres DB automatically per test run. Tests live in `Test/`.
---
## Deployment
### Primary: NixOS / `deploy-to-nixos`
The entire server config (nginx, Let's Encrypt, systemd, app config) lives declaratively in `Config/nix/hosts/production/` — version-controlled and reproducible.
```bash
deploy-to-nixos production
```
Runs `nixos-rebuild` remotely over SSH. AWS EC2: NixOS AMI, `t3a.small` min (`t3a.medium` recommended), 60 GiB root disk, ports 22/80/443.
**Required env vars:**
| Variable | Purpose |
|----------|---------|
| `IHP_SESSION_SECRET` | Session encryption key (`new-session-secret` to generate) |
| `DATABASE_URL` | Postgres connection string |
| `IHP_BASEURL` | External URL (e.g., `https://example.com`) |
**Production features built-in:**
- Systemd watchdog (heartbeat 30s; auto-restart after 60s)
- Socket activation (queues requests during restarts — zero-downtime deploys)
- Sentry integration via `ihp-sentry` (IHP Pro)
### Docker (IHP Pro)
```bash
nix build .#unoptimized-docker-image --option sandbox false
cat result | podman load
```
Env vars: same as above + `IHP_ASSET_VERSION` (cache-busting) + `IHP_REQUEST_LOGGER_IP_ADDR_SOURCE=FromHeader` (behind load balancer). Minimal Docker images lack CA certificates — copy `caCertificates` and set `SSL_CERT_FILE`.
### Bare Metal Binary
```bash
nix build .#optimized-prod-server # full optimisation
nix build .#unoptimized-prod-server # faster build, for staging
```
Runtime: `IHP_ENV=Production`, `DATABASE_URL`, `PORT` (default 8000). GHC RTS tunable via `GHCRTS`.
### CSS/JS Bundling
```bash
make static/prod.js static/prod.css
```
Dev uses individual files; production uses bundled/minified versions. Background jobs require deploying the `RunJobs` binary alongside the main app.
---
## Key Links
- [IHP Homepage](https://ihp.digitallyinduced.com/)
- [IHP Guide (full docs)](https://ihp.digitallyinduced.com/Guide/)
- [GitHub: digitallyinduced/ihp](https://github.com/digitallyinduced/ihp)
- [ihp-boilerplate](https://github.com/digitallyinduced/ihp-boilerplate) — template used by `ihp-new`
- [v1.5 release announcement](https://discourse.haskell.org/t/ihp-v1-5-has-been-released/13846)