Single-binary todo list application demonstrating HatMax framework patterns with authentication, event-driven architecture, and Postgres-based pub/sub.
A todo list is the archetypical example for a reason: it's familiar, simple to understand, and lets us focus on the framework patterns rather than complex business logic.
┌─────────────────────────────────────────────────────────────────┐
│ Single Binary :8080 │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Auth │ │ List │ │ Admin │ │
│ │ Handler │ │ Handler │ │ Handler │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Auth │ │ List │ │ Admin │ │
│ │ Service │ │ Service │ │ Service │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ │ │ publish │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ PubSub │─────────┼──────┐ │
│ │ │ (NOTIFY) │ │ │ subscribe │
│ │ └──────┬──────┘ │ ▼ │
│ │ │ │ ┌─────────────┐ │
│ │ │ │ │ Audit │ │
│ │ │ │ │ Service │ │
│ │ │ │ └──────┬──────┘ │
│ │ │ │ │ │
│ └────────────────┼────────────────┴────────┘ │
│ ▼ │
│ ┌─────────────┐ │
│ │ sqlc │ Type-safe queries │
│ └──────┬──────┘ │
└──────────────────────────┼──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PostgreSQL │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ auth │ │ ticked │ │ audit │ │
│ │ schema │ │ schema │ │ schema │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
- Single Binary: All features compile to one executable with embedded assets
- HTML + HTMX: Server-side rendering with dynamic interactions
- Postgres PubSub: Domain events via LISTEN/NOTIFY (no external broker)
- Store Pattern: Type-safe queries with sqlc
- Lifecycle Management: Automatic component discovery via
app.Setup() - Feature-based Organization: Code organized under
internal/feat/
- Go 1.24+
- PostgreSQL running locally
- Make
- sqlc (for regenerating queries)
Create database and user:
createdb ticked
createuser -P dev # password: devmake migratemake runAccess the application at http://localhost:8080
make build # Build the binary
make run # Build and run
make clean # Remove binary and logsmake migrate # Run database migrations
make sqlc # Regenerate sqlc queriesmake test # Run testsDefault configuration in config.yaml:
server:
port: ":8080"
database:
host: localhost
port: 5432
user: dev
password: dev
database: tickedhm
sslmode: disable
log:
level: debugOverride with environment variables (prefix TICKED_):
TICKED_SERVER_PORT=:9000 make run
TICKED_DATABASE_HOST=db.example.com make runRoutes follow CQRS-light pattern: verb-noun style, GET for queries, POST for commands.
GET /signup- Signup pagePOST /signup- Register userGET /signin- Login pagePOST /signin- Authenticate userPOST /signout- Logout
GET /list-items- Todo list viewPOST /add-item- Add itemPOST /toggle-item- Toggle item completionPOST /delete-item- Delete item
GET /admin- DashboardGET /admin/list-users- Users listGET /admin/get-user?id=xxx- User detailsPOST /admin/update-roles- Update user rolesPOST /admin/toggle-user- Toggle user active statusGET /admin/list-events- Audit events
Use
GET /debug/routesto list all registered endpoints.