-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Overview
Create preview environments for PRs so that doce.dev can test changes before merging. Each PR should get a dedicated, isolated environment with full Docker support to build and run project containers.
Requirements
- Only same-repo branches (no forks) - PRs from forks should not trigger previews
- Multiple concurrent PR environments supported
- Delete on close - clean up preview resources when PR is closed
- Full Docker access - preview environments must be able to run
dockeranddocker composecommands - Self-configured - admin user and OpenRouter API key are configured on first visit (not pre-configured in CI)
Architecture
Host Requirements (VPS)
- Docker Engine +
docker composeplugin - Node.js 20 + pnpm
- Reverse proxy (Caddy recommended)
- Wildcard DNS:
*.preview.doce.dev→ VPS IP (via Vercel DNS)
Per-PR Isolation
Each PR preview needs:
- Directory:
/opt/doce/previews/pr-{NUMBER}/(full repo checkout at PR SHA) - Data:
data/subdirectory with isolated SQLite DB and project files - Port: Unique port in range
48000-49000(persistent across PR updates) - Service:
doce-preview@{NUMBER}.systemdunit - Subdomain:
pr-{NUMBER}.preview.doce.dev
Key Technical Details
- doce.dev shells out to
docker composedirectly (seesrc/server/docker/compose.ts) - Data paths are relative to
process.cwd()(seesrc/server/projects/paths.ts) - DB path is configurable via
DB_FILE_NAMEenv var (seesrc/server/db/client.ts) - Each preview runs as a separate Node process with isolated working directory
Implementation Checklist
1. VPS Bootstrap
- Provision VPS with Docker, Node 20, pnpm
- Install Caddy reverse proxy
- Configure wildcard DNS in Vercel:
A *.preview.doce.dev → <VPS_IP> - Create
/opt/doce/previewsdirectory structure
2. Process Management
- Create systemd template unit:
doce-preview@.service - Template should:
- Use
WorkingDirectory=/opt/doce/previews/pr-%i - Load env vars from
/opt/doce/previews/pr-%i/.env - Run
node dist/server/entry.mjs - Enable
Restart=always
- Use
3. Port Allocation System
- Create port registry (simple file-based:
/opt/doce/previews/ports/) - Allocate first free port in range
48000-49000for each new PR - Store allocated port in
/opt/doce/previews/pr-{NUMBER}/PORT - Release port on PR close
4. Caddy Configuration
- Create Caddyfile snippet pattern per PR
- Example snippet for
pr-123.preview.doce.dev:pr-123.preview.doce.dev { reverse_proxy 127.0.0.1:<allocated_port> } - Script to add/remove snippets and reload Caddy
5. GitHub Actions Workflow
Create .github/workflows/pr-preview.yml with:
Triggers:
pull_request→opened,reopened,synchronize(deploy)pull_request→closed(teardown)
Deploy job (same-repo only):
jobs:
deploy-preview:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: SSH and deploy
run: |
# 1. Ensure PR directory exists
# 2. Fetch/update repo to PR SHA
# 3. Allocate port (if first time)
# 4. Write .env with PORT, HOST, DB_FILE_NAME
# 5. pnpm install && pnpm build
# 6. systemctl restart doce-preview@{PR_NUMBER}
# 7. Add Caddy snippet and reload
# 8. Comment PR with preview URLTeardown job:
jobs:
teardown-preview:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: SSH and teardown
run: |
# 1. systemctl stop doce-preview@{PR_NUMBER}
# 2. Remove Caddy snippet and reload
# 3. Release port
# 4. Optionally delete PR directorySecrets needed:
SSH_PRIVATE_KEY- for accessing the VPSVPS_HOST- VPS IP/hostnameVPS_USER- SSH user (e.g.,rootoradmin)
6. Environment Variables Per PR
Create .env file in each PR directory:
PORT=<allocated_port>
HOST=127.0.0.1
DB_FILE_NAME=/opt/doce/previews/pr-{NUMBER}/data/db.sqlite
7. Security Considerations
- Only deploy previews for same-repo PRs (Docker access is powerful)
- Preview services run on localhost only (127.0.0.1), accessed via reverse proxy
- Preview host needs access to Docker daemon (add user to
dockergroup)
Example Preview Flow
- PR #123 opened from branch
feature/new-login - GitHub Actions deploys to
/opt/doce/previews/pr-123/ - Allocates port
48015, stores inPORTfile - Creates Caddy snippet →
pr-123.preview.doce.dev - Preview available at
https://pr-123.preview.doce.dev - User visits URL, configures admin + OpenRouter on first setup
- User can create projects, run OpenCode agents, build containers
- PR closed → preview stopped, Caddy snippet removed, port released
Files to Create/Modify
.github/workflows/pr-preview.yml- main workflowscripts/deploy-preview.sh- helper script for SSH deploy (optional)scripts/teardown-preview.sh- helper script for SSH teardown (optional)systemd/doce-preview@.service- systemd unit templatecaddy/Caddyfile.snippet.example- example Caddy snippet
Out of Scope (for now)
- Fork PR previews
- Pre-configured OpenRouter key
- Custom domains per PR
- Preview sharing via link token
- Metrics/log aggregation across previews
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels