diff --git a/slides/tappaas/how-to/new-module/index.md b/slides/tappaas/how-to/new-module/index.md
index 57779c9..6ab84c2 100644
--- a/slides/tappaas/how-to/new-module/index.md
+++ b/slides/tappaas/how-to/new-module/index.md
@@ -4,229 +4,286 @@ theme: gaia
class: invert
paginate: true
title: How to implement a TAPPaaS module
-description: Walk-through of adding a new module to the TAPPaaS repository
+description: Live build of a Podman module — OrangeMaker session
---
-# How to implement a TAPPaaS module
+# Getting a module onto TAPPaaS
-From empty directory to merged pull request
+Live build of a **Podman** container host
+
+OrangeMaker · `TODO: date`
---
-## Who this is for
+## The plan
-- You want to add an **app** or a **foundation** capability to TAPPaaS
-- You can read shell, JSON, and a little Nix
-- You have a TAPPaaS test environment you are allowed to break
+1. **What TAPPaaS is** — two diagrams, ten minutes, no deeper
+2. **What a module actually is** — a json contract and three scripts
+3. **Build one live** — a test environment, then `podman` into it
+4. **Prove it works** — tests, then the web console
+5. **You get a login** — your own identity on this system
-**Prerequisites**
-
-- A clone of `TAPPaaS/TAPPaaS`, branch `TODO: ADR007 or stable`
-- SSH access to a test site
-- `TODO: tooling list`
+You leave with: a mental model, a module you watched get built, and an account.
---
-## Vocabulary in 60 seconds
+
-| Term | Means |
-| --- | --- |
-| **Module** | One installable unit under `src/apps/` or `src/foundation/` |
-| **Service** | A part of a module with its own lifecycle scripts |
-| **Manager** | Owns desired state for a domain |
-| **Controller** | Applies desired state to one concrete technology |
-
-`TODO: tighten against ADR-007 taxonomy; drop the terms that do not matter here`
-
----
-
-## Anatomy of a module
-
-```text
-src/apps//
-├── README.md # what it is, why it exists
-├── DESIGN.md # how it is put together
-├── INSTALL.md # operator-facing install notes
-├── UPGRADE.md # operator-facing upgrade notes
-├── AUTHORS.md # who to ask
-├── LICENSE
-├── .json # declaration: the module's contract
-├── .nix # runtime definition
-├── install.sh # create it
-├── update.sh # move it forward
-├── test.sh # prove it works
-└── services// # per-service install/update/test/delete
-```
-
----
-
-## The path from nothing to merged
+## The shape of a TAPPaaS site
```mermaid
flowchart LR
- A[Scaffold from
00-Template] --> B[Declare
module.json]
- B --> C[Define runtime
module.nix]
- C --> D[install.sh]
- D --> E[services/]
- E --> F[update.sh]
- F --> G[test.sh]
- G --> H[Docs]
- H --> I[PR + CI]
+ sat["satellite VPS
public IP · ingress
off-site backup"]
+ subgraph z0["mgmt · zone mgmt"]
+ cicd["tappaas-cicd"]
+ net["network"]
+ clu["cluster"]
+ bak["backup"]
+ idp["identity"]
+ end
+ subgraph z1["default · zone srv"]
+ nc["nextcloud"]
+ ha["home-assistant"]
+ end
+ subgraph z2["test · zone hacklab"]
+ pod["podman — today"]
+ end
+ sat --> net
+ cicd --> nc
+ cicd --> pod
```
---
-## Step 1 — Scaffold
+## The words we will use
+
+| Word | Meaning |
+| --- | --- |
+| **Module** | The smallest deployable unit — its own VM, its own json contract. Foundation *and* apps are modules. |
+| **Environment** | A tenant. `mgmt` and one named after the site always exist; add more freely. |
+| **Zone** | A VLAN with a firewall policy. Modules land in their environment's zone. |
+| **Mothership** | `tappaas-cicd` — where the managers run and where you type. |
+| **Satellite** | Optional VPS, for sites with no usable public IP. |
+
+Everything is a module. There is one model to learn, not eight.
+
+---
+
+
+
+## How code gets in: pull-based GitOps
+
+```mermaid
+flowchart RL
+ subgraph t["TAPPaaS repository"]
+ stable["stable"]
+ main["main"]
+ end
+ subgraph c["Community repository"]
+ cm["main"]
+ end
+ subgraph inst["Your TAPPaaS · tappaas-cicd"]
+ lt["clone of TAPPaaS"]
+ lc["clone of Community"]
+ end
+ lt -->|pull| stable
+ lc -->|pull| cm
+```
+
+Nothing pushes into your site. It pulls, on a schedule, and reconciles.
+
+---
+
+## Managers: the verbs you will watch me type
```bash
-cp -r src/apps/00-Template src/apps/
+module-manager module add|test|reconcile|modify|delete
+environment-manager add|modify|reconcile
+network-manager zone add|merge|reconcile
+people-manager user add|modify · reconcile --apply
```
-- Rename `template.json` → `.json`, `template.nix` → `.nix`
-- Read `README-template.md`, then delete it
-- `TODO: is there a scaffold script? if not, should there be?`
+Admins drive **verbs**, never hand-edited JSON. Each manager owns one slice of
+desired state; controllers push it into OPNsense, Proxmox, the switch, Authentik.
---
-## Step 2 — Declare the module
+## A module is a contract and three scripts
-`.json`
+```text
+podman/
+├── podman.json # the contract — what it is, needs, provides
+├── install.sh # put the software in the VM (once)
+├── update.sh # keep it patched (on schedule)
+├── test.sh # prove it still works (gates updates)
+├── README.md # what it is
+└── INSTALL.md # what automation cannot do for you
+```
+
+That is the whole surface. Everything else is the platform's job.
+
+---
+
+## The contract, for real
```json
{
- "TODO": "smallest working declaration"
+ "description": "Podman container host — Debian 13 VM with rootless Podman + Cockpit",
+ "vmname": "podman", "vmid": 812,
+ "dependsOn": ["cluster:vm", "templates:debian", "backup:vm", "network:proxy"],
+ "config": {
+ "cluster:vm": { "cores": 2, "memory": "2048", "diskSize": "20G",
+ "image": "debian-13-generic-amd64.qcow2" },
+ "network:proxy": { "proxyPort": 9090, "proxyUpstreamTls": true,
+ "proxyUpstreamHttp1": true, "proxyAllowedZones": ["mgmt"] }
+ }
}
```
-- What the module *is*, not how it is built
-- `TODO: required keys, optional keys, validation`
+`dependsOn` is the whole trick: four services, declared — not scripted.
---
-## Step 3 — Define the runtime
+## The three scripts, honestly
-`.nix`
+| Script | Called | Does |
+| --- | --- | --- |
+| `install.sh` | once, at add | For podman: `exec update.sh` — install *is* update here |
+| `update.sh` | every schedule | apt: `podman`, `podman-compose`, `cockpit`, `cockpit-podman`; enable the rootless socket |
+| `test.sh` | on demand + before every update merge | VM reachable · podman present · plugin present · console answers on `:9090` |
-```nix
-# TODO: minimal example
-```
-
-- `TODO: what belongs in nix vs. what belongs in install.sh`
+If `test.sh` is honest, unattended updates are safe. That is the entire deal.
---
-## Step 4 — `install.sh`
+## What you did not have to write
-- Idempotent: safe to run twice
-- Fails loudly, never half-way
-- `pre-install.sh` when something must exist first
+- A VM — `cluster:vm` built it from the Debian 13 cloud image
+- OS prep — `templates:debian` did apt + guest agent
+- A VLAN, an interface, DHCP, firewall rules — the zone came with the environment
+- `https://podman.` with a real certificate — `network:proxy`, one dependency
+- Nightly backup to PBS — `backup:vm`
+- Scheduled updates and health reporting — the mothership
+
+Six lines of json bought all of it.
+
+---
+
+## Demo 1 — an environment of our own
```bash
-# TODO: skeleton with the house conventions
+# srvTest ships in the zone template; a fresh one keeps the demo self-contained
+network-manager zone add hacklab --from-zone srv
+
+environment-manager add test \
+ --display "Hackerspace test" \
+ --zone hacklab \
+ --domain test.
```
+A tenant with its own VLAN, its own firewall posture, its own DNS names —
+and nothing in it can touch production.
+
+`TODO: our domain — and do we build the zone live or pre-bake it?`
+
+
+
---
-## Step 5 — Services
+## Demo 2 — install the module
+
+```bash
+module-manager module add podman --environment test
+```
+
+Watch the order: dependencies resolve first, then the VM, then the network, then
+`install.sh`. Install order is **computed** from every module's `dependsOn` — nobody
+maintains a list.
+
+
+
+---
+
+## Demo 3 — prove it, then look at it
+
+```bash
+module-manager module test podman
+```
+
+Then open **`https://podman.`** — Cockpit, with the Podman page.
+
+- Reachable from the `mgmt` zone only. Not from the internet, by declaration.
+- Cockpit authenticates against **Linux accounts on the VM** — the cloud-init
+ `tappaas` user has no password until someone sets one.
+
+`TODO: pre-create the demo login, or set the password live?`
+
+---
+
+## Where this module lives
```text
-services//install-service.sh
-services//update-service.sh
-services//test-service.sh
-services//delete-service.sh
+Community/src/larsrossen/containers/podman/
```
-- One service = one thing with its own lifecycle
-- `TODO: when to split into services vs. keep it in the module`
+Three homes for a module, all first-class:
----
-
-## Step 6 — `update.sh`
-
-- Upgrade in place, no data loss
-- Version pinning: `TODO`
-- Rollback story: `TODO`
-
----
-
-## Step 7 — `test.sh`
-
-- Runs against a real environment, not a mock
-- Exit non-zero on failure, quiet on success
-- `TODO: what CI runs, and what only a human can check`
-
----
-
-## Step 8 — Documentation
-
-| File | Answers |
+| Home | For |
| --- | --- |
-| `README.md` | What is this and why would I install it? |
-| `DESIGN.md` | How is it built, what were the trade-offs? |
-| `INSTALL.md` | How do I install it, step by step? |
-| `UPGRADE.md` | What breaks between versions? |
+| **TAPPaaS** repo, by pull request | modules the whole project should carry |
+| **Community** repo | yours, shared, no gatekeeping — today's podman |
+| **Private** repo | yours, not shared |
-Docs are synced to the docs site — a missing README is a missing page.
+Adding a repository is one `site-manager repository add`.
---
-## Try it on a test site
+## Your turn — identity on this TAPPaaS
```bash
-# TODO: the real loop
+people-manager user add --email @example.org \
+ --roles user --groups orangemaker__users
+
+people-manager reconcile # preview
+people-manager reconcile --apply # push to Authentik
```
-1. Deploy to the test environment
-2. Run `test.sh`
-3. Break it on purpose, run it again
+One login per person, roles via groups. `TODO: which groups/roles do participants get?`
+
+
---
-## Submit
+## Take it further
-- Branch: `TODO: naming convention`
-- One module per pull request
-- CI must be green
-- Review checklist:
- - [ ] Idempotent install
- - [ ] `test.sh` passes on a clean site
- - [ ] Docs complete
- - [ ] `TODO`
+- **Develop a module** — tappaas.org/generated/develop-a-module
+- **Every json field** — tappaas.org/generated/schemas
+- **Zones and the access model** — tappaas.org/generated/zones
+- **Repository topology** — tappaas.org/generated/design/cicd-git
+- **This deck** — slides.makerfloss.eu/tappaas/how-to/new-module
----
-
-## Pitfalls
-
-- `TODO: the three mistakes reviewers actually see`
-- `TODO`
-- `TODO`
-
----
-
-## Where to go next
-
-- `src/apps/00-Template/` — the canonical starting point
-- `docs/ADR/ADR-007 - TAPPaaS Taxonomy.md`
-- `TODO: contribution guide link`
-
-**Questions?**
+Pick an app you want on a sovereign box. Open an issue first — someone may already
+be packaging it.