diff --git a/apps/backend/Dockerfile b/apps/backend/Dockerfile index 25e85e0..9fdabeb 100644 --- a/apps/backend/Dockerfile +++ b/apps/backend/Dockerfile @@ -55,8 +55,13 @@ COPY --from=builder --chown=nestjs:nodejs /app/dist ./dist COPY --from=builder --chown=nestjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nestjs:nodejs /app/package*.json ./ -# Create logs directory -RUN mkdir -p /app/logs && chown -R nestjs:nodejs /app/logs +# Copy source code needed at runtime (for CSV storage path resolution) +COPY --from=builder --chown=nestjs:nodejs /app/src ./src + +# Create logs and uploads directories +RUN mkdir -p /app/logs && \ + mkdir -p /app/src/infrastructure/storage/csv-storage/rates && \ + chown -R nestjs:nodejs /app/logs /app/src # Switch to non-root user USER nestjs diff --git a/apps/backend/src/application/controllers/admin/csv-rates.controller.ts b/apps/backend/src/application/controllers/admin/csv-rates.controller.ts index b46e426..700299d 100644 --- a/apps/backend/src/application/controllers/admin/csv-rates.controller.ts +++ b/apps/backend/src/application/controllers/admin/csv-rates.controller.ts @@ -43,6 +43,23 @@ import { ConfigService } from '@nestjs/config'; import * as fs from 'fs'; import * as path from 'path'; +/** + * Get CSV upload directory path (works in both dev and Docker) + */ +function getCsvUploadPath(): string { + // In Docker, working directory is /app, so we use /app/src/... + // In local dev, process.cwd() points to the project root + const workDir = process.cwd(); + + // If we're in /app (Docker), use /app/src/infrastructure/... + if (workDir === '/app') { + return '/app/src/infrastructure/storage/csv-storage/rates'; + } + + // Otherwise (local dev), use relative path from project root + return path.join(workDir, 'apps/backend/src/infrastructure/storage/csv-storage/rates'); +} + /** * CSV Rates Admin Controller * @@ -56,6 +73,7 @@ import * as path from 'path'; @Roles('ADMIN') // ⚠️ ONLY ADMIN can access these endpoints export class CsvRatesAdminController { private readonly logger = new Logger(CsvRatesAdminController.name); + private readonly csvUploadPath: string; constructor( private readonly csvLoader: CsvRateLoaderAdapter, @@ -64,7 +82,10 @@ export class CsvRatesAdminController { private readonly csvRateMapper: CsvRateMapper, private readonly s3Storage: S3StorageAdapter, private readonly configService: ConfigService - ) {} + ) { + this.csvUploadPath = getCsvUploadPath(); + this.logger.log(`📁 CSV upload path: ${this.csvUploadPath}`); + } /** * Upload CSV rate file (ADMIN only) @@ -74,7 +95,7 @@ export class CsvRatesAdminController { @UseInterceptors( FileInterceptor('file', { storage: diskStorage({ - destination: './apps/backend/src/infrastructure/storage/csv-storage/rates', + destination: getCsvUploadPath(), filename: (req, file, cb) => { // Use timestamp + random string to avoid conflicts // We'll rename it later once we have the company name from req.body diff --git a/apps/frontend/.dockerignore b/apps/frontend/.dockerignore index 2995108..fdf528c 100644 --- a/apps/frontend/.dockerignore +++ b/apps/frontend/.dockerignore @@ -89,8 +89,9 @@ azure-pipelines.yml .prettierignore .eslintrc.json .eslintignore -postcss.config.js -tailwind.config.js +# postcss.config.js # NEEDED for Tailwind CSS compilation +# tailwind.config.js # NEEDED for Tailwind CSS compilation +# tailwind.config.ts # NEEDED for Tailwind CSS compilation next-env.d.ts tsconfig.tsbuildinfo diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ff6a393..a1bb0c3 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,41 +1,95 @@ +version: '3.8' + +# Build local pour Mac ARM64 services: - # PostgreSQL Database postgres: - image: postgres:latest + image: postgres:15-alpine container_name: xpeditis-postgres-dev - restart: unless-stopped ports: - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data environment: POSTGRES_DB: xpeditis_dev POSTGRES_USER: xpeditis POSTGRES_PASSWORD: xpeditis_dev_password - volumes: - - postgres_data_dev:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U xpeditis"] - interval: 5s + interval: 10s timeout: 5s retries: 5 - # Redis Cache redis: - image: redis:7 + image: redis:7-alpine container_name: xpeditis-redis-dev - restart: unless-stopped ports: - "6379:6379" - command: redis-server --requirepass xpeditis_dev_password - volumes: - - redis_data_dev:/data + command: redis-server --requirepass xpeditis_redis_password healthcheck: test: ["CMD", "redis-cli", "ping"] - interval: 5s - timeout: 3s + interval: 10s + timeout: 5s retries: 5 + minio: + image: minio/minio:latest + container_name: xpeditis-minio-dev + ports: + - "9000:9000" + - "9001:9001" + command: server /data --console-address ":9001" + volumes: + - minio_data:/data + environment: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: minioadmin + + backend: + build: + context: ./apps/backend + dockerfile: Dockerfile + container_name: xpeditis-backend-dev + ports: + - "4001:4000" + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + environment: + NODE_ENV: development + PORT: 4000 + DATABASE_HOST: postgres + DATABASE_PORT: 5432 + DATABASE_USER: xpeditis + DATABASE_PASSWORD: xpeditis_dev_password + DATABASE_NAME: xpeditis_dev + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: xpeditis_redis_password + JWT_SECRET: dev-secret-key + AWS_S3_ENDPOINT: http://minio:9000 + AWS_REGION: us-east-1 + AWS_ACCESS_KEY_ID: minioadmin + AWS_SECRET_ACCESS_KEY: minioadmin + AWS_S3_BUCKET: xpeditis-csv-rates + CORS_ORIGIN: http://localhost:3001 + + frontend: + build: + context: ./apps/frontend + dockerfile: Dockerfile + args: + NEXT_PUBLIC_API_URL: http://localhost:4001 + container_name: xpeditis-frontend-dev + ports: + - "3001:3000" + depends_on: + - backend + environment: + NEXT_PUBLIC_API_URL: http://localhost:4001 + volumes: - postgres_data_dev: - name: xpeditis_postgres_data_dev - redis_data_dev: - name: xpeditis_redis_data_dev + postgres_data: + redis_data: + minio_data: