build: Dockerfile + Dokploy manifest + README
- Multi-stage Dockerfile: golang:1.25-alpine builder → distroless static runtime as nonroot. Image weighs ~15 MB. Embeds templates, static assets and migrations into the single binary. - deploy/dokploy.yaml documents the Dokploy app for projax.msbls.de: Tailscale-only, healthz path, single replica, secret PROJAX_DB_URL. Translates to the Dokploy UI; not auto-applied. - README rewritten as runbook: env vars, route table, test command, deploy notes, trust model (Tailscale + no auth in v1, defer to Supabase auth if it ever outgrows the fence), schema summary. - .dockerignore strips .git, .m, .claude, docs, tests from build ctx. - .gitignore covers ad-hoc binary and dist artefacts. Verified locally: docker build succeeds, container responds to /healthz and / against msupabase via --network host.
This commit is contained in:
9
.dockerignore
Normal file
9
.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.git
|
||||||
|
.worktrees
|
||||||
|
.m
|
||||||
|
.claude
|
||||||
|
.mcp.json
|
||||||
|
*.md
|
||||||
|
!README.md
|
||||||
|
docs/
|
||||||
|
**/*_test.go
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/projax
|
||||||
|
/dist/
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# syntax=docker/dockerfile:1.6
|
||||||
|
|
||||||
|
FROM golang:1.25-alpine AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/projax ./cmd/projax
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/static-debian12:nonroot
|
||||||
|
COPY --from=build /out/projax /projax
|
||||||
|
ENV PROJAX_LISTEN_ADDR=:8080
|
||||||
|
EXPOSE 8080
|
||||||
|
USER nonroot:nonroot
|
||||||
|
ENTRYPOINT ["/projax"]
|
||||||
93
README.md
93
README.md
@@ -1,41 +1,78 @@
|
|||||||
# projax
|
# projax
|
||||||
|
|
||||||
m's personal project + self-management system. The data backbone for everything m tracks — code projects, physical projects, strategic threads, life themes, daily ops. Multiple interfaces consume the same model. Otto is one of them, not the owner.
|
m's personal data backbone for self-management — areas of life, projects within them, and aggregated views over tasks that live elsewhere. Subsumes scattered state currently held in `mai.projects`, CalDAV task lists, Gitea issues, and mBrian topic hubs.
|
||||||
|
|
||||||
## Status
|
Spec: `docs/design.md`. Project conventions: `CLAUDE.md`.
|
||||||
|
|
||||||
Bootstrap. Inventor designs schema + lifecycle + interface contracts before any code lands.
|
## Run locally
|
||||||
|
|
||||||
## Vision
|
```
|
||||||
|
export PROJAX_DB_URL=postgres://postgres:<pw>@<msupabase-host>:6789/postgres?sslmode=disable
|
||||||
|
go run ./cmd/projax
|
||||||
|
```
|
||||||
|
|
||||||
- **Single source of truth** for what m is doing, has done, will do, is sitting on, is procrastinating about.
|
Defaults:
|
||||||
- **Multiple interfaces** (none is canonical): Otto-PWA, browser UI, Excalidraw views, CalDAV task lists, CLI is *not* a requirement (m explicitly opted out).
|
- `PROJAX_LISTEN_ADDR=:8080`
|
||||||
- **Project Code** as the lingua franca — concise, human-readable, ambiguity-free across all interfaces.
|
- `PROJAX_AUTO_MIGRATE=on` (set to `off` to skip on-start migration apply)
|
||||||
- **Subsumes today's scattered state**: `mai.projects`, Gitea issues, CalDAV tasks, mBrian topic-hubs, Dokploy services, ~/dev/CLAUDE.md files. Migration over time.
|
|
||||||
- **Goes beyond code**: physical projects (mGreen greenhouse, household), strategic threads (career positioning), life themes (sport goals, learning) — all first-class.
|
|
||||||
|
|
||||||
## Out of scope (for now)
|
Visit `http://localhost:8080/`. Routes:
|
||||||
|
|
||||||
- Replacing mai.projects-the-table. projax will likely *own* it instead, or sync, or supersede gradually — design pass decides.
|
| Route | Purpose |
|
||||||
- Multi-user. m only.
|
| ------------------------- | ------------------------------------------------------ |
|
||||||
- Public exposure / sharing. Local-first, runs on m's infra.
|
| `GET /` | Tree of areas + projects, plus orphan mai.projects |
|
||||||
- Becoming a generic project-management product. Built for m's stack and tone.
|
| `GET /i/{path}` | Item detail; editable for projax, read-only for mai |
|
||||||
|
| `POST /i/{path}` | Save edits to a projax-native item |
|
||||||
|
| `POST /i/{path}/promote` | Promote a mai.projects orphan into a projax item |
|
||||||
|
| `GET /new?parent={path}` | Create a new item (area at root, project under parent) |
|
||||||
|
| `POST /new` | Submit |
|
||||||
|
| `GET /admin/classify` | Orphan list with inline HTMX promote |
|
||||||
|
| `GET /healthz` | DB ping |
|
||||||
|
| `GET /static/style.css` | Embedded CSS |
|
||||||
|
|
||||||
## Architecture (TBD by inventor)
|
## Test
|
||||||
|
|
||||||
Open questions for the first design pass:
|
DB-backed integration tests are skipped automatically when no `PROJAX_DB_URL` / `SUPABASE_DATABASE_URL` is set:
|
||||||
|
|
||||||
- Schema shape: relational (Postgres? SQLite?) vs graph (mBrian-style) vs hybrid
|
```
|
||||||
- Project Code generation: shortcode pattern, collision rules, retro-fitting to existing 30+ projects
|
SUPABASE_DATABASE_URL=postgres://... go test ./...
|
||||||
- Lifecycle states + transitions (idea → active → paused → done → archived?)
|
```
|
||||||
- How interfaces share the model — REST API? GraphQL? direct DB read?
|
|
||||||
- Where the data lives: msupabase schema? Own DB? mBrian sub-graph?
|
|
||||||
- Integration shape with: mai.* (tasks, workers, sessions), Gitea, CalDAV, mBrian, Otto-PWA, Excalidraw
|
|
||||||
- Migration: 28 active mai.projects + ~15 test rows + 4 archived — how to clean up and import
|
|
||||||
|
|
||||||
## Refs
|
Covers: migration idempotency, path-trigger semantics (nest, rename, re-parent, cycle, structural rules), `items_unified` source split + promotion hiding, every HTTP handler, and a Promote round-trip.
|
||||||
|
|
||||||
- mai.projects current state: msupabase `mai.projects` table
|
## Deploy (Dokploy on mlake)
|
||||||
- otto's project inventory walk-through (head session 2026-05-15)
|
|
||||||
- mBrian topic-hubs (paliad, hlckm, tech-msbls, ai, professional-positioning, schadensberechnung-lizenzanalogie, flexsiebels-brand)
|
`deploy/dokploy.yaml` is a reference manifest. Translate to the Dokploy UI:
|
||||||
- CalDAV calendars on `dav.msbls.de`: work, plan, privat, mhome, mcalendar, logm, people
|
|
||||||
|
1. Create an app `projax` with `Dockerfile` build context = repo root.
|
||||||
|
2. Set domain `projax.msbls.de` (Tailscale-only — do **not** publish through public reverse proxy).
|
||||||
|
3. Secret `PROJAX_DB_URL` pointing at msupabase's Tailscale address on port 6789 with the `postgres` user.
|
||||||
|
4. Health check path `/healthz`.
|
||||||
|
5. Single replica.
|
||||||
|
|
||||||
|
The image is a distroless static container running as `nonroot`. Total image size is well under 20 MiB because everything (templates, CSS, migrations) is `embed`-bundled.
|
||||||
|
|
||||||
|
## Trust model (v1)
|
||||||
|
|
||||||
|
Single-user, Tailscale-only. No authentication layer. The deployment relies on:
|
||||||
|
|
||||||
|
- Dokploy app exposed only to Tailscale (no public DNS / reverse proxy outside Tailscale).
|
||||||
|
- msupabase reachable only inside the same Tailscale network.
|
||||||
|
- `PROJAX_DB_URL` is a Dokploy secret, not in the repo.
|
||||||
|
|
||||||
|
If projax later needs auth (multi-device, shared with people, etc.), the natural fit is the same Supabase auth used by flexsiebels — defer until projax has actually outgrown the Tailscale fence.
|
||||||
|
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
```
|
||||||
|
projax.items (id, kind[], title, slug, path, parent_id, content_md,
|
||||||
|
aliases[], metadata jsonb, status, pinned, archived,
|
||||||
|
start_time, end_time, created_at, updated_at, deleted_at)
|
||||||
|
projax.item_links (item_id, ref_type, ref_id, rel, note, metadata, created_at)
|
||||||
|
projax.items_unified VIEW = projax.items UNION ALL adapter over mai.projects
|
||||||
|
```
|
||||||
|
|
||||||
|
A BEFORE trigger maintains `items.path` via parent walk and enforces structural rules (areas at root, projects not at root, no cycles). An AFTER trigger rewrites descendant paths on rename / re-parent.
|
||||||
|
|
||||||
|
A mai.projects row drops out of `items_unified` as soon as any `projax.item_links` row with `ref_type='mai-project'` points back at it — that's how the Promote flow makes the duplicate disappear without ever mutating `mai.projects`.
|
||||||
|
|
||||||
|
Migrations live in `db/migrations/`, are embedded into the binary, and applied lexicographically on boot.
|
||||||
|
|||||||
35
deploy/dokploy.yaml
Normal file
35
deploy/dokploy.yaml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Dokploy app: projax
|
||||||
|
#
|
||||||
|
# Apply via Dokploy UI on mlake, or as a reference for the manual setup.
|
||||||
|
# Tailscale-only; no public exposure. Single replica, single tenant (m).
|
||||||
|
#
|
||||||
|
# Environment expected (set via Dokploy secrets, NEVER commit):
|
||||||
|
# PROJAX_DB_URL postgres://postgres:<pw>@<msupabase-tailscale-ip>:6789/postgres?sslmode=disable
|
||||||
|
# PROJAX_LISTEN_ADDR :8080 (default; Dokploy maps to public port)
|
||||||
|
# PROJAX_AUTO_MIGRATE on (default; set "off" to bypass embedded migrations on boot)
|
||||||
|
|
||||||
|
name: projax
|
||||||
|
service: projax
|
||||||
|
image:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
domain:
|
||||||
|
host: projax.msbls.de
|
||||||
|
port: 8080
|
||||||
|
https: true
|
||||||
|
healthcheck:
|
||||||
|
path: /healthz
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
resources:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 128Mi
|
||||||
|
replicas: 1
|
||||||
|
restart: unless-stopped
|
||||||
|
env:
|
||||||
|
- PROJAX_LISTEN_ADDR=:8080
|
||||||
|
- PROJAX_AUTO_MIGRATE=on
|
||||||
|
secrets:
|
||||||
|
- PROJAX_DB_URL
|
||||||
Reference in New Issue
Block a user