Update CLAUDE.md with Dokploy deployment docs and fixes
This commit is contained in:
parent
79701c5e93
commit
b184d74ad4
1 changed files with 189 additions and 1 deletions
188
CLAUDE.md
188
CLAUDE.md
|
|
@ -78,3 +78,191 @@ Key modules (read in this order for domain understanding):
|
||||||
- **workers/** — Arq async tasks (run via Redis queue)
|
- **workers/** — Arq async tasks (run via Redis queue)
|
||||||
- **db/** — SQLAlchemy models + migrations
|
- **db/** — SQLAlchemy models + migrations
|
||||||
- **main.py** — FastAPI app factory
|
- **main.py** — FastAPI app factory
|
||||||
|
|
||||||
|
## Deployment (Dokploy)
|
||||||
|
|
||||||
|
### Docker Configuration
|
||||||
|
|
||||||
|
**API Dockerfile** (`packages/api/Dockerfile`):
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip install poetry
|
||||||
|
|
||||||
|
COPY packages /app/packages
|
||||||
|
|
||||||
|
WORKDIR /app/packages/api
|
||||||
|
RUN poetry install --no-interaction
|
||||||
|
|
||||||
|
ENV VENV_PATH=/root/.cache/pypoetry/virtualenvs/remodel-api-cufy8KWC-py3.12/bin
|
||||||
|
ENV PATH=$VENV_PATH:$PATH
|
||||||
|
ENV PYTHONPATH=/app/packages/engine/src:/app/packages/api/src
|
||||||
|
|
||||||
|
WORKDIR /app/packages/api
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["uvicorn", "remodel_api.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Web Dockerfile** (`packages/web/Dockerfile`):
|
||||||
|
```dockerfile
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
COPY . .
|
||||||
|
RUN test -f .env.local || echo "# placeholder" > .env.local
|
||||||
|
RUN pnpm install --frozen-lockfile --ignore-scripts
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
FROM node:22-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
COPY --from=builder /app/.next ./.next
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
COPY --from=builder /app/package.json .
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder /app/.env.local ./.env.local
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["/app/node_modules/.bin/next", "start"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### docker-compose.yml (Dokploy)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: packages/api/Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=sqlite+aiosqlite:///./remodel.db
|
||||||
|
- REDIS_URL=redis://redis:6379
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
- "traefik.http.routers.api.rule=Host(`model.manohargupta.com`) && PathPrefix(`/api`)"
|
||||||
|
- "traefik.http.routers.api.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.api.loadbalancer.server.port=8000"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- web
|
||||||
|
|
||||||
|
worker:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: packages/api/Dockerfile
|
||||||
|
command: python -m arq remodel_api.workers.main.WorkerSettings
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=sqlite+aiosqlite:///./remodel.db
|
||||||
|
- REDIS_URL=redis://redis:6379
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: ./packages/web
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=https://model.manohargupta.com/api
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
- "traefik.http.routers.web.rule=Host(`model.manohargupta.com`)"
|
||||||
|
- "traefik.http.routers.web.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.web.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.web.loadbalancer.server.port=3000"
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
internal: true
|
||||||
|
web:
|
||||||
|
name: dokploy-network
|
||||||
|
external: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis_data:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description | Required |
|
||||||
|
|----------|-------------|----------|
|
||||||
|
| `DATABASE_URL` | SQLite with async driver | `sqlite+aiosqlite:///./remodel.db` |
|
||||||
|
| `REDIS_URL` | Redis connection string | `redis://redis:6379` |
|
||||||
|
| `NEXT_PUBLIC_API_URL` | Public API URL for web | `https://model.manohargupta.com/api` |
|
||||||
|
|
||||||
|
### CORS Configuration
|
||||||
|
|
||||||
|
In `packages/api/src/remodel_api/main.py`:
|
||||||
|
```python
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["http://localhost:3000", "https://model.manohargupta.com"],
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Config Settings
|
||||||
|
|
||||||
|
In `packages/api/src/remodel_api/config.py`:
|
||||||
|
```python
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
model_config = SettingsConfigDict(env_prefix="", extra="ignore")
|
||||||
|
database_url: str = "sqlite+aiosqlite:///./remodel.db"
|
||||||
|
redis_url: str = "redis://localhost:6379"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important**: No prefix for env vars - they must match docker-compose exactly.
|
||||||
|
|
||||||
|
### Network Requirements
|
||||||
|
|
||||||
|
- `dokploy-network` must exist on Dokploy server (external network)
|
||||||
|
- Traefik uses `websecure` endpoint (HTTPS with Let's Encrypt TLS)
|
||||||
|
|
||||||
|
## Deployment Issues & Fixes
|
||||||
|
|
||||||
|
| Issue | Cause | Fix |
|
||||||
|
|-------|-------|-----|
|
||||||
|
| Poetry pyproject.toml not found | COPY syntax wrong in Dockerfile | Copy entire `packages/` directory |
|
||||||
|
| `--no-venv-seeding` flag error | Old Poetry version | Remove the flag |
|
||||||
|
| Missing `.env.local` | Not in git | Create placeholder in builder stage |
|
||||||
|
| `uvicorn` not in PATH | Poetry venv not in PATH | Set `ENV PATH=$VENV_PATH:$PATH` |
|
||||||
|
| `next` not found | pnpm stores bins differently | Use absolute path `/app/node_modules/.bin/next` |
|
||||||
|
| 504 Gateway Timeout | Redis/DB not accessible | Check network, restart containers |
|
||||||
|
| Worker can't connect to Redis | Wrong env prefix | Use `REDIS_URL` not `REMODEL_REDIS_URL` |
|
||||||
|
| SQLite async error | Wrong driver | Use `sqlite+aiosqlite://` not `sqlite://` |
|
||||||
|
| CORS blocked | Origin mismatch | Add production domain to allow_origins |
|
||||||
Loading…
Add table
Reference in a new issue