generated from coulomb/repo-seed
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:
243
docs/ihp-overview.md
Normal file
243
docs/ihp-overview.md
Normal 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 → 500–800 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: 10–15 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)
|
||||
Reference in New Issue
Block a user