* feat(deploy): add Azure deployment templates (App Service + ACI)
Adds a deploy/azure/ lane so Open Design can be deployed to Microsoft
Azure from the published runtime image, alongside the existing Docker
Compose and Helm options. Covers the App Service + ACI scope of #1028.
Two Bicep templates run the same single-port Alpine image used by
deploy/docker-compose.yml and charts/open-design:
- app-service.bicep: App Service for Containers with managed HTTPS,
Always On, and health checks on /api/health.
- aci.bicep: a single Azure Container Instances group with a public
FQDN and an /api/health liveness probe.
These are evaluation deployments: state lives on the container's local
disk and is ephemeral. Open Design stores SQLite under OD_DATA_DIR, and
SQLite needs real file locking, which the Azure Files (SMB) storage
behind both App Service and ACI persistence cannot provide without
corruption. App Service sets WEBSITES_ENABLE_APP_SERVICE_STORAGE=false to
keep the data dir on local disk. Durable self-hosting stays on the
Compose named volume or the Helm PVC.
Both wire the daemon's env contract (OD_BIND_HOST/OD_PORT/OD_WEB_PORT/
OD_DATA_DIR/OD_PUBLIC_BASE_URL/OD_ALLOWED_ORIGINS/OD_API_TOKEN) and take
the API token as a secure parameter so it never appears in deployment
outputs.
deploy-azure.sh wraps `az` to create the resource group, generate a
token when one isn't supplied, deploy a lane, and print the URL.
README.md documents both lanes, the ephemeral-data caveat, and the
security trade-offs.
deploy/tests/azure-bicep.test.ts guards the runtime contract and that the
data dir is never mounted to Azure Files; when the bicep CLI is present
it also compiles both templates.
* docs(deploy): add ACI health-check example to Azure quick start
The Alpine runtime image ships only BusyBox sh, so coding agents spawned
by the daemon reported "no POSIX shell in this environment" and could not
run their Bash tool. Install bash (and git, needed for nearly any agent
task) in the runtime stage alongside tini and poppler-utils.
* fix(deploy): move stage-2 asset copies into build stage
Stage 2 COPY commands for skills, design-systems, craft,
prompt-templates, assets, and plugins/_official previously read
from the build context, which couples the Dockerfile to the repo
root. Platforms like Railway that require the Dockerfile directory
to equal the build context could not find these paths.
Move the asset directories into the build stage and let Stage 2
pull them via --from=build, so the Dockerfile is fully
self-contained and works from any context directory.
* fix(deploy): chown volume at runtime so containers work with root-owned mounts
Platforms like Railway mount volumes as root, which overrides the
build-time chown on /app/.od. Run the container as root with tini,
chown the volume directory on start, then drop privileges to the
open-design user via su-exec before launching the daemon.
* Revert "fix(deploy): chown volume at runtime so containers work with root-owned mounts"
This reverts commit f32655d9c2.
* feat(deploy): add one-click Docker/Podman Compose installer for Linux and macOS
- Add install.sh with interactive wizard, Podman/Docker runtime detection,
port conflict check, health verification, and systemd user unit creation
- Add update.sh for image pull and restart with health check
- Add uninstall.sh with interactive user data backup before removal
- Unify CLI output styling with step/ok/warn/error/info helpers
- Add install-guide.md documentation
- Add install.test.ts integration test suite
* feat(deploy): add one-click Docker/Podman Compose installer
- interactive setup wizard with port, image, CORS, memory prompts
- automatic Docker/Podman detection with install guidance
- systemd user unit for Linux, health check polling
- update.sh (pull + restart + prune) and uninstall.sh (backup + cleanup)
- node:test integration suite and install-guide.md
* style(deploy): improve POSIX sh compatibility and systemd unit handling
- unify shell shebangs to #!/usr/bin/env bash
- add pipefail option for better error handling
- fix systemd unit for Podman: remove After/Requires when no service
- correct documentation to match actual uninstall behavior
* fix(deploy): address review feedback for installer scripts
- remove curl | sh path, document clone-first only
- isolate tests via docker-compose.override.yml with unique names
- support both --image <ref> and --image=<ref> in update.sh
- add running container detection before install
* docs(install): remove demo scripts and add MCP note
BYOK/API-mode chats bypass the daemon run path, so attached project
files were saved as message metadata but their readable contents were
not sent to the provider. This adds a web-side attachment context step
for API-mode requests, reusing raw text reads and existing document
preview extraction.
Constraint: Docker PDF previews require pdftotext in the runtime image
Confidence: high
Scope-risk: moderate
Tested: corepack pnpm --filter @open-design/web test -- tests/api-attachment-context.test.ts tests/components/ProjectView.api-empty-response.test.tsx
Tested: corepack pnpm --filter @open-design/web typecheck
Tested: corepack pnpm --filter @open-design/web build
Tested: corepack pnpm guard
Tested: corepack pnpm typecheck
Plan J4 / spec §15.4 / §15.5 / §16 Phase 5.
Three landings:
- deploy/Dockerfile now COPYs plugins/_official/ into the image so
the bundled atom plugins from §3.I3 register on container boot —
without this, registerBundledPlugins() silently no-ops inside the
container and the §23 self-bootstrap promise breaks for hosted
deployments.
- tools/pack/docker-compose.yml ships the canonical hosted-mode
manifest spec §15.4 calls out: two-volume layout (od-data +
od-config) per §15.2, OD_BIND_HOST=0.0.0.0 + OD_API_TOKEN +
OD_NAMESPACE + snapshot retention knobs as env, /api/daemon/status
as the healthcheck endpoint (Phase 1.5). Drop-in usable with
`docker compose -f tools/pack/docker-compose.yml up -d`.
- tools/pack/helm/open-design/{Chart.yaml,values.yaml,README.md}
pins the Helm chart parameter surface for the per-cloud overrides
spec §15.5 enumerates (AWS / GCP / Azure / Aliyun / Tencent /
Huawei / self-hosted). Templates land in the Phase 5 follow-up
PR; the values schema is locked here so the per-cloud override
files (values-<cloud>.yaml) review in isolation.
scripts/guard.ts allowlist gains
`packages/agui-adapter/esbuild.config.mjs` so the new package
passes the residual-JS guard.
Daemon tests stay at 1486/1486 (deploy artifacts only).
Co-authored-by: Tom Huang <1043269994@qq.com>
* Add Docker Compose deployment workflow
* Address Docker deployment review feedback
Harden publishing inputs and temporary credential handling, and tighten Docker runtime defaults requested by the PR review.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix Docker publish build in CI mode
Set CI=true during the image build so pnpm prune can run non-interactively inside Docker.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix Docker runtime dependency layout
Use pnpm deploy for the daemon package so the runtime image includes production dependencies where Node resolves them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Use legacy pnpm deploy in Docker build
Allow pnpm v10 deploy to package the daemon workspace without requiring injected workspace packages.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Align Docker runtime with Node 24
Use Node 24 for both build and runtime stages and update image verification for the workspace daemon dependency layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Remove legacy OD_HOST Docker binding fallback
Use OD_BIND_HOST as the single daemon bind-host setting for Docker deployment and origin validation.
* Update Docker image verifier for daemon dist runtime
Check the packaged daemon dist entrypoint and allow npm from the Node 24 runtime image while still rejecting build-only tools.
* Allow private LAN browser origins for daemon
* Share daemon origin validation helpers
Move browser origin validation into a shared daemon module so tests exercise the production logic and cover the remaining private LAN edge cases.
* Harden Docker Compose port exposure
Bind the Compose deployment to localhost by default and pass the published port through to the daemon origin checks so host-port overrides remain same-origin.
* Keep deployment hosts out of local-only no-origin checks
Require an actual matching Origin before configured deployment origins can satisfy local-only daemon guards, preventing no-Origin remote clients from bypassing those checks.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: mrcfps <mrc@powerformer.com>
Co-authored-by: lefarcen <935902669@qq.com>