docs: update dev environment config and documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 20:51:39 +00:00
parent b414502062
commit 5c78a4051a
3 changed files with 162 additions and 243 deletions

View File

@@ -1,154 +1,135 @@
# DevServer01 Environment Setup & Operations Guide # ResolutionFlow Dev Environment Setup & Operations Guide
## Server Overview ## Server Overview
- **Hostname:** devserver01 - **Provider:** Hostinger KVM VPS (srv1522117)
- **IP Address:** 192.168.0.9 - **IP Address:** 46.202.92.250
- **OS:** Ubuntu 25.10 (Questing Quokka) - **OS:** Ubuntu 24.04 LTS
- **CPU:** AMD Ryzen 3 PRO 3200GE w/ Radeon Vega Graphics - **CPU:** 2 vCPU cores
- **RAM:** ~5.2GB (some reserved by Vega iGPU) - **RAM:** 8GB
- **Disk:** 57GB LVM volume (`/dev/mapper/ubuntu--vg-ubuntu--lv`), ~47GB free - **Disk:** 100GB NVMe SSD
- **Hardware:** Lenovo ThinkCentre Micro Tower - **Swap:** 4GB (`/swapfile`, swappiness=10)
## Docker Setup ## Architecture
Docker was installed via the official convenience script: All services run as Docker containers on the host, managed via SSH or from the VS Code Server integrated terminal.
```bash ```
curl -fsSL https://get.docker.com | sh Host (root@srv1522117)
sudo usermod -aG docker michael ├── Traefik → reverse proxy + auto SSL (Let's Encrypt)
├── VS Code Server → browser IDE at https://code.resolutionflow.com
└── ResolutionFlow Stack
├── resolutionflow_frontend → Vite/React on port 5173
├── resolutionflow_backend → FastAPI/Uvicorn on port 8000
└── resolutionflow_postgres → PostgreSQL 16 + pgvector on port 5432
``` ```
Docker Compose is included with this installation. ## Access URLs
## Code-Server | Service | URL |
|---|---|
| VS Code Server | https://code.resolutionflow.com |
| Frontend (dev) | http://46.202.92.250:5173 |
| Backend API | http://46.202.92.250:8000 |
| API Docs | http://46.202.92.250:8000/docs |
### Overview ## Docker Layout
Code-server (codercom/code-server) runs in a Docker container, providing a browser-accessible VS Code instance at `https://192.168.0.9:8080`. It uses a custom Dockerfile to include additional tools like `gh` (GitHub CLI). ```
/docker/
### Custom Dockerfile ├── traefik/
│ ├── docker-compose.yml → Traefik reverse proxy
Location: `~/docker/Dockerfile.code-server` │ └── .env → ACME_EMAIL for Let's Encrypt
└── vscode/
```dockerfile ├── docker-compose.yml → VS Code Server
FROM codercom/code-server:latest └── .env → CODE_PASSWORD
USER root
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \
apt update && apt install -y gh && \
rm -rf /var/lib/apt/lists/*
USER coder
``` ```
### Docker Compose File Project lives inside the VS Code Server Docker volume:
```
Location: `~/docker/docker-compose.yml` /var/lib/docker/volumes/vscode_vscode-data/_data/resolutionflow/
```yaml
services:
code-server:
build:
context: .
dockerfile: Dockerfile.code-server
container_name: code-server
environment:
- PASSWORD=<password>
volumes:
- ./code-server/config/data:/home/coder/.local/share/code-server
- ./code-server/config/extensions:/home/coder/.local/share/code-server/extensions
- ./code-server/config/.config/code-server:/home/coder/.config/code-server
- ./projects:/projects
- ./code-server/certs:/certs
- /home/michael/.claude:/home/coder/.claude
ports:
- 8080:8443
command: --bind-addr 0.0.0.0:8443 --cert /certs/cert.pem --cert-key /certs/key.pem /projects
user: "1000:1000"
restart: unless-stopped
``` ```
### Key Details ## VS Code Server
- **Container user:** `coder` (UID 1000) - **Container user:** `coder` (UID 1000)
- **Home directory inside container:** `/home/coder` - **Home directory:** `/home/coder`
- **Projects mount:** Host `~/docker/projects` → Container `/projects` - **Project location:** `/home/coder/resolutionflow`
- **Claude Code config mount:** Host `/home/michael/.claude` → Container `/home/coder/.claude` - **Host volume path:** `/var/lib/docker/volumes/vscode_vscode-data/_data`
- **HTTPS:** Self-signed certs via a custom Homelab CA - **Access URL:** `https://code.resolutionflow.com`
- **Internal port:** 8443 (code-server listens here) - **HTTPS:** Auto-provisioned via Traefik + Let's Encrypt
- **External port:** 8080 (mapped to 8443 internally)
- **Access URL:** `https://192.168.0.9:8080`
### SSL Certificates ### Compose File Location
`/docker/vscode/docker-compose.yml`
Location: `~/docker/code-server/certs/` ## Traefik
A custom Certificate Authority (CA) was created for the homelab: Handles reverse proxying and automatic SSL for all services. HTTP automatically redirects to HTTPS.
- `ca.key` — CA private key ### Adding A New Service Behind Traefik
- `ca.crt` — CA certificate (imported into browsers to trust all homelab certs)
- `key.pem` — code-server private key
- `cert.pem` — code-server certificate (signed by CA)
- `server.cnf` — OpenSSL config with SANs for devserver01
The CA cert (`ca.crt`) has been imported into Firefox on client machines under Settings → Privacy & Security → Certificates → View Certificates → Authorities → Import → "Trust this CA to identify websites." Add these labels to any new Docker service:
### Volume Mapping Reference ```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.<n>.rule=Host(`subdomain.resolutionflow.com`)"
- "traefik.http.routers.<n>.entrypoints=websecure"
- "traefik.http.routers.<n>.tls.certresolver=letsencrypt"
- "traefik.http.services.<n>.loadbalancer.server.port=<port>"
```
| Host Path | Container Path | Purpose | Also create an A record in DNS pointing the subdomain to `46.202.92.250`.
|---|---|---|
| `~/docker/code-server/config/data` | `/home/coder/.local/share/code-server` | VS Code user data, settings |
| `~/docker/code-server/config/extensions` | `/home/coder/.local/share/code-server/extensions` | VS Code extensions |
| `~/docker/code-server/config/.config/code-server` | `/home/coder/.config/code-server` | code-server config |
| `~/docker/projects` | `/projects` | All project repos |
| `~/docker/code-server/certs` | `/certs` | SSL certificates |
| `/home/michael/.claude` | `/home/coder/.claude` | Claude Code config, plugins, skills, history |
## Patherly / ResolutionFlow Dev Environment ## ResolutionFlow Dev Stack
### Docker Compose (Dev) ### Important: No Docker Inside VS Code Container
Location: `~/docker/projects/patherly/docker-compose.dev.yml` The VS Code Server container does NOT have Docker. All `docker compose` commands must be run via SSH as root on the host.
This runs the full Patherly/ResolutionFlow stack:
- **PostgreSQL** (pgvector/pgvector:pg16) on port 5432
- **Backend** (FastAPI/Uvicorn) on port 8000
- **Frontend** (Vite/React) on port 5173
### Environment Files ### Environment Files
- `~/docker/projects/patherly/.env` — Backend secrets (SECRET_KEY, API keys, etc.) | File | Purpose |
- `~/docker/projects/patherly/frontend/.env` — Frontend config (VITE_API_URL) |---|---|
| `.env` | Root — Docker Compose interpolation (`SECRET_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_AI_API_KEY`, `POSTGRES_PORT`) |
| `backend/.env` | Backend source of truth — all FastAPI settings, API keys, DB URLs, CORS |
| `frontend/.env` | Frontend — `VITE_API_URL` pointing to backend |
### Critical Configuration for Remote Access ### Critical Remote Access Config
Since the dev environment is accessed from other machines on the LAN (not localhost), these settings are required: **`frontend/.env`:**
**Frontend `.env`:**
``` ```
VITE_API_URL=http://192.168.0.9:8000 VITE_API_URL=http://46.202.92.250:8000
``` ```
**Backend CORS_ORIGINS in `docker-compose.dev.yml`:** **`backend/.env`:**
```
CORS_ORIGINS=["http://localhost:3000","http://localhost:5173","http://127.0.0.1:3000","http://127.0.0.1:5173","http://46.202.92.250:5173","http://46.202.92.250:3000","https://resolutionflow.com","https://www.resolutionflow.com"]
FRONTEND_URL=http://46.202.92.250:5173
DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/resolutionflow
DATABASE_URL_SYNC=postgresql://postgres:postgres@db:5432/resolutionflow
```
Note: `DATABASE_URL` uses `@db:5432` (Docker service name), not `@localhost`.
**`docker-compose.dev.yml`:**
```yaml ```yaml
- CORS_ORIGINS=["http://localhost:3000","http://localhost:5173","http://127.0.0.1:3000","http://127.0.0.1:5173","http://192.168.0.9:5173","http://192.168.0.9:3000"] - VITE_API_URL=http://46.202.92.250:8000
``` ```
The `192.168.0.9` entries are required because browsers make requests from the client machine, where `localhost` refers to the client — not devserver01.
### Starting the Dev Environment ### Starting the Dev Environment
SSH into host as root:
```bash ```bash
cd ~/docker/projects/patherly cd /var/lib/docker/volumes/vscode_vscode-data/_data/resolutionflow
docker compose -f docker-compose.dev.yml up -d docker compose -f docker-compose.dev.yml up -d
``` ```
### Running Migrations (Fresh Database) ### Running Migrations (Fresh Database)
```bash ```bash
cd /var/lib/docker/volumes/vscode_vscode-data/_data/resolutionflow
docker compose -f docker-compose.dev.yml run --rm backend alembic upgrade head docker compose -f docker-compose.dev.yml run --rm backend alembic upgrade head
``` ```
@@ -158,193 +139,124 @@ docker compose -f docker-compose.dev.yml run --rm backend alembic upgrade head
docker exec resolutionflow_backend python -m scripts.seed_test_users docker exec resolutionflow_backend python -m scripts.seed_test_users
``` ```
### Rebuilding After Frontend .env Changes Test accounts (password: `TestPass123!`):
Vite bakes environment variables at build time, so changes to `VITE_API_URL` require a rebuild: | Email | Role | Plan |
|---|---|---|
| admin@resolutionflow.example.com | Owner | Team |
| pro@resolutionflow.example.com | Owner | Pro |
| teamadmin@resolutionflow.example.com | Owner | Team |
| engineer@resolutionflow.example.com | Engineer | Shared |
### Rebuilding After Config Changes
**Frontend** (Vite bakes env vars at build time — requires rebuild):
```bash
cd /var/lib/docker/volumes/vscode_vscode-data/_data/resolutionflow
docker compose -f docker-compose.dev.yml up -d --build frontend
```
**Backend** (restart only):
```bash
docker compose -f docker-compose.dev.yml restart backend
```
**Full restart:**
```bash ```bash
docker compose -f docker-compose.dev.yml down docker compose -f docker-compose.dev.yml down
docker compose -f docker-compose.dev.yml up -d --build docker compose -f docker-compose.dev.yml up -d
``` ```
Backend environment changes (like CORS_ORIGINS) only need a restart, not a rebuild. ## Installed Tools (Inside VS Code Server Container)
### Access URLs Installed in `/home/coder` — persists via Docker volume:
- **Frontend:** `http://192.168.0.9:5173` - **nvm** — Node version manager
- **Backend API:** `http://192.168.0.9:8000` - **Node.js 20.x** — via nvm, default alias set
- **API Docs:** `http://192.168.0.9:8000/docs` - **npm** — latest
- **GitHub CLI (gh)** — authenticated via personal access token
- **Claude Code CLI** — `@anthropic-ai/claude-code` (global npm)
## Known Issues & Fixes ### Permanent Tool Installs
### iptables DROP Rules Blocking Docker Traffic Tools installed via `apt` inside the container do NOT survive container rebuilds. To add permanently, modify the VS Code Server Docker image and rebuild.
Docker routes container traffic through the FORWARD chain. Rogue DROP rules in the DOCKER chain can block all container networking. Temporary (session only):
**Symptoms:** Container shows as running, port is listening via `ss`, but `curl` returns "Connection reset by peer" or "Connection refused" from other machines.
**Diagnosis:**
```bash ```bash
sudo iptables -L DOCKER -n --line-numbers sudo apt update && sudo apt install -y <tool>
``` ```
Look for blanket DROP rules: ## SSH Access
```
2 DROP all -- 0.0.0.0/0 0.0.0.0/0
3 DROP all -- 0.0.0.0/0 0.0.0.0/0
```
**Fix:**
```bash
# Remove DROP rules (remove highest numbered first)
sudo iptables -D DOCKER 3
sudo iptables -D DOCKER 2
```
If the FORWARD chain has `policy DROP` and Docker containers can't communicate:
```bash
sudo systemctl restart docker
```
Docker rebuilds its iptables chains on restart. These rules don't persist across reboots by default — if they come back, something else is creating them.
### Code-Server Port Mismatch
The codercom/code-server image listens on port **8443** internally, not 8080. The compose file must map `8080:8443`:
```yaml
ports:
- 8080:8443
```
The code-server config file (`/home/coder/.config/code-server/config.yaml`) must bind to `0.0.0.0`, not `127.0.0.1`:
```yaml
bind-addr: 0.0.0.0:8443
```
If it says `127.0.0.1`, it will only accept connections from inside the container.
### Permission Issues Inside Container
The container runs as user `coder` (UID 1000). Host files mounted into the container must be owned by UID 1000:
```bash ```bash
# Fix project permissions ssh root@46.202.92.250
sudo chown -R 1000:1000 ~/docker/projects
# Fix code-server config permissions
sudo chown -R 1000:1000 ~/docker/code-server/config/
# Fix Claude Code config permissions
sudo chown -R 1000:1000 ~/.claude/
``` ```
### GitHub CLI (gh) Auth Key auth configured via `~/.ssh/authorized_keys` on host.
gh stores its config at `/home/coder/.config/gh/`. If it fails with permission denied:
```bash
docker exec -u root code-server mkdir -p /home/coder/.config/gh
docker exec -u root code-server chown -R 1000:1000 /home/coder/.config
```
## Useful Commands ## Useful Commands
### Check all running containers ### Check all running containers
```bash ```bash
docker ps docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
``` ```
### View logs for a specific container ### View container logs
```bash ```bash
docker logs <container_name> --tail 30 docker logs <container_name> --tail 30 -f
``` ```
### Restart code-server ### Restart VS Code Server
```bash ```bash
cd ~/docker cd /docker/vscode && docker compose restart
docker compose up -d
``` ```
### Rebuild code-server (after Dockerfile changes) ### Restart Traefik
```bash ```bash
cd ~/docker cd /docker/traefik && docker compose restart
docker compose down
docker compose up -d --build
``` ```
### Restart dev environment ### Restart dev stack
```bash ```bash
cd ~/docker/projects/patherly cd /var/lib/docker/volumes/vscode_vscode-data/_data/resolutionflow
docker compose -f docker-compose.dev.yml down docker compose -f docker-compose.dev.yml down
docker compose -f docker-compose.dev.yml up -d docker compose -f docker-compose.dev.yml up -d
``` ```
### SSH into devserver01 ### Check swap
```bash ```bash
ssh michael@192.168.0.9 free -h && swapon --show
``` ```
### Check what's listening on ports ### Check disk
```bash ```bash
sudo ss -tlnp | grep <port> df -h
``` ```
### Check firewall / iptables ### Check memory + container usage
```bash ```bash
sudo ufw status free -h && docker stats --no-stream
sudo iptables -L -n --line-numbers
sudo iptables -L DOCKER -n --line-numbers
``` ```
### Execute commands inside containers ## DNS Records (resolutionflow.com)
```bash
# As default user
docker exec code-server <command>
# As root | Type | Name | Value | Purpose |
docker exec -u root code-server <command> |---|---|---|---|
| A | code | 46.202.92.250 | VS Code Server |
# Interactive shell ## Security Notes
docker exec -it code-server bash
```
## Network Info - UFW is inactive — Traefik and Docker manage port exposure
- All public-facing services run through Traefik with valid HTTPS certs
- PostgreSQL port 5432 is exposed on all interfaces — restrict if needed in production
- Rotate API keys (Anthropic, Voyage) if ever exposed in logs or chat
- Never commit `.env` files to Git
- **Server IP:** 192.168.0.9 ## VS Code Server Browser Tips
- **Docker bridge network:** 172.17.0.0/16 and 172.18.0.0/16
- **Host user:** michael (UID 1000)
- **Container user:** coder (UID 1000) — same UID allows seamless file sharing via volume mounts
## Code-Server Browser Tips - **Command Palette:** `F1`
- **Terminal:** Ctrl+`
- **Command Palette:** `F1` (not Ctrl+Shift+P, which opens Firefox private window)
- **Context Menu (right-click):** `Alt + Right Click`
- **Terminal:** `` Ctrl+` ``
- **Rename file:** `F2` - **Rename file:** `F2`
- **Go to definition:** `F12` - **Go to definition:** `F12`
- **Find references:** `Shift+F12` - **Find references:** `Shift+F12`
- **Context Menu:** `Alt + Right Click`
## Adding New Tools to Code-Server
To permanently add tools (survive container restarts), add them to `~/docker/Dockerfile.code-server`:
```dockerfile
USER root
RUN apt update && apt install -y <new-tool> && rm -rf /var/lib/apt/lists/*
USER coder
```
Then rebuild:
```bash
cd ~/docker
docker compose down
docker compose up -d --build
```
For temporary installs (gone after restart):
```bash
docker exec -u root code-server apt update
docker exec -u root code-server apt install -y <new-tool>
```

View File

@@ -1,10 +1,10 @@
# Application # Application
APP_NAME=Patherly APP_NAME=ResolutionFlow
DEBUG=true DEBUG=true
# Database # Database
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/patherly DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/resolutionflow
DATABASE_URL_SYNC=postgresql://postgres:postgres@localhost:5432/patherly DATABASE_URL_SYNC=postgresql://postgres:postgres@localhost:5432/resolutionflow
# JWT Settings - CHANGE THESE IN PRODUCTION # JWT Settings - CHANGE THESE IN PRODUCTION
# Generate with: openssl rand -hex 32 # Generate with: openssl rand -hex 32
@@ -15,3 +15,10 @@ REFRESH_TOKEN_EXPIRE_DAYS=7
# CORS # CORS
CORS_ORIGINS=["http://localhost:3000","http://localhost:5173"] CORS_ORIGINS=["http://localhost:3000","http://localhost:5173"]
# Anthropic API Key
ANTHROPIC_API_KEY=
VOYAGE_API_KEY=
# ConnectWise PSA Integration
CW_CLIENT_ID=<CONNECTWISE CLIENT ID>

View File

@@ -39,7 +39,7 @@ services:
- AI_PROVIDER=anthropic - AI_PROVIDER=anthropic
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- GOOGLE_AI_API_KEY=${GOOGLE_AI_API_KEY} - GOOGLE_AI_API_KEY=${GOOGLE_AI_API_KEY}
- CORS_ORIGINS=["http://localhost:3000","http://localhost:5173","http://127.0.0.1:3000","http://127.0.0.1:5173","http://192.168.0.9:5173","http://192.168.0.9:3000"] - CORS_ORIGINS=["http://localhost:3000","http://localhost:5173","http://127.0.0.1:3000","http://127.0.0.1:5173","http://46.202.92.250:5173","http://46.202.92.250:3000","https://resolutionflow.com","https://www.resolutionflow.com"]
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@@ -55,7 +55,7 @@ services:
- ./frontend:/app - ./frontend:/app
- /app/node_modules - /app/node_modules
environment: environment:
- VITE_API_URL=http://192.168.0.9:8000 - VITE_API_URL=http://46.202.92.250:8000
depends_on: depends_on:
- backend - backend