189 lines
5.7 KiB
Markdown
189 lines
5.7 KiB
Markdown
# HTMX + Go 1.22+ Reactive Patterns
|
|
|
|
> Production-ready HTMX patterns for game backends without JavaScript frameworks.
|
|
|
|
**Last Updated:** 2026-03-14
|
|
**Go Version:** 1.22+
|
|
**HTMX Version:** 1.9.x
|
|
|
|
---
|
|
|
|
## Purpose
|
|
|
|
This example demonstrates building reactive game admin interfaces using **HTMX** with **Go 1.22+** without requiring JavaScript frameworks. Patterns include:
|
|
|
|
- Component composition with Go `template/block` syntax
|
|
- WebSocket-based real-time updates for game events
|
|
- Progressive enhancement for accessibility
|
|
- Systemic consistency for game state management
|
|
- Server-driven UI patterns for game admin panels
|
|
|
|
---
|
|
|
|
## 2026 Best Practices
|
|
|
|
### HTMX Architecture Patterns
|
|
|
|
| Pattern | Use Case | Implementation |
|
|
|---------|----------|----------------|
|
|
| **Boost Mode** | Full page transitions | `hx-boost="true"` on forms |
|
|
| **Push URL** | Browser history sync | `hx-push-url="true"` for navigation |
|
|
| **Polling** | Periodic state refresh | `hx-trigger="every 2s"` for metrics |
|
|
| **WebSocket** | Real-time game events | `hx-ext="ws"` for event streaming |
|
|
| **SSE** | One-way server updates | `hx-ext="sse"` for notifications |
|
|
|
|
### Go 1.22+ Template Features
|
|
|
|
```go
|
|
// Block syntax for component composition
|
|
{{block "player-card" .Player}}
|
|
<div class="player-card" hx-get="/players/{{.Player.ID}}">
|
|
{{.Player.Name}} - Level {{.Player.Level}}
|
|
</div>
|
|
{{end}}
|
|
```
|
|
|
|
### Accessibility (A11Y) Requirements
|
|
|
|
| Requirement | HTMX Pattern | WCAG Level |
|
|
|-------------|--------------|------------|
|
|
| **Focus Management** | `hx-focus="#element"` on updates | AA |
|
|
| **ARIA Live Regions** | `aria-live="polite"` with `hx-trigger` | AA |
|
|
| **Keyboard Navigation** | Standard `<form>` + `<button>` elements | A |
|
|
| **Progressive Enhancement** | Core functionality without HTMX | A |
|
|
|
|
### Systemic Consistency Rulesets
|
|
|
|
```
|
|
GAME STATE CONSISTENCY RULES:
|
|
|
|
1. **SERVER AUTHORITY**
|
|
- All game state originates from server
|
|
- Client never computes game logic
|
|
- HTMX requests always validate against server state
|
|
|
|
2. **OPTIMISTIC UI WITH ROLLBACK**
|
|
- Display changes immediately with hx-confirm
|
|
- Rollback on server rejection with hx-swap="none"
|
|
- Show error states with aria-invalid
|
|
|
|
3. **EVENTUAL CONSistency**
|
|
- Polling interval matches game tick rate
|
|
- WebSocket updates use sequence numbers
|
|
- Conflict resolution via server timestamp
|
|
|
|
4. **BOUNDARY VALIDATION**
|
|
- All hx-get/hx-post paths validate authz
|
|
- Rate limiting per player session
|
|
- Audit logging on state mutations
|
|
```
|
|
|
|
---
|
|
|
|
## Running the Example
|
|
|
|
```bash
|
|
cd examples/go/htmx-patterns
|
|
go mod init htmx-patterns
|
|
go get github.com/gorilla/mux
|
|
go get github.com/yohox/go-htmx
|
|
go run main.go
|
|
```
|
|
|
|
Access the admin panel at `http://localhost:8080/admin`
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
| File | Purpose | Key Patterns |
|
|
|------|---------|--------------|
|
|
| `main.go` | HTTP server, HTMX handlers | Boost, polling, WebSocket |
|
|
| `templates.go` | Template blocks, component composition | `block` syntax, embedded templates |
|
|
| `game-admin-panel.go` | Admin panel handlers | Game state management, authz |
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
+------------------+ +------------------+ +------------------+
|
|
| Browser | | Go Server | | Game Backend |
|
|
| (HTMX client) | | (1.22+) | | (State) |
|
|
+------------------+ +------------------+ +------------------+
|
|
| | |
|
|
| GET /admin | |
|
|
|-----------------------| |
|
|
| | |
|
|
| Template render | Query game state |
|
|
|-----------------------|------------------------|
|
|
| | |
|
|
| WebSocket connect | Subscribe to events |
|
|
|-----------------------|------------------------|
|
|
| | |
|
|
| hx-trigger="every 2s"| |
|
|
|-----------------------| |
|
|
| | |
|
|
| SSE for notifications| |
|
|
|-----------------------|------------------------|
|
|
```
|
|
|
|
---
|
|
|
|
## Component Composition
|
|
|
|
### Template Block Pattern
|
|
|
|
```go
|
|
// templates.go
|
|
var PlayerCardTemplate = template.MustParse(`
|
|
{{block "player-card" .}}
|
|
<div class="card" hx-get="/api/player/{{.ID}}" hx-swap="innerHTML">
|
|
<span class="name">{{.Name}}</span>
|
|
<span class="level">Level {{.Level}}</span>
|
|
<button hx-post="/api/player/{{.ID}/action" hx-vals="js:{action: 'attack'}">
|
|
Attack
|
|
</button>
|
|
</div>
|
|
{{end}}
|
|
`)
|
|
```
|
|
|
|
### Server-Driven Events
|
|
|
|
```go
|
|
// game-admin-panel.go
|
|
func (g *GameAdmin) broadcastEvent(w http.ResponseWriter, r *http.Request) {
|
|
// Game event originates from server
|
|
event := GameEvent{Type: "PLAYER_ACTION", Payload: action}
|
|
g.mu.Lock()
|
|
g.clients[wsID] <- event
|
|
g.mu.Unlock()
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Guardrails Compliance
|
|
|
|
| Rule | Implementation |
|
|
|------|----------------|
|
|
| **PRODUCTION FIRST** | Server code before template tests |
|
|
| **SERVER AUTHORITY** | No client-side game logic |
|
|
| **ACCESSIBILITY** | ARIA labels, keyboard nav, focus management |
|
|
| **RATE LIMITING** | Per-session request limits |
|
|
| **AUDIT LOGGING** | All state mutations logged |
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [AGENT_GUARDRAILS.md](../../docs/AGENT_GUARDRAILS.md) - Core safety protocols
|
|
- [TEST_PRODUCTION_SEPARATION.md](../../docs/standards/TEST_PRODUCTION_SEPARATION.md) - Separation standards
|
|
- [WEB_UI_IMPLEMENTATION.md](../../docs/sprints/SPRINT_002_WEB_UI_IMPLEMENTATION.md) - Web UI patterns
|
|
|
|
---
|
|
|
|
**Authored by:** Claude Code (Anthropic)
|
|
**Document Owner:** Project Maintainers
|
|
**Review Cycle:** Monthly |