- /admin/projects list + /admin/projects/edit gallery editor (AdminLayout chrome, session-guarded). Upload/replace images per slot, captions, add/remove, Instagram reel URL. Save -> cja_projects -> rebuild -> live. - adminprojects API (list/get/save); media path validation (local paths only). - runner /rebuild endpoint: build public/ + commit after structured edits. - Ownership: app/ + public/ now owned by carlos-arias-agent:caweb so the agent can rebuild its own output; www serves via the caweb group. Documented in SETUP.md — never build as root. Verified end to end: upload image -> save to gallery -> rebuild -> image live on the project page and served. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
3.1 KiB
3.1 KiB
Console — operational setup (server state, not in git)
Records the OS-level setup the admin console depends on. Reproduce this on any new server; none of it lives in the repo.
Agent runtime
- OS user
carlos-arias-agent— system user,/usr/sbin/nologin, no sudo. The headless agent runs as this user. Never as root. - HOME
/var/lib/carlos-arias-agent(0700). Contains.claude.jsonwithhasTrustDialogAccepted: truefor the repo path (headless can't click the trust dialog). - Claude binary relocated to
/usr/local/bin/claude(self-contained 257M ELF)./rootis0750, so the agent could not reach root's install. - Token in
agents/.env→CLAUDE_CODE_OAUTH_TOKEN(git-ignored, 0600). Aclaude setup-tokenvalue (sk-ant-oat01-…). Rotate it — it passed through a chat transcript during setup.
Permissions model (no chown-to-www needed)
- Shared group
caweb; members:carlos-arias-agent+www. app/,brand/,api/db,api/cli,agents/→ groupcaweb,g+rwX, setgid on dirs (new files inherit the group).public/andpublic-preview/→ groupcaweb,g+rwX, setgid, world-read. nginx (www) only needs read to serve, so the agent can own build output and nginx still serves it — no privileged chown step.
Build model
- Isolated preview:
PREVIEW_OUT=../public-preview/<jobId>PREVIEW_BASE=/_preview/<jobId>thencd app && npm run build(supported natively byapp/astro.config.mjs). - Publish: normal build to
public/, thengit commit(rollback point).
Verified working (2026-07-23)
Confined agent, as carlos-arias-agent with the token: reads the repo, writes
source, runs a 24-page isolated preview build (~7.5s), output servable by nginx.
Full edit→preview→serve loop proven end to end.
Still to build (Phase 1 remainder)
- Runner service
agents/console/server.mjs(Node, binds127.0.0.1:3011):run/preview/publish/discard/ping/auth/logout. - nginx:
/devconsole/*+/admin/*→auth_requestagainst a PHP admin-session check → proxy to127.0.0.1:3011. Runner never exposed directly. - Wire
DevConsole.astroto the runner. - systemd unit to keep the runner alive.
Build ownership (IMPORTANT)
app/andpublic/are owned by carlos-arias-agent:caweb. The agent runs all builds and must own its output to overwrite it.- Never run
npm run buildas root — it creates root-owned files the agent then can't overwrite (EPERM in vite prepare-out-dir). If it happens, fix with:chown -R carlos-arias-agent:caweb app public. - Rebuild via the runner (
POST /devconsole/rebuild) orsudo -u carlos-arias-agent env HOME=/var/lib/carlos-arias-agent … npm run build. - www serves
public/via the sharedcawebgroup — no chown-to-www needed.
Phase 2/3 delivered
- Media upload:
POST /api/media/upload(GD/ffmpeg optimise → app/public/media). - Projects admin:
/admin/projects(list) +/admin/projects/edit?slug=(gallery upload/replace + Instagram URL). Saves to cja_projects, then rebuilds. POST /devconsole/rebuildregenerates the live site after structured edits.