diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..a7b5de7 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,59 @@ +name: Build & Push Docker images + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}/moraworld-imports + +jobs: + build-api: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push API + uses: docker/build-push-action@v6 + with: + context: . + file: apps/api/Dockerfile + push: true + tags: ${{ env.IMAGE_PREFIX }}/api:latest + + build-web: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push Web + uses: docker/build-push-action@v6 + with: + context: . + file: apps/web/Dockerfile + push: true + build-args: | + NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }} + tags: ${{ env.IMAGE_PREFIX }}/web:latest diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index a9778ab..df6be4b 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -19,4 +19,5 @@ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/packages/database ./packages/database USER app EXPOSE 3001 -CMD ["node", "dist/main.js"] \ No newline at end of file +# ponytail: migrate antes de arrancar; si quieres zero-downtime migrations, sepáralas como job previo en Coolify +CMD ["sh", "-c", "node node_modules/.bin/prisma migrate deploy --schema packages/database/prisma/schema.prisma && node dist/main.js"] \ No newline at end of file diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 0bffed2..4a95fdd 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -1,5 +1,7 @@ import { Module } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; +import { ThrottlerModule, ThrottlerGuard } from "@nestjs/throttler"; +import { APP_GUARD } from "@nestjs/core"; import { HealthModule } from "./health/health.module"; import { PrismaModule } from "./prisma/prisma.module"; import { CalculatorModule } from "./calculator/calculator.module"; @@ -25,6 +27,7 @@ import { ConsolidationsModule } from "./consolidations/consolidations.module"; isGlobal: true, envFilePath: ["../../.env", ".env"], }), + ThrottlerModule.forRoot([{ ttl: 60000, limit: 20 }]), PrismaModule, HealthModule, CalculatorModule, @@ -44,5 +47,6 @@ import { ConsolidationsModule } from "./consolidations/consolidations.module"; PaymentsModule, ConsolidationsModule, ], + providers: [{ provide: APP_GUARD, useClass: ThrottlerGuard }], }) export class AppModule {} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 5eada06..6b5aa68 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -30,7 +30,7 @@ async function bootstrap() { app.useGlobalPipes( new ValidationPipe({ whitelist: true, - forbidNonWhitelisted: false, + forbidNonWhitelisted: true, transform: true, transformOptions: { enableImplicitConversion: true }, }), diff --git a/coolify-compose.yml b/coolify-compose.yml index 81421d8..a4d6de9 100644 --- a/coolify-compose.yml +++ b/coolify-compose.yml @@ -47,6 +47,9 @@ services: web: image: ghcr.io/lizandrogd/moraworld-imports/web:latest + depends_on: + api: + condition: service_healthy build: context: . dockerfile: apps/web/Dockerfile