12 Commits
Author SHA1 Message Date
Tomáš DvořákandDevin 7547375cc2 feat(notifications): producers — backups, agent health, scans, upgrades (#49)
* feat(filters): dynamic filter framework — typed schema, URL state, FilterBar

Port of dflow's filter.utils pattern, adapted to Containr:

- lib/dynamic-filter.ts: FilterConfig schema (search/select/multiselect/
  boolean/date-range/status), FilterEngine with client-side apply,
  derived options with counts, active-filter tracking, removal.
- lib/use-dynamic-filter.ts: filter state lives in ?f.<key> search
  params — filtered views are shareable links. useFilterState exposes
  URL state before data loads (server-backed filters); useDynamicFilter
  adds the engine over fetched data.
- shared/components/FilterBar.tsx: renders a schema as compact controls
  + active-filter chips, matching design tokens.
- Applied: audit logs (server-backed — state in URL, params to API),
  builds (server-backed + client date-range), activity (severity to the
  server query, category/search on the fetched page).
- 8 unit tests for the engine.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(filters): erasableSyntaxOnly compat + BuildStatus cast

- Constructor parameter properties are banned under erasableSyntaxOnly —
  declare fields explicitly.
- listBuilds status param needs the BuildStatus type, not raw string.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* feat(notifications): producers round-out — backups, agent health, scans, upgrades

Four new emitters behind insertUserNotification:

- Backups: createBackupProcess notifies the database owner on
  completion (with size) and on failure (docker-down, snapshot error).
- Agent health: StartAgentHealthSweep marks agents offline after 3 min
  without heartbeat and back online on recovery — admins notified on
  each transition.
- Security scans: Scanner.OnScanComplete callback notifies the project
  owner with critical/high/total counts + score; scans with findings
  get a distinct title.
- Upgrades: daily check against the latest GitHub release; admins
  notified once per new tag (deduped via app_settings). Version stamped
  into the image via Dockerfile ARG + ldflags on tag builds; "dev"
  disables the check.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-09 12:12:21 +02:00
Tomas DvorakandDevin 925199633b feat(mobile): Containr companion app — Expo/RN thin client
Phone app v1 (Phase I): PAT auth against any instance, secure-store
credentials, dark UI matching the design system.

- Overview: service status counts, per-project health dots, deploy feed
- Services/Projects: status badges, drill-down detail
- Service detail: start/stop/restart/redeploy/sleep/wake, env-doctor
  issues, deployment history + rollback
- Logs: 300-line tail, 5s poll, stderr highlighted
- Databases: status, start/stop/restart, backup-now
- Settings: server info, disconnect

CI: mobile job (tsc + expo lint) gated on a dedicated app/mobile paths
filter so non-mobile PRs skip it entirely.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-09 05:08:48 +02:00
Tomas DvorakandDevin 57f8b4f56e ci: release MCP binaries + path-gate heavyweight jobs
- build-cli.sh also builds containr-mcp-<os>-<arch> per platform; the
  existing containr-* asset glob in the release job picks them up
- paths-filter 'changes' job gates backend/frontend/smoke/docker on PRs —
  docs-only PRs skip ~10min of compute; skipped checks satisfy protection
- docker job requires success() explicitly (skipped parents would pass
  '!= failure'); release requires docker success to never release stale images

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-09 01:07:18 +02:00
Tomáš Dvořák f9ae5b962c chore: add FUNDING.yml — GitHub Sponsors button
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
CI / Release (push) Canceled after 0s
2026-10-04 19:50:34 +02:00
Tomas DvorakandDevin 9a2aa7267b fix(ci): recreate release instead of --clobber upload
gh release upload --clobber races GitHub's asset tombstones and 422s
intermittently on reruns. Delete-then-create is deterministic; the
git tag is kept.

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-23 11:57:37 +02:00
Tomas DvorakandDevin a99f2e461e feat(ci): release pipeline on merge to main
After tests + image publish, a release job bumps the tag via
conventional commits (github-tag-action, default_bump=false so
docs/chore merges skip releasing), retags :main images in GHCR as
semver+latest (tag pushes via GITHUB_TOKEN do not retrigger CI),
cross-compiles the CLI for 5 platforms, and cuts a GitHub Release
with generated notes and checksums. Manual v* tag pushes get the
same release treatment. CLI --version now reports the tag via the
previously dead -X ldflags.

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-23 11:44:37 +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 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 d0bdf0a441 ci: retry frontend smoke check
nginx needs a few seconds for its entrypoint scripts; the single-shot
curl raced the container start. Same retry loop as the backend check,
with a log dump on failure.

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-17 20:46:33 +02:00
Tomas DvorakandDevin 0f984fb579 ci: inject throwaway auth secrets into smoke boot
Production validation rejects the compose placeholder secrets, so the
backend panicked at config load and the container went unhealthy.
Generate ephemeral BETTER_AUTH_SECRET and BETTER_AUTH_INTERNAL_TOKEN
per run; verified locally that the container reaches healthy.

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-17 20:41:06 +02:00
Tomas DvorakandDevin b61203f908 ci: compose boot smoke + GHCR image publish
Adds a smoke job that boots postgres/redis/backend/frontend/traefik via
docker compose, polls the backend /health endpoint, verifies the
frontend responds, and tears down. Adds a tag-gated images job that
builds and pushes backend/frontend images to GHCR on v* tags.

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-17 18:38:54 +02:00
Tomas Dvorak 08cb5754f3 small fix, don't worry about it 2026-04-10 12:02:36 +02:00