Commit Graph
15 Commits
Author SHA1 Message Date
Tomas Dvorak e881747388 feat: personal access tokens with scoped bearer auth
Add cnp_ personal access tokens so the CLI, MCP server, and external
agents authenticate without a browser session — the agent-first spine
from ROADMAP2 phase A. Modeled on agent_auth_tokens: raw token shown
once, only SHA-256 hash stored.

- user_tokens table (goose migration + sqlc), name/prefix/scope/expiry,
  owner-scoped revoke, last_used_at stamping
- middleware: cnp_ bearer resolution, read scope gates mutations with
  403 SCOPE_INSUFFICIENT, non-admin scopes cap is_admin even for admin
  owners — a token never outranks its scope or its owner
- GET/POST/DELETE /api/v1/user/tokens + OpenAPI + generated types
- Settings UI: create with scope/expiry pickers, one-time token display
  with copy, list with last-used/expiry, confirm-revoke
- docs: OPERATIONS.md section, README feature line

Verified end-to-end against live Postgres: create/list/revoke, read
scope blocks PUT (403), write PAT on admin owner blocked from admin
routes (403), admin scope works, revoked token returns 401.

Authored By: TDvorak <[email protected]>
2026-10-08 14:31:29 +02:00
Tomas DvorakandDevin 0844fab6bf docs: refresh README for public platform and admin console
CI / Infra (Compose + Scripts) (push) Canceled after 0s
CI / Backend (Go) (push) Canceled after 0s
CI / Frontend (React) (push) Canceled after 0s
CI / Compose boot smoke (push) Canceled after 0s
CI / Build & publish images (push) Canceled after 0s
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-22 20:02:11 +02:00
Tomas DvorakandDevin ff356230fe feat: real service runtime — private networks, replicas, lifecycle, rollback
Services now reconcile into actual Docker containers instead of
bookkeeping rows:

- Per-project bridge network with service-name DNS aliases and
  ${{service.KEY}} env expansion (HOST/PORT builtins)
- Replicas, published ports, Traefik domain routing, health checks,
  restart policies persisted on the service spec; spec-hash drift
  recreates containers on redeploy
- Lifecycle API: start/stop/restart/redeploy, live runtime state,
  real image rollback (replaces the fake sleep)
- Manual scale and PUT replicas reconcile live containers; service
  and project delete remove their containers and the project network
- Canvas: real URLs, replica badges, env filter, right-click
  deploy/restart/stop/delete menu, empty state
- Service detail: real lifecycle buttons, live replica/URL strip,
  Networking editor, ${{ }} variable helper
- Fix prebuilt-image pulls racing the tag (drain the pull stream)

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 19:31:19 +02:00
Tomas DvorakandDevin c16b32f56a feat: owner accounts and in-app platform settings
- First registered account becomes admin (users.is_admin, backfilled
  to earliest account); better-auth mirror path does the same
- Public registration closes after bootstrap; admin can reopen it via
  GET/PUT /api/v1/settings (admin-gated) or SIGNUP_ENABLED env
- In-app settings override env vars; secrets stored in app_settings,
  token values never returned by the API
- Saving a Cloudflare Tunnel token pulls and runs a managed
  cloudflared sidecar on the backend's networks; clearing removes it;
  startup restores it from saved settings
- group_add DOCKER_GID grants the non-root backend user Docker socket
  access; install.sh probes the in-container socket gid
- Settings page gains an owner-only Platform section (registration
  toggle, tunnel token, link to Cloudflare dashboard); sign-up page
  stays reachable while registration is open
- OpenAPI spec + generated types updated; manual user creation now
  requires admin

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 18:05:22 +02:00
Tomas DvorakandDevin 060038cb6f feat: swap Redis for Dragonfly, fix remote installs, self-hosted email-only auth
- Replace redis:7-alpine with Dragonfly (Redis-protocol compatible; go-redis
  client unchanged) in root, infra, and backend-dev compose files. Bounded
  defaults --proactor_threads/--maxmemory so it boots on small VPSs.
- Frontend now defaults to same-origin API calls; nginx proxies /api/* to the
  backend (WebSocket-aware, docker DNS resolver for upstream re-resolution).
  Removes the baked localhost:8082 that broke installs reached by IP/domain.
- /auth/bootstrap returns configured OAuth providers; the UI hides
  GitHub/Google buttons unless real credentials exist. Self-hosted stays
  email/password only - OAuth reserved for a future managed offering.
- Sidecar ignores PLACEHOLDER_* OAuth credentials and trusts same-host
  origins dynamically (Origin host == request Host) so remote installs pass
  origin checks without config; cross-origin requests still rejected.
- install.sh writes ENVIRONMENT=production; COOKIE_SECURE=false in
  production is now a startup warning instead of fatal (plain-HTTP installs).
- Bootstrap failure surfaces an error notice instead of silently rendering
  the sign-in page.

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 17:24:43 +02:00
Tomas DvorakandDevin 254d896802 docs: tighten README
- fold "What is" into a single intro paragraph, drop the heading
- compress 15 feature bullets into 8 grouped lines
- drop the port table (already in docs/guides + onboarding)
- collapse quick-start subsections into prose; dev/self-hosted details
  point to docs/guides and infra/
- fold the Configuration section into two lines; footer links inline

170 -> 100 lines, no information lost that docs/ doesn't already carry.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 16:52:54 +02:00
Tomas DvorakandDevin a0141ae552 feat: standalone curl-pipe installer, no clone required
- install.sh works outside a checkout: installs into CONTAINR_DIR
  (default ./containr), downloads docker-compose.yml + .env.example from
  the repo, generates secrets, pulls published images
- CONTAINR_REF selects the git ref for downloads; CONTAINR_BUILD=1 or a
  failed pull fetches the source tarball and builds locally
- env-var overrides (HTTP_PORT/API_PORT/...) are persisted into .env;
  health-wait ports resolve env -> .env -> defaults
- drop fixed `name: containr` from root compose so installs in different
  directories get distinct project names
- README: curl one-liner is the primary install path

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 16:43:42 +02:00
Tomas DvorakandDevin 430370dbc7 docs: add app screenshots, default compose to published :latest images
- docker-compose.yml now references ghcr.io/dvorinka/containr-*:latest with
  pull_policy: missing, so `docker compose up` pulls published images by
  default; CONTAINR_VERSION pins a release tag, build config retained for
  source builds
- install.sh pulls instead of always building (CONTAINR_BUILD=1 or a failed
  pull falls back to a source build)
- README gains a Screenshots section (dashboard, canvas, service detail,
  databases) captured from a live local stack, plus updated install docs

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 16:20:16 +02:00
Tomas DvorakandDevin c07ae2bef6 ci: build images on every change, add install script
- docker job: buildx + GHA cache, GHCR push on main/tags via
  metadata-action tags, Trivy scan (report-only)
- fix: tag pushes now trigger the workflow so releases publish images
- root compose: parameterized host ports, backend healthcheck,
  frontend waits for healthy backend
- install.sh: generates .env secrets, builds, boots, waits for health
- README: easy-install section, port remap docs, CI badge

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 13:19:41 +02:00
Tomas DvorakandDevin 9f3b196032 Overhaul: real metrics, Git integration UI, open-source hygiene, root cleanup
Backend:
- GET /services/:id/metrics with real Docker container stats
- DELETE /git/providers/:id and GET repo branches endpoint

Frontend:
- Service detail shows real telemetry or honest empty states
- Live status distinguishes idle/polling/reconnecting
- Git providers section in Settings; repo+branch pickers in Add Service
- Real logo, compact Projects header, canvas fitView fix
- index.css deduplicated (1725 -> 1384 lines)
- Fixed smoke tests, lint errors, ToastProvider/context unification

Repo hygiene:
- Added LICENSE (MIT), CONTRIBUTING.md, SECURITY.md; rewrote README
- Untracked .env.prod and data/letsencrypt secrets; fixed .gitignore
- Removed legacy root src/internal/cmd and stale configs/docs/artifacts
- Moved guides and design references under docs/

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-15 18:59:40 +02:00
Tomas Dvorak 08cb5754f3 small fix, don't worry about it 2026-04-10 12:02:36 +02:00
Tomas Dvorak 08bd0c6e5c update 2026-02-26 09:41:42 +01:00
Tomas Dvorak 0977d95539 fix 2026-02-23 16:43:39 +01:00
Tomas Dvorak b62cf649d9 update readme 2026-02-16 10:21:45 +01:00
Tomas Dvorak ffa5489dc1 feat: initial implementation of container management platform 2026-02-16 10:18:05 +01:00