From 22e8cc893f0d4e220ba31dde250c6036c08fcd37 Mon Sep 17 00:00:00 2001 From: Kilian Date: Thu, 30 Apr 2026 10:22:37 +0100 Subject: [PATCH] Add Dockerfiles, .dockerignore and brand logo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - apps/api/Dockerfile: multi-stage pnpm build, runtime node:22-alpine, port 3001 - apps/web/Dockerfile: multi-stage pnpm + Vite, runtime nginx:alpine with SPA config - .dockerignore: excludes node_modules, dist, .env, .git, IDE folders, design docs - Brand logo (naturcalabacera.webp) integrated as favicon, sidebar icon, header logo - index.html title updated to 'Naturcalabacera · Reservas' --- .dockerignore | 63 +++++++++++++++++++++++++++ apps/api/Dockerfile | 38 ++++++++++++++++ apps/web/Dockerfile | 52 ++++++++++++++++++++++ apps/web/index.html | 5 ++- apps/web/public/naturcalabacera.webp | Bin 0 -> 4888 bytes apps/web/src/App.tsx | 19 +++++--- apps/web/src/components/Sidebar.tsx | 2 +- 7 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 .dockerignore create mode 100644 apps/api/Dockerfile create mode 100644 apps/web/Dockerfile create mode 100644 apps/web/public/naturcalabacera.webp diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f97574a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Dependencias y builds (se generan dentro del contenedor) +node_modules +**/node_modules +dist +**/dist + +# Variables de entorno (NUNCA en imágenes) +.env +.env.* +**/.env +**/.env.* +!**/.env.example + +# Git +.git +.gitignore + +# Editor / SO +.vscode +.idea +.DS_Store +*.swp +*.swo + +# Logs +*.log +logs + +# Documentación y archivos de planificación que no necesita el build +*.md +!README.md +architecture +directivas +skills +.agents +.claude +.codebuddy +.commandcode +.continue +.crush +.factory +.goose +.kilocode +.kiro +.mcpjam +.mux +.neovate +.openhands +.pi +.qoder +.qwen +.roo +.tmp +.trae +.windsurf +.zencoder +findings.md +gemini.md +progress.md +task_plan.md + +# Imágenes de diseño en raíz +*.png diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile new file mode 100644 index 0000000..51a5aa3 --- /dev/null +++ b/apps/api/Dockerfile @@ -0,0 +1,38 @@ +# syntax=docker/dockerfile:1 + +# ───── Stage 1: build ───── +FROM node:22-alpine AS builder +WORKDIR /repo +RUN corepack enable + +# Manifiestos primero (para cachear pnpm install si no cambian deps) +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ +COPY packages/shared/package.json ./packages/shared/ +COPY apps/api/package.json ./apps/api/ + +RUN pnpm install --frozen-lockfile + +# Código fuente +COPY packages/shared ./packages/shared +COPY apps/api ./apps/api + +# Compila TypeScript del api +RUN pnpm --filter @naturcalabacera/api build + +# Carpeta de despliegue self-contained con node_modules de producción +RUN pnpm --filter @naturcalabacera/api deploy --prod /out + +# Copia plantillas HTML al dist (tsc no las copia) +RUN cp -r apps/api/src/templates /out/dist/templates + +# ───── Stage 2: runtime ───── +FROM node:22-alpine +WORKDIR /app +ENV NODE_ENV=production + +COPY --from=builder /out/dist ./dist +COPY --from=builder /out/node_modules ./node_modules +COPY --from=builder /out/package.json ./package.json + +EXPOSE 3001 +CMD ["node", "dist/index.js"] diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile new file mode 100644 index 0000000..5daaeb4 --- /dev/null +++ b/apps/web/Dockerfile @@ -0,0 +1,52 @@ +# syntax=docker/dockerfile:1 + +# ───── Stage 1: build ───── +FROM node:22-alpine AS builder +WORKDIR /repo +RUN corepack enable + +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ +COPY packages/shared/package.json ./packages/shared/ +COPY apps/web/package.json ./apps/web/ + +RUN pnpm install --frozen-lockfile + +COPY packages/shared ./packages/shared +COPY apps/web ./apps/web + +# Variables públicas inyectadas en el bundle por Vite (build-time) +ARG VITE_SUPABASE_URL +ARG VITE_SUPABASE_ANON_KEY +ARG VITE_SUPABASE_SCHEMA +ARG VITE_API_URL +ENV VITE_SUPABASE_URL=$VITE_SUPABASE_URL +ENV VITE_SUPABASE_ANON_KEY=$VITE_SUPABASE_ANON_KEY +ENV VITE_SUPABASE_SCHEMA=$VITE_SUPABASE_SCHEMA +ENV VITE_API_URL=$VITE_API_URL + +RUN pnpm --filter @naturcalabacera/web build + +# ───── Stage 2: runtime (Nginx sirviendo SPA) ───── +FROM nginx:alpine +COPY --from=builder /repo/apps/web/dist /usr/share/nginx/html + +# Config SPA: cualquier ruta cae en index.html (React Router friendly) +RUN printf 'server {\n\ + listen 80;\n\ + server_name _;\n\ + root /usr/share/nginx/html;\n\ + index index.html;\n\ +\n\ + location / {\n\ + try_files $uri $uri/ /index.html;\n\ + }\n\ +\n\ + # Cache largo para assets con hash\n\ + location /assets/ {\n\ + expires 1y;\n\ + add_header Cache-Control "public, immutable";\n\ + }\n\ +}\n' > /etc/nginx/conf.d/default.conf + +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/web/index.html b/apps/web/index.html index eac8330..3aeb28d 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -2,9 +2,10 @@ - + + - reservas-app + Naturcalabacera · Reservas
diff --git a/apps/web/public/naturcalabacera.webp b/apps/web/public/naturcalabacera.webp new file mode 100644 index 0000000000000000000000000000000000000000..33a8c9559f3ab4863ae6fc437f72fc8982d63340 GIT binary patch literal 4888 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 XpBNJLe=xP7gVQ4r4L}CK{`UU^|Atr_ literal 0 HcmV?d00001 diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index dea6919..32cf611 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -126,12 +126,19 @@ function AppContent() {
{/* Relative container: center title absolutely, left/right content on sides */}
- {/* Left: status dot + tagline (desktop only) */} -
- - - Gestiona tus reservas y disponibilidad - + {/* Left: brand logo + status dot + tagline */} +
+ Naturcalabacera +
+ + + Gestiona tus reservas y disponibilidad + +
{/* Center: property name — always truly centered */} diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 8b1a0be..501b319 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -31,7 +31,7 @@ export function Sidebar({ currentView, onNavigate, isViewer = false, isAdmin = f

- + Naturcalabacera
Reservas