# {{APP_NAME}}
A Statum + Spry application, scaffolded by `spry new`.
## Development
```bash
spry dev
```
Builds, runs the app on port 8080 (`--port N` to change) and watches
`src/`, `meson.build` and `web-config.json`: saving a file rebuilds
incrementally — page HTML and resources recompile via the meson codegen
targets — and restarts the app when the build succeeds. A failed build
keeps the previous process running while the compiler errors are shown.
Restarts are cheap: Statum state is client-carried (the browser recovers
transparently) and the static keys in `web-config.json` keep sessions
alive — just refresh. `--fresh` starts from an empty database;
`--no-run` builds once and exits.
The environment below is required for the underlying meson builds (the
`spry dev` child processes set it for you; export it in shells where you
build or run manually):
```bash
export WS_PREFIX="$HOME/.local"
export PKG_CONFIG_PATH="$WS_PREFIX/lib64/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
export XDG_DATA_DIRS="$WS_PREFIX/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"
export LD_LIBRARY_PATH="$WS_PREFIX/lib64${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
meson setup builddir
ninja -C builddir
./builddir/{{APP_NAME}}
```
The server listens on port 8080 (pass another port as the first argument).
Static signing/encryption keys live in `web-config.json` (written by `spry
keys`; gitignored and mode 0600 — never commit it or bake it into images),
so sessions survive a restart. The SQLite store is `./{{APP_NAME}}.sqlite`,
or `SPRY_DB_PATH` when that variable is set.
An admin account is seeded on boot only when BOTH `SPRY_SEED_ADMIN_USERNAME`
and `SPRY_SEED_ADMIN_PASSWORD` are set (the password is never logged);
seeding is skipped silently otherwise. Generate the password — do not
reuse a memorable one — and rotate it after the first login (boot logs a
warning when it is shorter than 12 characters or well-known):
```bash
export SPRY_SEED_ADMIN_USERNAME=admin
export SPRY_SEED_ADMIN_PASSWORD=Xk7-prod-seed-9f2mQv
unset SPRY_SEED_ADMIN_PASSWORD
```
## Layout
| Path | Purpose |
|---|---|
| `src/main.vala` | application wiring: modules, database, pages, actions |
| `src/pages/*.html` | Statum pages, compiled to Vala by `statum-mkpstm` at build time |
| `src/entrypoints/` | one `StatumEntrypoint` per page |
| `src/actions/` | `StatumAction` subclasses |
| `src/resources/` | static resources embedded by `statum-mkres` |
| `MANIFEST.usm` | USM package manifest: `provides bin:{{APP_NAME}}`, build/runtime/manage deps |
| `usm-scripts/` | USM build + install scripts (meson `--prefix=/usr` staging) |
| `web-config.json` | static keys and other configuration (gitignored, 0600) |
Registrations live between `// spry:*-begin/end` markers in `src/main.vala`,
`# spry:*-begin/end` markers in `meson.build` and ``
markers in `src/pages/main.html` (the layout's nav, plus the logged-in-only
`` block); the `spry add` commands edit only
those blocks and are idempotent.
## Styling
`src/pages/main.html` (the layout) loads the Spry CSS framework, served by
SpryModule as a built-in resource — no file to ship:
```html
```
Optional themes (`spry-theme-airy|dwarf|formal|glassy|h2o|living-sky|modern`)
are served the same way; load one *after* the core and set its slug on the
root element:
```html
```
## Growing the app
```
spry dev
spry add page [--route /path]
spry add action
spry add resource
spry add login
spry add register
spry add user-management
spry keys
spry deploy
```
`add login`, `add register` and `add user-management` also grow the layout
nav (a Login/Register link when logged out, a Log-out button once login is
added, a Users link for admins) inside the nav markers.
## Deployment (USM)
`spry deploy [--exec CMD] [--base IMAGE] [--repository FILE]...
[--installer-url URL] [--no-build]` packages the application and builds a
single-stage container image through USM (`usm manifest deploy`): the
generated `MANIFEST.usm` + `usm-scripts/` drive the in-container build and
install, the system package manager provides the platform libraries and
toolchain, and USM repositories provide the Web-Stack. The result is
`{{APP_NAME}}-.image.tar.xz`, loadable with `podman load -i`.
By default USM resolves from the machine's configured repositories — point
it at a specific repository (for example a local Web-Stack repository) with
repeatable `--repository `. The image installs USM itself from
the canonical installer URL baked into usm
(`https://packages.astrologue.nz/install-usm.sh`); pass
`--installer-url file:///…/install-usm.sh` to carry a locally built
installer script into the image instead. `--exec` defaults to
`{{APP_NAME}} 8080`.
`web-config.json` is never packaged (`.usmignore`), so keys are never
baked into the image. Serve pages with ephemeral keys by running the image
directly, or mount the config read-only for full authentication:
```bash
podman load -i {{APP_NAME}}-0.1.image.tar.xz
podman run -d -p 8080:8080 \
-v $PWD/web-config.json:/run/web-config.json:ro \
-e ASTRALIS_CONFIG_PATH=/run/web-config.json \
-e SPRY_DB_PATH=/var/lib/{{APP_NAME}}/{{APP_NAME}}.sqlite \
localhost/{{APP_NAME}}:0.1
```