Summary
In container mode, APPX_DATA holds only the SQLite DB and TLS certs. Project files live inside the outer container, in the builder-workspace Docker volume under Docker's data-root — not under APPX_DATA. The bootstrap prompt says otherwise ("Data directory: stores the DB, TLS certs, and project files"), which leads to three concrete problems:
- An operator who points
APPX_DATA at a mounted volume for capacity gets almost none of the growth there.
- The project terminal tab is broken: appx reports a host
projectDir that does not exist, and creating a shell in it fails.
teardown.sh --purge-data does not purge project data, because that data is in Docker volumes it never touches.
Found while wiping and reinstalling appx-prod from scratch on 0.1.7 with APPX_DATA=/mnt/appx-prod-volume/appx-data.
Where
cmd/appx/main.go:89 derives the project root from the data dir:
projectRoot := filepath.Join(*dataDir, "projects")
internal/project/manager.go:53 states the invariant that no longer holds:
The projectRoot is the base directory where project subdirectories live (in a co-located deployment it must equal agent-server's WORKSPACE_DIR).
In container mode WORKSPACE_DIR is /workspace inside the container, backed by the builder-workspace volume, so it can never equal a host path under APPX_DATA. ProjectDir() (manager.go:166) therefore returns a path that does not exist, and it is surfaced all the way to the UI:
internal/server/project_handlers.go:26,86 — sets p.ProjectDir on list/get responses
web/src/pages/Project.tsx:161 — <Terminal cwd={projectDir} />
internal/terminal/local.go:94 — cmd.Dir = cwd, which fails when the directory is missing
Related: deploy/system-setup.sh still creates $DATA_DIR/projects (appx:projects 2770) that nothing writes to, and deploy/teardown.sh purges $DATA_DIR but leaves the outer container, builder-workspace, and builder-podman-storage in place.
Observed
Fresh 0.1.7 install, APPX_DATA=/mnt/appx-prod-volume/appx-data, one project test created from the dashboard:
$ curl -sk -b cj https://<host>/api/projects
[{"name":"test", ..., "projectDir":"/mnt/appx-prod-volume/appx-data/projects/test"}]
$ ssh host 'test -d /mnt/appx-prod-volume/appx-data/projects/test && echo EXISTS || echo MISSING'
MISSING
$ ssh host 'docker exec builder-outer ls /workspace'
.pi-global
test # <- the real project directory
$ curl -sk -b cj -X POST https://<host>/api/shell \
-H 'Content-Type: application/json' \
-d '{"cwd":"/mnt/appx-prod-volume/appx-data/projects/test"}'
failed to create shell # HTTP 500 — this is what the Terminal tab does
Where the bytes actually are:
$ du -sh /mnt/appx-prod-volume/appx-data \
/var/lib/docker/volumes/builder-workspace/_data \
/var/lib/docker/volumes/builder-podman-storage/_data
720K /mnt/appx-prod-volume/appx-data # DB + TLS certs + empty projects/
120K /var/lib/docker/volumes/builder-workspace/_data
303M /var/lib/docker/volumes/builder-podman-storage/_data
And after a full purge, all project data survives:
$ bash deploy/teardown.sh --purge-data
purged data: /mnt/appx-prod-volume/appx-data and /home/appx-agent
$ docker volume ls
local builder-podman-storage
local builder-workspace # <- every project file still here
$ docker ps -a
builder-outer Up 2 months # <- still running
Suggested direction
- Pick a source of truth for project storage and make deploy match it. Either back the two named volumes with
APPX_DATA (docker volume create --opt type=none --opt o=bind --opt device=$APPX_DATA/workspace, minding the container's unprivileged uid ownership), or keep them on Docker's data-root and say so in the prompt and docs. Note that if the mounted volume is smaller than the root disk, Docker's data-root may be the better default — the fix may be documentation plus a prompt that no longer promises project files.
- Stop reporting a host
projectDir in container mode. Either omit it and hide the project terminal tab, or point the project terminal into the container (docker exec -w /workspace/<name>) so the tab does something useful. Right now it is a guaranteed 500.
- Drop the unused
$DATA_DIR/projects from system-setup.sh, or keep it only if (1) makes it the real workspace.
- Make
teardown.sh --purge-data remove the outer container plus builder-workspace and builder-podman-storage. Otherwise --purge-data does not purge the data an operator most wants gone, and a reinstall silently inherits the old workspace. (Doing this by hand was required to get a genuinely clean reinstall.)
Summary
In container mode,
APPX_DATAholds only the SQLite DB and TLS certs. Project files live inside the outer container, in thebuilder-workspaceDocker volume under Docker's data-root — not underAPPX_DATA. The bootstrap prompt says otherwise ("Data directory: stores the DB, TLS certs, and project files"), which leads to three concrete problems:APPX_DATAat a mounted volume for capacity gets almost none of the growth there.projectDirthat does not exist, and creating a shell in it fails.teardown.sh --purge-datadoes not purge project data, because that data is in Docker volumes it never touches.Found while wiping and reinstalling appx-prod from scratch on 0.1.7 with
APPX_DATA=/mnt/appx-prod-volume/appx-data.Where
cmd/appx/main.go:89derives the project root from the data dir:internal/project/manager.go:53states the invariant that no longer holds:In container mode
WORKSPACE_DIRis/workspaceinside the container, backed by thebuilder-workspacevolume, so it can never equal a host path underAPPX_DATA.ProjectDir()(manager.go:166) therefore returns a path that does not exist, and it is surfaced all the way to the UI:internal/server/project_handlers.go:26,86— setsp.ProjectDiron list/get responsesweb/src/pages/Project.tsx:161—<Terminal cwd={projectDir} />internal/terminal/local.go:94—cmd.Dir = cwd, which fails when the directory is missingRelated:
deploy/system-setup.shstill creates$DATA_DIR/projects(appx:projects 2770) that nothing writes to, anddeploy/teardown.shpurges$DATA_DIRbut leaves the outer container,builder-workspace, andbuilder-podman-storagein place.Observed
Fresh 0.1.7 install,
APPX_DATA=/mnt/appx-prod-volume/appx-data, one projecttestcreated from the dashboard:Where the bytes actually are:
And after a full purge, all project data survives:
Suggested direction
APPX_DATA(docker volume create --opt type=none --opt o=bind --opt device=$APPX_DATA/workspace, minding the container's unprivileged uid ownership), or keep them on Docker's data-root and say so in the prompt and docs. Note that if the mounted volume is smaller than the root disk, Docker's data-root may be the better default — the fix may be documentation plus a prompt that no longer promises project files.projectDirin container mode. Either omit it and hide the project terminal tab, or point the project terminal into the container (docker exec -w /workspace/<name>) so the tab does something useful. Right now it is a guaranteed 500.$DATA_DIR/projectsfromsystem-setup.sh, or keep it only if (1) makes it the real workspace.teardown.sh --purge-dataremove the outer container plusbuilder-workspaceandbuilder-podman-storage. Otherwise--purge-datadoes not purge the data an operator most wants gone, and a reinstall silently inherits the old workspace. (Doing this by hand was required to get a genuinely clean reinstall.)