# projax — Project Instructions ## Purpose Data backbone for m's complete self-management — projects (digital + physical + strategic + life themes), tasks, lifecycle, milestones. Multiple interfaces consume it. No interface is canonical; each is a view. **Memory group_id:** `projax` **Live spec:** `docs/design.md` (PRD, schema, migration plan, deferred phases) ## Architecture principles 1. **Model first, interfaces second.** The data model is the asset; UIs are replaceable. 2. **First-class non-code projects.** Greenhouse construction, household chores, career positioning, sport goals — same model as code projects. 3. **No CLI required.** m has explicitly opted out of CLI-first. Interfaces are visual / API / Otto-mediated. 4. **Subsumes existing scattered state.** mai.projects (adapter view today), Gitea issues, CalDAV tasks, mBrian topics. Migration not greenfield isolation. 5. **Otto is a consumer, not an owner.** Otto-PWA renders projax data; otto coordinates work *based on* projax; otto does not *define* projax. ## Tech stack (Phase 1) - **Backend**: Go single binary. `pgx` for Postgres. `html/template` + HTMX (CDN), no JS build step. Static assets and migrations bundled with `embed`. - **Database**: msupabase, schema `projax` (new). View `projax.items_unified` reads across `projax.*` + `mai.projects`. RLS off for v1 (single-user, Tailscale-only). - **Hosting**: Dokploy on mlake, domain `projax.msbls.de`, Tailscale-only. - **Tests**: `go test ./...` against `SUPABASE_DATABASE_URL` (skips when unset). ## Layout ``` cmd/projax/ main entrypoint (pool, migrate, serve) db/ migrations (embedded) + runner + integration tests store/ pgx-backed data access web/ handlers, templates, static deploy/dokploy.yaml reference manifest for projax.msbls.de docs/design.md PRD — the source of truth for behaviour ``` ## Branch strategy - `main` = production-deployable - `feat/*` / `fix/*` — short-lived - No `dev` branch initially (small project) - `--no-ff` merges to main ## Post-deploy verification (mandatory) After every `git push origin main`, verify the new binary actually rolled — do NOT trust `/healthz: ok` alone. The pre-3p Phase 3n triage caught 11 commits silently stuck on an old container because the Gitea webhook was missing and healthz kept reporting 200 from the stale binary. The check: ```sh git rev-parse --short HEAD # what you just pushed curl -s https://projax.msbls.de/healthz | tail -1 # "version: " ``` If the SHAs match, the deploy rolled. If they don't, the webhook is broken — inspect `https://mgit.msbls.de/api/v1/repos/m/projax/hooks` (curl --netrc) and confirm hook id 172 exists pointing at `http://mlake.horse-ayu.ts.net:3000/api/deploy/`. The healthz endpoint exposes `Server.Version` (populated from `main.gitCommit` via Dockerfile-time `-ldflags="-X main.gitCommit=..."` reading `git rev-parse --short HEAD`). ## Status - **PRD landed** (`docs/design.md`, 2026-05-15) — schema, lifecycle, interface contracts settled. - **Phase 1 underway**: schema + path trigger + adapter view + Go server + tree/detail/new/classify pages + Docker/Dokploy + README all on a feature branch. - **Phase 2** (CalDAV + Gitea ingest) and **Phase 3** (Excalidraw / MCP / Otto-PWA) are scoped in `docs/design.md` but not started. When a phase-1 follow-up surfaces (auth, hiding mai.projects test rows, mBrian topic-hub auto-link, …), file it against `docs/design.md` §8 first, then split into commits. ## Out of scope (still) - Multi-user - Push notifications + background sync (Otto-PWA's domain) - Public exposure - Generic SaaS-product instincts - CLI surface (m has explicitly opted out) ## Refs - `docs/design.md` — live spec (this is the source of truth) - `mai.projects` schema (msupabase) — primary current state (read-only adapted via `projax.items_unified`) - mBrian conventions (topic-hub pattern) — relevant for non-code project tracking, deferred to Phase 3 - otto session 2026-05-15 — inventory of where project data lives today, justifying this project's existence - `~/.claude/CLAUDE.md` § Git Strategy, Channel Routing, Memory Protocol