# Project Box Project Box is a Go + vanilla web app for managing user projects. Features: - Workspace model mapping each app-user workspace to a host Unix account - Create projects per authenticated user - Auto-create Forgejo repository or onboard an existing repository URL - Auto-create Caddy reverse-proxy route via Admin API (optional) - Manage project env vars - Auto-generate user-scoped systemd service per project - PostgreSQL persistence with startup migration - Authentik forward-auth header support + dev mode demo user - HTTP server on TCP and optional Unix socket - Request/access logs ## Run 1. Copy config: ```bash cp .env.example .env ``` 2. Start PostgreSQL and create database `box`. 3. Start app: ```bash go run . ``` 4. Open `http://localhost:8080`. ## Environment Variables See `.env.example`. Important: - `DEV_MODE=true` uses a demo user and bypasses forward-auth headers. - `DEV_MODE=false` expects auth headers from your reverse proxy: - `X-authentik-username` - `X-authentik-email` - `DB_PROVISION_ENABLED=true` provisions a dedicated PostgreSQL role/database per app. - `DB_PROVISION_ADMIN_URL` is the admin DSN used for provisioning (defaults to `DATABASE_URL`). - `FORGEJO_BASE_URL` + `FORGEJO_TOKEN` enable repository creation. - `FORGEJO_GIT_USERNAME` is used with `FORGEJO_TOKEN` for non-interactive HTTPS git clone/fetch (default `oauth2`). - `FORGEJO_ORG` switches creation from personal repos to org repos. - `UNIX_SOCKET_PATH` enables unix socket listener in addition to `LISTEN_ADDR`. - `CADDY_ROUTE_ENABLED=true` enables route provisioning. - `CADDY_ADMIN_URL` points to the Caddy Admin API (default `http://localhost:2019`). - `CADDY_SERVER_ID` is the HTTP server object id under `apps.http.servers` (default `srv0`). - `CADDY_DOMAIN_SUFFIX` controls generated host as `.` (if empty: `-.local`). - `WEBHOOK_BASE_URL` sets absolute webhook URLs returned by API/UI (recommended behind reverse proxy). ## Caddy API Behavior On project creation, when Caddy routing is enabled, the app appends a route to: - `POST /config/apps/http/servers//routes` Route shape: - `match.host = []` - `handle[0].handler = reverse_proxy` - `handle[0].upstreams[0].dial = unix//projects//app.sock` ## Workspaces and Unix Users - Create one or more workspaces per authenticated user. - Each workspace stores a `unix_user` (must exist on the host). - Project creation requires selecting a workspace. - Service/env files are written under that Unix user's home: - `~/.config/systemd/user/.service` - `~/.config/project-manager///service.env` - The app attempts to run user-systemd commands as that Unix user via: - `sudo -n -u systemctl --user ...` ## Existing Repos - In project creation, set `repo_url` (or fill \"Existing Repo URL\" in UI) to onboard an existing repo. - If `repo_url` is provided, Forgejo repo creation is skipped. - If `repo_url` is empty, the app tries to create a Forgejo repo when Forgejo env vars are configured. ## Auto Deploy via Webhook - Each project gets a unique deploy webhook URL, exposed as `webhook_url` in project API responses and shown in UI. - For repos hosted on the configured Forgejo instance, the app now auto-provisions the repository webhook via Forgejo API. - If auto-provisioning cannot apply (for example external non-Forgejo repo), configure a webhook manually to call `webhook_url`. - Deploy runs only when payload `ref` equals `refs/heads/main`. - Deploy behavior: 1. Clone repo to `~/projects//repo` if missing. 2. Otherwise `fetch origin main` and `reset --hard origin/main`. 3. Build binary to `~/projects//bin/app`. 4. Restart the project user service via `systemctl --user restart`. Notes: - `WEBHOOK_BASE_URL` should be set to an externally reachable base URL so Forgejo can call webhook endpoints. ## Runtime Status and Logs - Per-project runtime endpoints: - `GET /api/projects/:id/status` - `GET /api/projects/:id/logs?lines=200` - `POST /api/projects/:id/reprovision` (retry provisioning for failed/pending projects) - Status is read via `systemctl --user show `. - Logs are read via `journalctl --user -u `. - Both commands are executed as the workspace Unix user via `sudo -n -u ...`. - The app also auto-runs `loginctl enable-linger ` (via sudo) to keep user systemd available without active login. ## Systemd For each project in workspace `` owned by unix user ``, the app writes: - env file: `/projects//.env` - binary path used by systemd: `/projects//bin/app` - unit file: `/.config/systemd/user/projectmgr--.service` Then it attempts as that unix user: - `systemctl --user daemon-reload` - `systemctl --user enable --now ` The generated `.env` is synced from the project env-var configuration and always includes: - `LISTEN_NETWORK=unix` - `LISTEN_ADDRESS=/projects//app.sock` - `DATABASE_URL=postgres://:@.../` If user systemd is not available in the runtime environment, project creation still succeeds and unit files are still generated.