From 91dfdce66d75b2a16bc579e62f607e63d420d0b1 Mon Sep 17 00:00:00 2001 From: Jose Selesan Date: Fri, 10 Apr 2026 19:44:33 -0300 Subject: [PATCH] Improved Dockerfile --- AGENTS.md | 67 +++++++++++++++++++++++++++++++++++++++ Dockerfile | 59 ++++++++++++++++++++++++---------- apps/backend/package.json | 5 +-- bun.lock | 6 ++-- entrypoint.sh | 5 +++ 5 files changed, 120 insertions(+), 22 deletions(-) create mode 100644 AGENTS.md create mode 100644 entrypoint.sh diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..6ba5f00 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,67 @@ +# AGENTS.md + +## Commands + +```sh +# Root (runs both frontend + backend) +bun run dev + +# Individual packages +bun run dev:frontend +bun run dev:backend +bun run build:frontend + +# Linting (Biome - ESLint was replaced) +bun run lint +bun run lint:fix # fixes and formats + +# Prisma (run from backend) +bun --filter backend prisma:generate # regenerate client after schema changes +bun --filter backend prisma:migrate # apply migrations +``` + +## Architecture + +``` +apps/frontend/ # React + Vite + TanStack Router/Query +apps/backend/ # Bun + Hono + Prisma +packages/api-contract/ # Shared Zod schemas, types, route definitions +``` + +**Shared contract pattern:** +1. Update `packages/api-contract` first (schemas/types) +2. Implement handler in `apps/backend` +3. Consume from `apps/frontend` via workspace import `@repo/api-contract` + +## Key Quirks + +- **Prisma 7**: Uses `prisma.config.ts`, requires `DATABASE_URL` env var at generate time +- **Zod v4**: Use `.issues` instead of `.errors` for validation errors +- **Generated files**: `routeTree.gen.ts` and `tsconfig*.json` are auto-generated (ignored by Biome) +- **TanStack Router**: Routes are code-generated. Use `--filter frontend build` not raw vite build. + +## Docker Deployment (Dokploy) + +- **Build Context**: `./` (monorepo root) +- **Dockerfile**: `Dockerfile` (in root, not `apps/backend/`) +- **Required args**: `DATABASE_URL`, `VITE_API_BASE_URL`, `VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY` +- **bun.lock must be tracked**: It's in `.gitignore` by default - remove it for Docker builds + +## Linting + +Biome is used (not ESLint). Config in `biome.json`: +- Line width: 100 +- Quote style: single +- Semicolons: always +- `noUnusedVariables`: warn + +## Environment Variables + +**Backend** (`apps/backend/.env`): +- `DATABASE_URL` - PostgreSQL connection (required for Prisma) +- `SUPABASE_URL`, `SUPABASE_ANON_KEY` - Auth +- `CORS_ORIGIN` - Frontend URL + +**Frontend** (`apps/frontend/.env`): +- `VITE_*` prefix required (Vite embeds these at build time) +- `VITE_API_BASE_URL` - Backend URL (default: http://localhost:3000) diff --git a/Dockerfile b/Dockerfile index 52ed545..5cdfb39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,64 @@ # syntax=docker/dockerfile:1.7 -FROM oven/bun:1.3 AS deps +# ============================================================================= +# Stage 1: Install frontend dependencies +# ============================================================================= +FROM oven/bun:1.3.11 AS deps-frontend WORKDIR /app COPY package.json bun.lock ./ -COPY apps/backend/package.json apps/backend/ COPY apps/frontend/package.json apps/frontend/ COPY packages/api-contract/package.json packages/api-contract/ -RUN bun install --frozen-lockfile +RUN bun install -FROM deps AS build +# ============================================================================= +# Stage 2: Build Frontend +# ============================================================================= +FROM deps-frontend AS build-frontend WORKDIR /app -COPY . . - +COPY apps/frontend ./apps/frontend +COPY packages ./packages ARG VITE_API_BASE_URL ARG VITE_SUPABASE_URL ARG VITE_SUPABASE_ANON_KEY ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} ENV VITE_SUPABASE_URL=${VITE_SUPABASE_URL} ENV VITE_SUPABASE_ANON_KEY=${VITE_SUPABASE_ANON_KEY} - -ARG DATABASE_URL=postgresql://placeholder:placeholder@placeholder:5432/placeholder -ENV DATABASE_URL=${DATABASE_URL} - RUN bun run build:frontend -RUN bun --cwd apps/backend prisma generate -FROM deps AS runner +# ============================================================================= +# Stage 3: Install backend dependencies +# ============================================================================= +FROM oven/bun:1.3.11 AS deps-backend +WORKDIR /app +COPY package.json bun.lock ./ +COPY apps/backend/package.json apps/backend/ +COPY packages/api-contract/package.json packages/api-contract/ +RUN bun install + +# ============================================================================= +# Stage 4: Build Backend +# ============================================================================= +FROM deps-backend AS build-backend +WORKDIR /app +COPY apps/backend ./apps/backend +COPY packages ./packages +RUN bun --cwd apps/backend build + +# ============================================================================= +# Stage 5: Runner - Production image +# ============================================================================= +FROM oven/bun:1.3.11 AS runner WORKDIR /app ENV NODE_ENV=production HOST=0.0.0.0 PORT=3000 -COPY --from=build /app/node_modules ./node_modules -COPY --from=build /app/apps/backend ./apps/backend -COPY --from=build /app/packages ./packages +COPY --from=deps-backend /app/node_modules ./node_modules +COPY --from=build-frontend /app/apps/frontend/dist ./apps/frontend/dist +COPY --from=build-backend /app/apps/backend ./apps/backend +COPY --from=build-backend /app/packages ./packages COPY package.json ./ +COPY entrypoint.sh /app/entrypoint.sh + +RUN chmod +x /app/entrypoint.sh -WORKDIR /app/apps/backend EXPOSE 3000 -CMD ["sh", "-lc", "bun run prisma migrate deploy && bun src/server.ts"] +CMD ["/app/entrypoint.sh"] \ No newline at end of file diff --git a/apps/backend/package.json b/apps/backend/package.json index 433e77f..df95d36 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -3,6 +3,7 @@ "scripts": { "dev": "bun run --hot src/server.ts", "start": "bun src/server.ts", + "build": "tsc -b", "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write .", @@ -25,11 +26,11 @@ "pino": "10.3.1", "pino-pretty": "13.1.3", "pino-std-serializers": "7.1.0", + "prisma": "^7", "uuid": "^13.0.0" }, "devDependencies": { "@types/bun": "latest", - "@types/nodemailer": "^8.0.0", - "prisma": "^7" + "@types/nodemailer": "^8.0.0" } } diff --git a/bun.lock b/bun.lock index 6e763be..a71ff8e 100644 --- a/bun.lock +++ b/bun.lock @@ -28,12 +28,12 @@ "pino": "10.3.1", "pino-pretty": "13.1.3", "pino-std-serializers": "7.1.0", + "prisma": "^7", "uuid": "^13.0.0", }, "devDependencies": { "@types/bun": "latest", "@types/nodemailer": "^8.0.0", - "prisma": "^7", }, }, "apps/frontend": { @@ -571,7 +571,7 @@ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], + "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="], "@types/node": ["@types/node@24.12.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ=="], @@ -643,7 +643,7 @@ "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], - "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], + "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..5cc5723 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd /app/apps/backend +bun --cwd /app/apps/backend prisma migrate deploy +bun --cwd /app/apps/backend prisma generate +bun run start \ No newline at end of file