# Go web apps

Read [../web.md](../web.md), [baseline.md](baseline.md), [mise.md](mise.md),
[testing.md](testing.md), and [preferred-libraries.md](preferred-libraries.md)
before applying these Go web specifics.

Default to a light server-rendered stack unless the product is clearly
frontend-heavy.

## Default light web stack

- `net/http`
- `html/template` or `text/template` as appropriate
- `embed.FS` for templates and static assets
- plain CSS with semantic variables
- semantic HTML forms and links before client-side JavaScript
- small Node toolchain only for things like Prettier/template formatting when
  needed

This is the default for admin panels, dashboards, release trackers, internal
tools, and server-rendered apps with modest interaction.

## Light web layout

```text
cmd/<app>/main.go
internal/config/...
internal/db/...
internal/<domain>/...
internal/web/ or web/
├── handler.go
└── static/
    ├── head.html.tmpl
    ├── page.html.tmpl
    ├── styles.css
    └── reset.css
```

Use `template.ParseFS` with named shared templates. Keep handlers thin: parse
input, call domain code, render or redirect.

## Security

- Treat form/query values as untrusted.
- Use `bluemonday` when rendering user-provided HTML or Markdown-derived HTML.
- Keep auth/session logic in a domain package; handlers should not duplicate
  password or token handling.
- Prefer `database/sql` with explicit migrations for small SQLite-backed apps.

## Escalate to frontend-heavy only when needed

Escalate to a frontend-heavy stack only when the UI needs rich local state,
complex component composition, desktop integration, drag/drop, long-running event
streams, or substantial client-side interaction. For Wails, prefer Svelte 5 +
TypeScript + Vite; Tailwind and shadcn-svelte remain explicit project choices.
If the page can remain a form and a template, keep it light.
