5558396bb7
Embed SvelteKit static build in Go binary via go:embed. Event bus for pub/sub with deploy log, instance status, and deploy status events. SSE endpoints for real-time streaming. Frontend SSE client with exponential backoff reconnection. Makefile for build pipeline. Update Phase 12 auth plan with OAuth2/OIDC support.
4.9 KiB
4.9 KiB
Phase 11: Frontend Embed & Real-Time Updates
Status: Done Parent plan: PLAN.md Domain: fullstack
Objective
Build SvelteKit to static files, embed into the Go binary with go:embed, serve from Go, and implement SSE for real-time deploy progress and instance status updates.
Tasks
- Task 1: Configure SvelteKit static adapter to output to
web/build/(already configured) - Task 2: Add
//go:embed web/builddirective in Go —web.goat project root - Task 3: Create Go handler for serving embedded SPA —
internal/api/static.gowith SPA fallback - Task 4: Implement SSE endpoint for deploy logs —
GET /api/deploys/:id/logs(SSE + JSON fallback) - Task 5: Implement SSE endpoint for instance status —
GET /api/eventsstreams instance status changes - Task 6: Create event bus/broadcaster in Go —
internal/events/bus.gowith pub/sub channels - Task 7: Frontend: connect to SSE for deploy progress —
connectDeployLogs()inweb/src/lib/sse.ts - Task 8: Frontend: connect to SSE for instance status — global SSE in
+layout.sveltevia store - Task 9: Handle SSE reconnection in frontend — exponential backoff with jitter in
connectSSE() - Task 10: Build script/Makefile —
make buildbuilds frontend then Go binary
Files to Modify/Create
web/svelte.config.js— already configured with static adapter outputting toweb/build/web.go— root-level embed directive (//go:embed web/build)internal/api/static.go— embedded static file server with SPA fallbackinternal/api/sse.go— SSE endpoints for deploy logs and instance eventsinternal/events/bus.go— event bus for publishing/subscribing to eventsweb/src/lib/sse.ts— SSE client helper with auto-reconnectweb/src/lib/stores/instance-status.ts— Svelte store for real-time instance statusweb/src/routes/+layout.svelte— wired up global SSE connection for instance statusMakefile— build frontend + backendcmd/server/main.go— wired embedded static serving and event businternal/api/router.go— added eventBus to Server, SSE routesinternal/api/deploys.go— removed old JSON stub, replaced by SSE handlerinternal/deployer/deployer.go— added event publishing for deploy logs, status, instance status
Acceptance Criteria
make buildproduces a single Go binary with embedded frontend- Go binary serves the SvelteKit SPA on all non-API routes
- Deploy progress streams in real-time via SSE
- Instance status updates appear without page refresh
- SSE reconnects automatically after network hiccups
Notes
go:embedrequires the embedded directory to be relative to the Go source file- SPA fallback: any request that doesn't match
/api/*getsindex.html - Event bus: simple pub/sub with channels — no external dependency needed
- SSE format:
data: {"type": "deploy_log", "payload": {...}}\n\n - Keep SSE connections lightweight — use context cancellation for cleanup
- WriteTimeout on HTTP server set to 0 to support long-lived SSE connections
- Deploy logs endpoint serves both SSE (Accept: text/event-stream) and JSON (default)
Review Checklist
- All tasks completed
- Single binary serves both API and frontend
- SSE handles multiple concurrent clients (buffered channels, non-blocking publish)
- No goroutine leaks on SSE disconnect (context cancellation + Unsubscribe)
- Build process is reproducible (Makefile)
Handoff to Next Phase
What was implemented
- Event bus (
internal/events/bus.go): In-process pub/sub with topic filtering, buffered subscriber channels (64 events), non-blocking publish. SupportsEventDeployLog,EventInstanceStatus, andEventDeployStatusevent types. - SSE endpoints:
GET /api/deploys/{id}/logsstreams deploy logs with JSON fallback;GET /api/eventsstreams global instance/deploy status changes. - Static file serving:
web.goat project root embedsweb/build/,internal/api/static.goserves SPA with fallback. Mounted via chi'sNotFoundhandler. - Frontend SSE client (
web/src/lib/sse.ts):connectSSE()with exponential backoff + jitter,connectDeployLogs()andconnectGlobalEvents()convenience functions. - Instance status store (
web/src/lib/stores/instance-status.ts): Svelte writable store updated by global SSE connection in+layout.svelte. - Deployer integration:
deployer.gonow publishes deploy log, deploy status, and instance status events viaEventPublisherinterface.
Key integration points for next phase
events.Busis passed to bothapi.NewServeranddeployer.Newapi.NewServernow requires an*events.Busparameter (6th arg before encKey)deployer.Newnow requires anEventPublisherparameter (6th arg before encKey)- HTTP server
WriteTimeoutis 0 to support SSE - The
web.gofile at project root uses package namedockerwatcher(imported asgithub.com/alexei/docker-watcher)