8.5 KiB
Xtablo — Go + HTMX Product
What This Is
A Go + HTMX version of Xtablo centered on tablos as collaborative workspaces. v1 established the authenticated Tablos workflow with tasks, files, worker, and deploy scaffolding; v2 adds the collaboration and planning layer around each tablo: native messaging, etapes, scheduled events, personal planning, and Google/Apple sign-in.
Built for a developer who wants a simpler, durable product stack: one Go server, Postgres, server-rendered UI, and no managed chat provider.
Core Value
A user can sign in and run the Tablos workflow — organize work, attach files, discuss, and plan scheduled events — without a JS framework or managed chat provider.
If everything else fails, this must work end-to-end on a single Go binary backed by Postgres and an S3-compatible bucket.
Current Milestone: v2.0 Collaboration, planning, and social sign-in
Goal: Add the collaboration and scheduling capabilities that make tablos useful for ongoing work, while keeping the Go+HTMX/server-owned architecture.
Target features:
- Native per-tablo chat/messaging with real-time delivery, persisted in Postgres, and no third-party chat vendor
- Etapes as one-level wrappers around tasks: a task may belong to one etape, and an etape cannot itself have a parent
- Google and Apple sign-in flows integrated into the existing server-managed session model
- Individual planning view for each authenticated user, including scheduled events that belong to tablos like tasks do
Requirements
Validated
(None yet — ship to validate)
Active
- Existing users can continue using email/password sessions while new users can sign in with Google or Apple
- Tablo detail pages support native discussions/messages persisted in Postgres
- Real-time message delivery works without a managed messaging provider
- Users can organize tasks under one-level etapes inside a tablo
- Users can create, edit, view, and delete scheduled events attached to tablos
- Each authenticated user has an individual planning view aggregating their events
Out of Scope
- Managed chat/messaging providers — no Stream Chat, Ably, Pusher, Firebase Realtime Database, or equivalent for v2 chat
- Stripe / billing — defer monetization until product loop is validated
- Public booking widget —
apps/externalrewrite not in v1 (may return in a later milestone) - Client portal —
apps/clientsmagic-link experience deferred - Admin app —
apps/admininternal tooling deferred - Notes / rich documents inside a Tablo — not part of this milestone
- Managed auth platforms — no Clerk/Auth0/Lucia; Google and Apple are identity providers only, with Xtablo still owning users and sessions
- Mobile / Expo app — out of scope for this rewrite
- Supabase as a runtime dependency — Postgres only; Supabase Auth / RLS replaced by Go-side authz
- The existing
go-backend/directory — treated as scratch; new code lives in a freshbackend/Go package
Context
- The JS monorepo (this repository) is the source of truth for product behavior and is fully mapped in
.planning/codebase/(ARCHITECTURE, STACK, STRUCTURE, INTEGRATIONS, CONVENTIONS, CONCERNS, TESTING). Use these to derive expected behavior — but the rewrite is free to simplify both schema and visuals. - The DB schema will change during the rewrite — the JS version's Supabase schema is a reference, not a constraint. The user wants to be in the loop on schema decisions for each domain (users/sessions, tablos, tasks, files).
- Visuals will also change — no requirement to mirror the existing UI; Tailwind + HTMX patterns drive the new look.
go-backend/already contains real scaffolding (router, sqlc, air, tailwind input). It is not the foundation — a freshbackend/package will be created.- Developer is comfortable in Go and wants a low-dependency, server-rendered stack going forward.
- v2 UI can stay functional and plain; the user will provide a more polished visual design later. The milestone should focus on working behavior and clean integration points.
Constraints
- Tech stack: Go (server + templates) + HTMX + Tailwind + Postgres + sqlc — no JS framework, no managed BaaS
- Auth: Server-managed sessions remain authoritative; Google/Apple sign-in may verify external ID tokens but must end by issuing Xtablo's own session cookie
- Chat: No third-party chat provider; messages and read state live in Postgres, with real-time delivery handled by the Go app
- Storage: Files in S3-compatible object storage (Cloudflare R2 to start)
- Architecture: One web server binary + one background worker (same repo, possibly same binary with subcommand)
- Deploy target: Single VPS / container — no Kubernetes
- Planning: Events belong to tablos, but each individual user can access their own planning view
- Etapes: One level only — a task can have at most one parent/wrapper, and a parent cannot itself have a parent
- Scope discipline: v2 adds collaboration and planning only; billing, booking, portal, admin, notes, and mobile remain deferred
Key Decisions
| Decision | Rationale | Outcome |
|---|---|---|
| Rewrite in Go + HTMX (no SPA) | Simpler stack, developer preference, product pivot | — Pending |
| Built-in sessions, no 3rd-party auth | Avoid vendor coupling; sessions are well-trodden ground | — Pending |
| Drop Supabase (keep Postgres) | Owning the auth + RLS story in Go is simpler than maintaining the boundary | — Pending |
Fresh backend/ Go package, set go-backend/ aside |
Existing scaffold has decisions to revisit; cleaner to start over | — Pending |
| v1 = Tablos workflow only (Tasks + Files), defer chat/billing/booking/portal/admin | Focus the rewrite around the load-bearing user loop first | — Pending |
| Single binary + background worker, single VPS deploy | Matches the "simpler stack" thesis; avoid orchestration cost early | — Pending |
| User-in-the-loop on Postgres schema for each domain | Schema is changing from JS version; explicit review before sqlc generation | — Pending |
| v2 chat is native, not vendor-backed | User explicitly does not want third-party chat; Postgres + Go should be enough for the first real-time version | — Pending |
| Google/Apple are identity providers only | Preserve server-owned users/sessions while allowing social sign-in | — Pending |
| Etapes are one-level wrappers around tasks | Matches the requested mental model and avoids recursive planning complexity | — Pending |
| Planning is individual, events remain tablo-scoped | Lets users see their schedule while preserving tablos as the source of work context | — Pending |
Evolution
This document evolves at phase transitions and milestone boundaries.
After each phase transition (via /gsd-transition):
- Requirements invalidated? → Move to Out of Scope with reason
- Requirements validated? → Move to Validated with phase reference
- New requirements emerged? → Add to Active
- Decisions to log? → Add to Key Decisions
- "What This Is" still accurate? → Update if drifted
After each milestone (via /gsd-complete-milestone):
- Full review of all sections
- Core Value check — still the right priority?
- Audit Out of Scope — reasons still valid?
- Update Context with current state
Phase History
- Phase 1: Foundation — Completed 2026-05-14. Fresh
backend/Go package boots a web server, renders an HTMX-driven base layout, connects to local Postgres with goose migrations. FOUND-01..FOUND-05 satisfied; user-approved manual walkthrough. Two inline justfile/tailwind fixes during UAT (commitfix(01): guard sqlc on empty queries and correct tailwind paths). - Phase 7: deploy-v1 — Completed 2026-05-15. Multi-stage Dockerfile (assets→builder→distroless nonroot), docker-compose.prod.yaml with 4 services (postgres/web/worker/caddy), Caddyfile with
{$DOMAIN}TLS, README runbook covering first-deploy/rollback/incident. DEPLOY-01..DEPLOY-05 satisfied. 3 UAT items (Docker build, compose config, live smoke test) pending on a Docker-equipped machine. - Milestone v2.0 started: Collaboration, planning, and social sign-in — Started 2026-05-15. Scope: native per-tablo chat, one-level etapes, Google/Apple sign-in, and individual planning with tablo events.
Last updated: 2026-05-15 after starting milestone v2.0