T9/Phase 7: deploy 4-container compose + Caddy reverse proxy
- docker-compose.yml: 4 services (db, api, spa, worker), Next.js removed - Dockerfile.api: Bun base, install, run - Dockerfile.worker: Bun base, install, run - Dockerfile.spa: multi-stage (Bun build -> Caddy serve), fixed lockfile + workspace stubs - Caddyfile: serve SPA + reverse-proxy /api/* + /mcp, SPA fallback routing - Old Node worker stopped, replaced with new Bun worker - Old Next.js server on :3000 stopped - BASELINE.md: Phase 7 Deploy section added - DEPLOY.md: deploy/rollback/debug guide added
This commit is contained in:
+38
@@ -60,3 +60,41 @@
|
|||||||
- `Dockerfile.spa` — Multi-stage: Bun build → Caddy serve
|
- `Dockerfile.spa` — Multi-stage: Bun build → Caddy serve
|
||||||
- `Caddyfile` — Serves dist on :80, reverse-proxies /api/* and /mcp to api:3000
|
- `Caddyfile` — Serves dist on :80, reverse-proxies /api/* and /mcp to api:3000
|
||||||
- `docker-compose.yml` — 4 services: db, api, spa, worker (old web service removed)
|
- `docker-compose.yml` — 4 services: db, api, spa, worker (old web service removed)
|
||||||
|
|
||||||
|
## Phase 7 — Deploy (completed)
|
||||||
|
|
||||||
|
**Deploy time:** 2026-08-01T02:40Z
|
||||||
|
**Commit:** `fc59431140329bd93223dfae3c72406d9e02646e`
|
||||||
|
**Branch:** `redesign/ui-v2`
|
||||||
|
|
||||||
|
### Image SHAs
|
||||||
|
| Image | SHA256 |
|
||||||
|
|-------|--------|
|
||||||
|
| `projecte-api` | `fc46878d1618bb3a0d6a43d645a21cad14caa1bb6eaf773e4e32579a268adc10` |
|
||||||
|
| `projecte-spa` | `1cced4e61fb35d31df53225b3c8f5863a3d581b82ed961c13286bd5e3f940f48` |
|
||||||
|
| `projecte-worker` | `7fc57170100f6cf6b12439835f5700383c7c4570eecf3c4ab3f06fa739d10d07` |
|
||||||
|
|
||||||
|
### Compose file SHA
|
||||||
|
`bb21417829c866048509f81881304e81b5e29430270a278e0b3a77caa68f8b1b`
|
||||||
|
|
||||||
|
### Verification results
|
||||||
|
| Check | Result |
|
||||||
|
|-------|--------|
|
||||||
|
| `docker compose ps` — all 4 services running, db healthy | ✅ |
|
||||||
|
| `curl :3000/api/health` — 200 + `{"status":"ok"}` | ✅ |
|
||||||
|
| `curl :3000/` — 200 + HTML | ✅ |
|
||||||
|
| Login (user@example.com) — token received | ✅ |
|
||||||
|
| `/api/domains` — 2 domains returned | ✅ |
|
||||||
|
| `/mcp` — endpoint reachable (requires API key) | ✅ |
|
||||||
|
| All 13 page routes return 200 | ✅ (13/13) |
|
||||||
|
|
||||||
|
### Container state
|
||||||
|
| Container | Status | Ports |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| `project-e-db` | Running (healthy) | :5432 |
|
||||||
|
| `project-e-api` | Running | :3001 |
|
||||||
|
| `project-e-spa` | Running | :3000 |
|
||||||
|
| `project-e-worker` | Running | — |
|
||||||
|
|
||||||
|
### URL
|
||||||
|
- http://10.0.0.204:3000 — **LIVE** (SPA served by Caddy, API reverse-proxied)
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
:80 {
|
:80 {
|
||||||
root * /usr/share/caddy
|
root * /usr/share/caddy
|
||||||
file_server
|
encode gzip
|
||||||
|
|
||||||
@api path /api/* /mcp*
|
route /api/* {
|
||||||
reverse_proxy @api api:3000
|
reverse_proxy api:3000
|
||||||
|
}
|
||||||
|
|
||||||
handle_errors {
|
route /mcp* {
|
||||||
respond 404 "Not Found"
|
reverse_proxy api:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
route {
|
||||||
|
try_files {path} /index.html
|
||||||
|
file_server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
# Project E — Deploy Guide
|
||||||
|
|
||||||
|
## How to redeploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ProjectE
|
||||||
|
|
||||||
|
# Pull latest
|
||||||
|
git pull origin redesign/ui-v2
|
||||||
|
|
||||||
|
# Rebuild images
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
# Restart stack
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to roll back
|
||||||
|
|
||||||
|
If the new stack fails:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ProjectE
|
||||||
|
|
||||||
|
# Stop the new stack
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# Restart the old worker (Node) from the legacy compose
|
||||||
|
# (The old compose file is preserved in git history)
|
||||||
|
# docker compose -f docker-compose.legacy.yml up -d worker
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to view logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# All services
|
||||||
|
docker compose logs --tail=50 -f
|
||||||
|
|
||||||
|
# Specific service
|
||||||
|
docker compose logs --tail=50 -f api
|
||||||
|
docker compose logs --tail=50 -f spa
|
||||||
|
docker compose logs --tail=50 -f worker
|
||||||
|
docker compose logs --tail=50 -f db
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to debug
|
||||||
|
|
||||||
|
### API health check
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3001/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### SPA health check
|
||||||
|
```bash
|
||||||
|
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/
|
||||||
|
```
|
||||||
|
|
||||||
|
### API through reverse proxy
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Login test
|
||||||
|
```bash
|
||||||
|
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/credentials \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d email:user@example.com | \
|
||||||
|
python3 -c "import sys,json; print(json.load(sys.stdin).get(token,))")
|
||||||
|
echo "Token: $TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check container health
|
||||||
|
```bash
|
||||||
|
docker inspect project-e-db --format {{.State.Health.Status}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart a single service
|
||||||
|
```bash
|
||||||
|
docker compose restart api
|
||||||
|
docker compose restart spa
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rebuild a single service
|
||||||
|
```bash
|
||||||
|
docker compose build spa
|
||||||
|
docker compose up -d --force-recreate spa
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet → :3000 → Caddy (SPA container)
|
||||||
|
├── /api/* → api:3000 (Hono/Bun)
|
||||||
|
├── /mcp* → api:3000 (Hono/Bun)
|
||||||
|
└── /* → index.html (SPA fallback)
|
||||||
|
|
||||||
|
API (:3001, direct) → PostgreSQL (:5432)
|
||||||
|
Worker → PostgreSQL
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important notes
|
||||||
|
|
||||||
|
- The `project-e-pg-data` Docker volume contains the live database. **Do not delete it.**
|
||||||
|
- The `apps/web-legacy/` directory contains the old Next.js app for reference. **Do not delete it.**
|
||||||
|
- Port 3000 is the SPA (Caddy), port 3001 is the API directly (for debugging).
|
||||||
|
- The MCP endpoint requires a valid API key (separate from JWT auth).
|
||||||
|
EOF cd ~/ProjectE && cat > DEPLOY.md << 'EOF'
|
||||||
|
# Project E — Deploy Guide
|
||||||
|
|
||||||
|
## How to redeploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ProjectE
|
||||||
|
|
||||||
|
# Pull latest
|
||||||
|
git pull origin redesign/ui-v2
|
||||||
|
|
||||||
|
# Rebuild images
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
# Restart stack
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to roll back
|
||||||
|
|
||||||
|
If the new stack fails:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/ProjectE
|
||||||
|
|
||||||
|
# Stop the new stack
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# Restart the old worker (Node) from the legacy compose
|
||||||
|
# (The old compose file is preserved in git history)
|
||||||
|
# docker compose -f docker-compose.legacy.yml up -d worker
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to view logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# All services
|
||||||
|
docker compose logs --tail=50 -f
|
||||||
|
|
||||||
|
# Specific service
|
||||||
|
docker compose logs --tail=50 -f api
|
||||||
|
docker compose logs --tail=50 -f spa
|
||||||
|
docker compose logs --tail=50 -f worker
|
||||||
|
docker compose logs --tail=50 -f db
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to debug
|
||||||
|
|
||||||
|
### API health check
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3001/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### SPA health check
|
||||||
|
```bash
|
||||||
|
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/
|
||||||
|
```
|
||||||
|
|
||||||
|
### API through reverse proxy
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3000/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Login test
|
||||||
|
```bash
|
||||||
|
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/credentials \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d password:<password> | \
|
||||||
|
python3 -c "import sys,json; print(json.load(sys.stdin).get(token,))")
|
||||||
|
echo "Token: $TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check container health
|
||||||
|
```bash
|
||||||
|
docker inspect project-e-db --format {{.State.Health.Status}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart a single service
|
||||||
|
```bash
|
||||||
|
docker compose restart api
|
||||||
|
docker compose restart spa
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rebuild a single service
|
||||||
|
```bash
|
||||||
|
docker compose build spa
|
||||||
|
docker compose up -d --force-recreate spa
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet → :3000 → Caddy (SPA container)
|
||||||
|
├── /api/* → api:3000 (Hono/Bun)
|
||||||
|
├── /mcp* → api:3000 (Hono/Bun)
|
||||||
|
└── /* → index.html (SPA fallback)
|
||||||
|
|
||||||
|
API (:3001, direct) → PostgreSQL (:5432)
|
||||||
|
Worker → PostgreSQL
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important notes
|
||||||
|
|
||||||
|
- The `project-e-pg-data` Docker volume contains the live database. **Do not delete it.**
|
||||||
|
- The `apps/web-legacy/` directory contains the old Next.js app for reference. **Do not delete it.**
|
||||||
|
- Port 3000 is the SPA (Caddy), port 3001 is the API directly (for debugging).
|
||||||
|
- The MCP endpoint requires a valid API key (separate from JWT auth).
|
||||||
+12
-2
@@ -2,11 +2,21 @@
|
|||||||
FROM oven/bun:1.3 AS builder
|
FROM oven/bun:1.3 AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package.json bunfig.toml ./
|
# Copy workspace manifests + lockfile
|
||||||
COPY apps/web/package.json apps/web/
|
COPY package.json bunfig.toml bun.lock ./
|
||||||
|
COPY apps/web/package.json apps/web/package.json
|
||||||
|
COPY apps/api/package.json apps/api/package.json
|
||||||
|
COPY apps/worker/package.json apps/worker/package.json
|
||||||
|
COPY packages/db/package.json packages/db/package.json
|
||||||
|
COPY packages/shared/package.json packages/shared/package.json
|
||||||
|
|
||||||
|
# Install dependencies (workspace-aware)
|
||||||
RUN bun install --frozen-lockfile 2>/dev/null || bun install
|
RUN bun install --frozen-lockfile 2>/dev/null || bun install
|
||||||
|
|
||||||
|
# Copy full web app source
|
||||||
COPY apps/web ./apps/web
|
COPY apps/web ./apps/web
|
||||||
|
|
||||||
|
# Build the SPA
|
||||||
RUN cd apps/web && bun run build
|
RUN cd apps/web && bun run build
|
||||||
|
|
||||||
# Serve stage
|
# Serve stage
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ services:
|
|||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}
|
||||||
volumes:
|
volumes:
|
||||||
- project-e-pg-data:/var/lib/postgresql/data
|
- project-e-pg-data:/var/lib/postgresql/data
|
||||||
- ./drizzle/0000_first_mauler.sql:/docker-entrypoint-initdb.d/0000_first_mauler.sql:ro
|
|
||||||
networks:
|
networks:
|
||||||
- project-e-network
|
- project-e-network
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
Reference in New Issue
Block a user