diff --git a/docs/03-deployment/CROMERO_DAPP_DEPLOYMENT.md b/docs/03-deployment/CROMERO_DAPP_DEPLOYMENT.md
new file mode 100644
index 00000000..c384dcd7
--- /dev/null
+++ b/docs/03-deployment/CROMERO_DAPP_DEPLOYMENT.md
@@ -0,0 +1,78 @@
+# CROMERO Dapp — Phoenix Deploy
+
+Deploys [`d-bis/CROMERO`](https://gitea.d-bis.org/d-bis/CROMERO) (a
+Vite + React + thirdweb v5 dapp) to
+`https://d-bis.org/ecosystem/cromero/`.
+
+## Pipeline
+
+1. Push to `main` on `d-bis/CROMERO` triggers
+ `.gitea/workflows/deploy-to-phoenix.yml`, which POSTs
+ `{repo, sha, branch, target: "default"}` to the Phoenix Deploy API.
+2. Phoenix runs the registered target (see
+ `phoenix-deploy-api/deploy-targets.json`):
+ `bash scripts/deployment/phoenix-deploy-cromero-from-workspace.sh`.
+3. The script builds the staged workspace (`npm ci && npm run build`),
+ copies `dist/` through `r630-01` into NPMplus CT `10233`, and lands
+ files in `/var/www/ecosystem/cromero/`.
+4. Healthcheck: `https://d-bis.org/ecosystem/cromero/` must return
+ HTTP 200 with `
",
+ "attempts": 12,
+ "delay_ms": 5000,
+ "timeout_ms": 15000
+ }
+ },
{
"repo": "d-bis/proxmox",
"branch": "main",
diff --git a/scripts/deployment/phoenix-deploy-cromero-from-workspace.sh b/scripts/deployment/phoenix-deploy-cromero-from-workspace.sh
new file mode 100755
index 00000000..cf6042a7
--- /dev/null
+++ b/scripts/deployment/phoenix-deploy-cromero-from-workspace.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
+if [[ -f "$PROJECT_ROOT/scripts/lib/load-project-env.sh" ]]; then
+ # shellcheck source=/dev/null
+ source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
+fi
+if [[ -f "$PROJECT_ROOT/config/ip-addresses.conf" ]]; then
+ # shellcheck source=/dev/null
+ source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
+fi
+
+PHOENIX_DEPLOY_WORKSPACE="${PHOENIX_DEPLOY_WORKSPACE:-}"
+NPMPLUS_PROXMOX_HOST="${NPMPLUS_PROXMOX_HOST:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
+NPMPLUS_VMID="${NPMPLUS_VMID:-10233}"
+NPMPLUS_DEPLOY_ROOT="${NPMPLUS_DEPLOY_ROOT:-/var/www/ecosystem/cromero}"
+NPMPLUS_DATA_ROOT="${NPMPLUS_DATA_ROOT:-/opt/npmplus/html/ecosystem/cromero}"
+PUBLIC_URL="${PUBLIC_URL:-https://d-bis.org/ecosystem/cromero/}"
+DRY_RUN="${DRY_RUN:-0}"
+SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new)
+TMP_ARCHIVE="/tmp/cromero-dapp-dist-$$.tgz"
+
+usage() { printf 'Usage: %s [--dry-run]\n' "$(basename "$0")"; }
+log() { printf '[cromero-phoenix] %s\n' "$*" >&2; }
+die() { printf '[cromero-phoenix][FATAL] %s\n' "$*" >&2; exit 1; }
+need_cmd() { command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"; }
+run() { if [[ "$DRY_RUN" == 1 ]]; then printf '[dry-run] %q ' "$@" >&2; printf '\n' >&2; else "$@"; fi; }
+cleanup() { rm -f "$TMP_ARCHIVE"; }
+trap cleanup EXIT
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --dry-run) DRY_RUN=1; shift ;;
+ -h|--help) usage; exit 0 ;;
+ *) die "unknown arg: $1" ;;
+ esac
+done
+
+for cmd in ssh scp tar curl node npm; do need_cmd "$cmd"; done
+[[ -n "$PHOENIX_DEPLOY_WORKSPACE" ]] || die "PHOENIX_DEPLOY_WORKSPACE is required"
+[[ -d "$PHOENIX_DEPLOY_WORKSPACE" ]] || die "staged workspace missing: $PHOENIX_DEPLOY_WORKSPACE"
+
+log "building CROMERO from staged workspace: $PHOENIX_DEPLOY_WORKSPACE"
+pushd "$PHOENIX_DEPLOY_WORKSPACE" >/dev/null
+if [[ -f package-lock.json ]]; then
+ run npm ci --no-audit --no-fund
+else
+ run npm install --no-audit --no-fund
+fi
+run env \
+ VITE_THIRDWEB_CLIENT_ID="${VITE_THIRDWEB_CLIENT_ID:-}" \
+ VITE_PROJECT_WALLET_ADDRESS="${VITE_PROJECT_WALLET_ADDRESS:-0x3E309b87fA79092767531a0A6F5B6c3480737c5e}" \
+ VITE_CHAIN_138_RPC="${VITE_CHAIN_138_RPC:-https://rpc.d-bis.org}" \
+ VITE_CHAIN_138_EXPLORER="${VITE_CHAIN_138_EXPLORER:-https://explorer.d-bis.org}" \
+ npm run build
+[[ -f dist/index.html ]] || die "build produced no dist/index.html"
+tar -C "$PHOENIX_DEPLOY_WORKSPACE" -czf "$TMP_ARCHIVE" dist
+popd >/dev/null
+
+log "deploying dist/ through $NPMPLUS_PROXMOX_HOST to CT $NPMPLUS_VMID:$NPMPLUS_DEPLOY_ROOT"
+run scp "${SSH_OPTS[@]}" "$TMP_ARCHIVE" "root@$NPMPLUS_PROXMOX_HOST:/tmp/cromero-dapp-dist.tgz"
+if [[ "$DRY_RUN" == 1 ]]; then
+ log "dry-run complete"
+ exit 0
+fi
+ssh "${SSH_OPTS[@]}" "root@$NPMPLUS_PROXMOX_HOST" bash -s -- "$NPMPLUS_VMID" "$NPMPLUS_DEPLOY_ROOT" "$NPMPLUS_DATA_ROOT" <<'INNER'
+set -euo pipefail
+vmid="$1"
+deploy_root="$2"
+data_root="$3"
+pct exec "$vmid" -- bash -lc "
+set -euo pipefail
+mkdir -p '$data_root' /var/www/ecosystem
+if [ -e '$deploy_root' ] && [ ! -L '$deploy_root' ]; then rm -rf '$deploy_root'; fi
+ln -sfn '$data_root' '$deploy_root'
+rm -rf /tmp/cromero-dist
+"
+pct push "$vmid" /tmp/cromero-dapp-dist.tgz /tmp/cromero-dapp-dist.tgz
+pct exec "$vmid" -- bash -lc "
+set -euo pipefail
+rm -rf /tmp/cromero-dist
+mkdir -p /tmp/cromero-dist '$data_root'
+tar -xzf /tmp/cromero-dapp-dist.tgz -C /tmp/cromero-dist
+find '$data_root' -mindepth 1 -maxdepth 1 -exec rm -rf {} +
+cp -R /tmp/cromero-dist/dist/. '$data_root/'
+chown -R root:root /opt/npmplus/html/ecosystem /var/www/ecosystem
+chmod 755 /opt/npmplus/html /opt/npmplus/html/ecosystem '$data_root' /var/www /var/www/ecosystem
+if command -v docker >/dev/null 2>&1; then
+ docker exec npmplus sh -lc 'rm -rf /var/www && ln -s /data/html /var/www && nginx -t && nginx -s reload'
+fi
+rm -rf /tmp/cromero-dist /tmp/cromero-dapp-dist.tgz
+"
+rm -f /tmp/cromero-dapp-dist.tgz
+INNER
+
+log "verifying $PUBLIC_URL"
+body="$(curl -fsS --max-time 20 "$PUBLIC_URL")" || die "public URL failed: $PUBLIC_URL"
+printf '%s' "$body" | grep -F '
' >/dev/null || die "public URL missing React root"
+log "CROMERO Phoenix deploy completed"
diff --git a/scripts/deployment/phoenix-deploy-dbis-portal-live-from-workspace.sh b/scripts/deployment/phoenix-deploy-dbis-portal-live-from-workspace.sh
new file mode 100755
index 00000000..b4eae43b
--- /dev/null
+++ b/scripts/deployment/phoenix-deploy-dbis-portal-live-from-workspace.sh
@@ -0,0 +1,186 @@
+#!/usr/bin/env bash
+# Deploy the DBIS public portal from a Phoenix Deploy API staged DBIS checkout.
+#
+# The DBIS repo is normally a submodule of Gov_Web_Portals/gov-portals-monorepo
+# and depends on the parent workspace package @public-web-portals/shared. This
+# wrapper builds a temporary monorepo-shaped workspace, overlays the staged DBIS
+# source into it, syncs that tree to CT 7804, then rebuilds/restarts DBIS.
+
+set -euo pipefail
+
+die() {
+ echo "ERROR: $*" >&2
+ exit 1
+}
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
+
+source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
+[ -f "$PROJECT_ROOT/.env" ] && set +u && source "$PROJECT_ROOT/.env" 2>/dev/null || true && set -u
+
+PHOENIX_REPO_ROOT="${PHOENIX_REPO_ROOT:-$PROJECT_ROOT}"
+PHOENIX_DEPLOY_WORKSPACE="${PHOENIX_DEPLOY_WORKSPACE:-}"
+GOV_PORTALS_REPO_URL="${GOV_PORTALS_REPO_URL:-https://gitea.d-bis.org/Gov_Web_Portals/gov-portals-monorepo.git}"
+GOV_PORTALS_REF="${GOV_PORTALS_REF:-main}"
+
+VMID_GOV_PORTALS="${VMID_GOV_PORTALS:-7804}"
+IP_GOV_PORTALS_DEV="${IP_GOV_PORTALS_DEV:-192.168.11.54}"
+PROXMOX_HOST="${DBIS_PORTAL_PROXMOX_HOST:-${PROXMOX_HOST_GOV_PORTALS:-192.168.11.14}}"
+CT_APP_DIR="${DBIS_PORTAL_CT_DIR:-/srv/gov-portals}"
+SERVICE_NAME="${DBIS_PORTAL_SERVICE:-gov-portal-DBIS}"
+DBIS_PORT="${DBIS_PORT:-3001}"
+
+[[ -d "$PHOENIX_REPO_ROOT" ]] || die "PHOENIX_REPO_ROOT does not exist: $PHOENIX_REPO_ROOT"
+[[ -n "$PHOENIX_DEPLOY_WORKSPACE" ]] || die "PHOENIX_DEPLOY_WORKSPACE is required"
+[[ -d "$PHOENIX_DEPLOY_WORKSPACE" ]] || die "staged DBIS workspace missing: $PHOENIX_DEPLOY_WORKSPACE"
+[[ "$CT_APP_DIR" != "/" ]] || die "refusing to deploy into /"
+
+TMP_DIR="$(mktemp -d)"
+BUILD_CONTEXT="$TMP_DIR/gov-portals"
+ARCHIVE="$TMP_DIR/gov-portals-dbis-live.tgz"
+REMOTE_ARCHIVE="/tmp/gov-portals-dbis-live-${PHOENIX_DEPLOY_SHA:-manual}-$$.tgz"
+
+cleanup() {
+ rm -rf "$TMP_DIR"
+}
+trap cleanup EXIT
+
+echo "Preparing DBIS live deploy context"
+echo " DBIS source: $PHOENIX_DEPLOY_WORKSPACE"
+echo " parent repo: $GOV_PORTALS_REPO_URL#$GOV_PORTALS_REF"
+echo " target: CT $VMID_GOV_PORTALS ($IP_GOV_PORTALS_DEV), service $SERVICE_NAME, port $DBIS_PORT"
+
+git_auth_args=()
+if [[ -n "${GITEA_TOKEN:-}" ]]; then
+ git_auth_args=(-c "http.extraHeader=Authorization: token ${GITEA_TOKEN}")
+fi
+
+git "${git_auth_args[@]}" clone --depth 1 --branch "$GOV_PORTALS_REF" "$GOV_PORTALS_REPO_URL" "$BUILD_CONTEXT"
+
+rm -rf "$BUILD_CONTEXT/DBIS"
+mkdir -p "$BUILD_CONTEXT/DBIS"
+tar \
+ --exclude=.git \
+ --exclude=node_modules \
+ --exclude=.next \
+ --exclude='*.tsbuildinfo' \
+ -C "$PHOENIX_DEPLOY_WORKSPACE" \
+ -cf - . | tar -C "$BUILD_CONTEXT/DBIS" -xf -
+
+tar \
+ --exclude=.git \
+ --exclude=node_modules \
+ --exclude=.next \
+ --exclude='*.tsbuildinfo' \
+ -C "$BUILD_CONTEXT" \
+ -czf "$ARCHIVE" .
+
+echo "Uploading deploy archive to Proxmox host $PROXMOX_HOST"
+scp -q -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$ARCHIVE" "root@$PROXMOX_HOST:$REMOTE_ARCHIVE"
+
+echo "Pushing archive into CT $VMID_GOV_PORTALS"
+ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "root@$PROXMOX_HOST" \
+ "pct push $VMID_GOV_PORTALS '$REMOTE_ARCHIVE' '$REMOTE_ARCHIVE'"
+
+echo "Extracting, building, and restarting DBIS inside CT $VMID_GOV_PORTALS"
+ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "root@$PROXMOX_HOST" \
+ "pct exec $VMID_GOV_PORTALS -- bash -s" <
/dev/null 2>&1; then
+ apt-get update -qq
+ apt-get install -y -qq curl ca-certificates
+fi
+
+NODE_MAJOR="\$(node -p 'process.versions.node.split(\".\")[0]' 2>/dev/null || echo 0)"
+if [ "\$NODE_MAJOR" -lt 20 ]; then
+ curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
+ apt-get install -y nodejs
+ hash -r
+fi
+
+export PATH="/usr/local/bin:/usr/bin:/bin:\$PATH"
+if ! command -v pnpm >/dev/null 2>&1; then
+ npm install -g pnpm@8.15.0
+ hash -r
+fi
+PNPM_BIN="\$(command -v pnpm || true)"
+if [ -z "\$PNPM_BIN" ]; then
+ for candidate in /usr/local/bin/pnpm /usr/bin/pnpm; do
+ if [ -x "\$candidate" ]; then
+ PNPM_BIN="\$candidate"
+ break
+ fi
+ done
+fi
+[ -n "\$PNPM_BIN" ] || { echo "pnpm is required but was not found after install" >&2; exit 1; }
+
+cd "\$CT_APP_DIR"
+"\$PNPM_BIN" install --frozen-lockfile
+"\$PNPM_BIN" --filter portal-dbis build
+
+cat > "/etc/systemd/system/\$SERVICE_NAME.service" </dev/null
+CT_SCRIPT
+
+ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "root@$PROXMOX_HOST" "rm -f '$REMOTE_ARCHIVE'" >/dev/null 2>&1 || true
+
+echo "DBIS live deployment complete."
+echo "Local origin check: http://$IP_GOV_PORTALS_DEV:$DBIS_PORT/"