# VNCmail+ — setup & deploy runbook

VNCmail+ is VNC's fork of [Bulwark](https://github.com/bulwarkmail/webmail), a
Next.js (App Router) JMAP webmail client for **Stalwart**. Stalwart is the source
of truth; VNCmail+ is the UI. It deploys as a **container on Kubernetes
(microk8s)** at `vncmail.sandbox.vnc.de` — see **[deploy/k8s/](deploy/k8s/README.md)**.

> **License:** AGPL-3.0. Serving a modified VNCmail+ to users over the network
> obligates VNC to offer those users the corresponding source. Keeping this fork
> public (with a "Source" link in the imprint/UI) satisfies that. Loop in legal
> before a public/customer-facing launch if a closed fork is ever desired.

## Architecture — why a container, not Vercel

- Bulwark is a **stateful, long-lived server**: it persists settings-sync, admin
  config/state, and telemetry to a **local data directory** (`/app/data/*`).
- **Vercel serverless was tried and dropped** — its filesystem is read-only
  except `/tmp`, so Bulwark's `mkdir ./data` crashes (`ENOENT /var/task/data`).
  You cannot point its data dirs at a remote host either (they're POSIX paths,
  not URLs). Bulwark's native model is a container + persistent volumes.
- So VNCmail+ runs as a Docker image (`ghcr.io/brvncde-dotcom/vncmail-plus-*`)
  with **4 persistent volumes**, exactly like the existing `bulwark.sandbox.vnc.de`.
- JMAP calls go through **server-side `/api/*` routes** (`proxy.ts`) → server-to-
  server to Stalwart, **no browser CORS**. Config is **runtime-read**.

## Branches (dev-first)

| Branch | Role |
|--------|------|
| `main` | **Production** — CI builds `…/vncmail-plus-beta`. Only updated by an explicit promote. |
| `dev`  | Integration + QA — CI builds `…/vncmail-plus-dev` on push. Default working branch. |
| `vnc/*`| Feature branches for UI work (branch off `dev`, PR into `dev`). |

All VNC customization lives under `vnc/` (see `vnc/VNC-CHANGES.md`).

## Deploy (Kubernetes / microk8s)

Full runbook: **[deploy/k8s/README.md](deploy/k8s/README.md)**. In short:

1. CI builds the image on push to `dev`/`main` → `ghcr.io/brvncde-dotcom/vncmail-plus-dev` (`.github/workflows/docker-publish.yml`).
2. `kubectl apply` the manifests in `deploy/k8s/` (namespace, 4 PVCs, deployment, service, ingress) + a `secret.yaml` (from `secret.example.yaml`) + a `ghcr-pull` image-pull secret.
3. Point `vncmail.sandbox.vnc.de` DNS at the ingress; cert-manager issues TLS.

Runs alongside the existing `bulwark.sandbox.vnc.de`. Match your cluster's
StorageClass / IngressClass / cert issuer to bulwark's (see the runbook).

## Deploy workflow (dev-first — ALWAYS)

Same flow as every other VNC/SRC repo:

1. Work on `dev` (or `vnc/*` → PR into `dev`). Push to `dev` → CI builds the `-dev` image → `kubectl -n vncmail rollout restart deploy/vncmail-plus` to pull it. QA at `vncmail.sandbox.vnc.de`.
2. **Promote to production only on explicit go-live** — merge `dev` → `main`:
   ```bash
   git log dev..main            # MUST be empty — main must have nothing dev lacks (else prod would revert)
   git checkout main && git merge --ff-only dev
   git push origin main         # CI builds the production image
   git checkout dev
   ```
   Then roll the production deployment to the new image (pin its digest — see deploy/k8s/README.md).
   Never push straight to `main`. Never let a dev→main merge silently revert prod.

## Syncing upstream (Bulwark releases)

Bring upstream into `dev` (NOT main), integrate + QA on the dev image, then promote as above:

```bash
git fetch upstream
git checkout dev && git merge upstream/main    # resolve conflicts via vnc/VNC-CHANGES.md; QA on preview
```

## Auth

Basic auth via Stalwart is the default — users sign in with their
`@sandbox.vnc.de` address + password; VNCmail+ authenticates them over JMAP. No
extra config. (SSO via vncdirectory/OIDC is a later option — see
`vnc/vercel.env.template`.)
