mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 12:41:04 +00:00
modify pipeline to speed up deployment
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
**/node_modules
|
||||
**/dist
|
||||
**/.turbo
|
||||
**/.git
|
||||
**/.github
|
||||
**/.vscode
|
||||
**/.git
|
||||
**/.idea
|
||||
**/.env
|
||||
.env
|
||||
**/.env.*
|
||||
!**/.env.example
|
||||
**/coverage
|
||||
**/*.tsbuildinfo
|
||||
**/*.log
|
||||
.DS_Store
|
||||
|
||||
71
.github/workflows/deploy-freight.yml
vendored
Normal file
71
.github/workflows/deploy-freight.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: Deploy Freight
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- staging
|
||||
paths:
|
||||
- "apps/edr-freight-api/**"
|
||||
- "apps/edr-freight-web/**"
|
||||
- "packages/**"
|
||||
- "infrastructure/docker/Dockerfile.web"
|
||||
- "infrastructure/nginx/**"
|
||||
- "docker-compose.yaml"
|
||||
- "pnpm-lock.yaml"
|
||||
- "scripts/deploy/**"
|
||||
- ".github/workflows/deploy-freight.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-freight-${{ github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Build and deploy freight stack
|
||||
runs-on: self-hosted
|
||||
env:
|
||||
PROJECT: edr-freight
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
DEPLOY_USER: user
|
||||
BUILD_ENV_FILE: freight-web.build.env
|
||||
DOCKER_BUILDKIT: "1"
|
||||
COMPOSE_DOCKER_CLI_BUILD: "1"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Sync environment from server
|
||||
run: |
|
||||
chmod +x scripts/deploy/*.sh
|
||||
./scripts/deploy/sync-env-from-server.sh \
|
||||
freight-api \
|
||||
freight-portal \
|
||||
freight-backoffice
|
||||
|
||||
- name: Configure npm auth for Docker builds
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: ./scripts/deploy/create-npmrc.sh
|
||||
|
||||
- name: Build images
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker compose build \
|
||||
freight-api \
|
||||
freight-portal \
|
||||
freight-backoffice
|
||||
|
||||
- name: Deploy containers
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker compose up -d \
|
||||
freight-api \
|
||||
freight-portal \
|
||||
freight-backoffice
|
||||
|
||||
- name: Remove npm credentials from workspace
|
||||
if: always()
|
||||
run: rm -f .npmrc .npmrc_temp
|
||||
71
.github/workflows/deploy-passenger.yml
vendored
Normal file
71
.github/workflows/deploy-passenger.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: Deploy Passenger
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- staging
|
||||
paths:
|
||||
- "apps/edr-passenger-api/**"
|
||||
- "apps/edr-passenger-web/**"
|
||||
- "packages/**"
|
||||
- "infrastructure/docker/Dockerfile.web"
|
||||
- "infrastructure/nginx/**"
|
||||
- "docker-compose.yaml"
|
||||
- "pnpm-lock.yaml"
|
||||
- "scripts/deploy/**"
|
||||
- ".github/workflows/deploy-passenger.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-passenger-${{ github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Build and deploy passenger stack
|
||||
runs-on: self-hosted
|
||||
env:
|
||||
PROJECT: edr-passenger
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
DEPLOY_USER: user
|
||||
BUILD_ENV_FILE: passenger-web.build.env
|
||||
DOCKER_BUILDKIT: "1"
|
||||
COMPOSE_DOCKER_CLI_BUILD: "1"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Sync environment from server
|
||||
run: |
|
||||
chmod +x scripts/deploy/*.sh
|
||||
./scripts/deploy/sync-env-from-server.sh \
|
||||
passenger-api \
|
||||
passenger-portal \
|
||||
passenger-backoffice
|
||||
|
||||
- name: Configure npm auth for Docker builds
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: ./scripts/deploy/create-npmrc.sh
|
||||
|
||||
- name: Build images
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker compose build \
|
||||
passenger-api \
|
||||
passenger-portal \
|
||||
passenger-backoffice
|
||||
|
||||
- name: Deploy containers
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker compose up -d \
|
||||
passenger-api \
|
||||
passenger-portal \
|
||||
passenger-backoffice
|
||||
|
||||
- name: Remove npm credentials from workspace
|
||||
if: always()
|
||||
run: rm -f .npmrc .npmrc_temp
|
||||
96
.github/workflows/deploy.yaml
vendored
96
.github/workflows/deploy.yaml
vendored
@@ -1,96 +0,0 @@
|
||||
name: Automatic Deployment
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
environment:
|
||||
name: 🌍 Setup Environment
|
||||
runs-on: [self-hosted]
|
||||
outputs:
|
||||
target: ${{ steps.dev.outputs.target || steps.staging.outputs.target }}
|
||||
steps:
|
||||
- name: Verify NPM Token
|
||||
env:
|
||||
# We map the secret here to check its existence
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
if [ -z "$NPM_TOKEN" ]; then
|
||||
echo "::error::The NPM_TOKEN secret is missing or empty. Please add it to your GitHub Secrets."
|
||||
exit 1
|
||||
fi
|
||||
echo "NPM_TOKEN is present, proceeding with build..."
|
||||
|
||||
- name: 🛠️ Set Development Environment
|
||||
id: dev
|
||||
if: ${{github.ref_name == 'dev'}}
|
||||
run: |
|
||||
echo "target=dev" >> $GITHUB_OUTPUT
|
||||
- name: 🚀 Set Staging Environment
|
||||
id: staging
|
||||
if: ${{github.ref_name == 'staging'}}
|
||||
run: |
|
||||
echo "target=staging" >> $GITHUB_OUTPUT
|
||||
|
||||
build-base-image:
|
||||
name: 🏗️ Build Base Image
|
||||
runs-on: [self-hosted, dev]
|
||||
needs: [environment]
|
||||
steps:
|
||||
- name: 🔍 Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🐳 Build Docker Image
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Create the multi-line file
|
||||
cat <<EOF > .npmrc_temp
|
||||
@tria-plc:registry=https://npm.pkg.github.com
|
||||
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
|
||||
always-auth=true
|
||||
EOF
|
||||
|
||||
# Build using the file
|
||||
docker build --secret id=npmrc,src=.npmrc_temp -t edr-${{needs.environment.outputs.target}} .
|
||||
docker build --secret id=npmrc,src=.npmrc_temp --target passenger-migration -t edr-passenger-migration-${{needs.environment.outputs.target}} .
|
||||
|
||||
# Shred/Remove the sensitive file
|
||||
rm .npmrc_temp
|
||||
|
||||
deploy-service:
|
||||
name: ${{ matrix.display_name }}
|
||||
runs-on: [self-hosted, dev]
|
||||
needs: [build-base-image, environment]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- service: freight-api
|
||||
env_file: .env.freight-api
|
||||
display_name: 🚚 Deploy Freight API Service
|
||||
- service: passenger-api
|
||||
env_file: .env.passenger-api
|
||||
display_name: 🧑🦲 Deploy Passenger API Service
|
||||
|
||||
steps:
|
||||
- name: 🔍 Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 📋 Copy ${{ matrix.service }} Environment
|
||||
run: cp ~/environment/edr/${{needs.environment.outputs.target}}/${{ matrix.env_file }} .env
|
||||
|
||||
- name: 🧪 Run Passenger API migrations
|
||||
if: ${{ matrix.service == 'passenger-api' }}
|
||||
run: |
|
||||
docker run --rm --env-file .env edr-passenger-migration-${{needs.environment.outputs.target}}
|
||||
|
||||
- name: 🚀 Start ${{ matrix.service }} Service
|
||||
run: docker compose --project-name="edr-${{needs.environment.outputs.target}}" up -d --force-recreate ${{ matrix.service }} --build
|
||||
84
Dockerfile
84
Dockerfile
@@ -1,84 +0,0 @@
|
||||
FROM node:24.15.0 AS base
|
||||
RUN corepack enable && corepack prepare pnpm@latest-11 --activate
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS deps
|
||||
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
|
||||
|
||||
COPY apps/edr-freight-api/package.json ./apps/edr-freight-api/
|
||||
COPY apps/edr-passenger-api/package.json ./apps/edr-passenger-api/
|
||||
|
||||
COPY apps/edr-freight-web/backoffice/package.json ./apps/edr-freight-web/backoffice/
|
||||
COPY apps/edr-freight-web/portal/package.json ./apps/edr-freight-web/portal/
|
||||
|
||||
COPY apps/edr-passenger-web/backoffice/package.json ./apps/edr-passenger-web/backoffice/
|
||||
COPY apps/edr-passenger-web/portal/package.json ./apps/edr-passenger-web/portal/
|
||||
|
||||
|
||||
COPY packages/api-common/package.json packages/api-common/
|
||||
|
||||
COPY packages/config/eslint-config/package.json packages/config/eslint-config/
|
||||
COPY packages/config/prettier-config/package.json packages/config/prettier-config/
|
||||
COPY packages/config/tsconfig/package.json packages/config/tsconfig/
|
||||
|
||||
COPY packages/types/package.json packages/types/
|
||||
COPY packages/ui-common/package.json packages/ui-common/
|
||||
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store\
|
||||
--mount=type=secret,id=npmrc,target=./.npmrc \
|
||||
pnpm install --frozen-lockfile
|
||||
FROM deps AS build
|
||||
COPY . .
|
||||
|
||||
RUN pnpm run build --log-order grouped
|
||||
|
||||
FROM base AS freight-api
|
||||
# RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
|
||||
WORKDIR /app/apps/edr-freight-api
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY --from=deps /app/node_modules ./../../node_modules
|
||||
COPY --from=deps /app/apps/edr-freight-api/node_modules ./node_modules
|
||||
COPY --from=build /app/apps/edr-freight-api/dist ./dist
|
||||
COPY --from=build /app/apps/edr-freight-api/package.json ./package.json
|
||||
COPY --from=build /app/packages ./../../packages
|
||||
|
||||
EXPOSE 3001
|
||||
CMD ["node", "dist/main.js"]
|
||||
|
||||
|
||||
FROM base AS passenger-api
|
||||
RUN apt-get update -y && apt-get install -y openssl
|
||||
# RUN corepack enable && corepack prepare pnpm@9.12.0 --activate
|
||||
WORKDIR /app/apps/edr-passenger-api
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Use build-stage node_modules (not deps): `pnpm run build` runs `prisma generate`, which
|
||||
# writes the real @prisma/client (enums, types). deps never runs generate, so @IsEnum(ServiceClass)
|
||||
# and similar would see undefined at runtime if we copied deps only.
|
||||
COPY --from=build /app/node_modules ./../../node_modules
|
||||
COPY --from=build /app/apps/edr-passenger-api/node_modules ./node_modules
|
||||
COPY --from=build /app/apps/edr-passenger-api/dist ./dist
|
||||
COPY --from=build /app/apps/edr-passenger-api/package.json ./package.json
|
||||
COPY --from=build /app/packages ./../../packages
|
||||
|
||||
EXPOSE 3001
|
||||
CMD ["node", "dist/main.js"]
|
||||
|
||||
FROM build as passenger-migration
|
||||
WORKDIR /app/apps/edr-passenger-api
|
||||
CMD pnpm run prisma:migrate && pnpm run prisma:seed
|
||||
|
||||
|
||||
|
||||
FROM nginx:1.27-alpine AS freight-web-portal
|
||||
COPY --from=build /app/apps/edr-freight-web/portal/dist /usr/share/nginx/html
|
||||
EXPOSE 5173
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
|
||||
FROM nginx:1.27-alpine AS freight-web-backoffice
|
||||
COPY --from=build /app/apps/edr-freight-web/backoffice/dist /usr/share/nginx/html
|
||||
EXPOSE 5173
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
120
README.md
120
README.md
@@ -170,7 +170,7 @@ pnpm --filter @edr/passenger-api run prisma:generate
|
||||
|
||||
#### Run Migrations
|
||||
```bash
|
||||
pnpm --filter @edr/passenger-api run prisma:migrate
|
||||
pnpm --filter @edr/passenger-api run prisma:migrate:dev
|
||||
```
|
||||
|
||||
#### Seed Database
|
||||
@@ -523,59 +523,103 @@ pnpm --filter @edr/passenger-api run type-check # TypeScript check
|
||||
|
||||
# Database
|
||||
pnpm --filter @edr/passenger-api run prisma:generate # Generate Prisma client
|
||||
pnpm --filter @edr/passenger-api run prisma:migrate # Run migrations
|
||||
pnpm --filter @edr/passenger-api run prisma:migrate:dev # Run migrations (local dev)
|
||||
pnpm --filter @edr/passenger-api run prisma:seed # Seed database
|
||||
```
|
||||
|
||||
## 🐳 Docker Deployment
|
||||
|
||||
### Build Image
|
||||
All six apps build from Dockerfiles: each API has its own (`apps/edr-freight-api/Dockerfile`, `apps/edr-passenger-api/Dockerfile`); Vite frontends share `infrastructure/docker/Dockerfile.web` and are served with **nginx**. APIs run on **Node 22**.
|
||||
|
||||
**Prerequisites**
|
||||
|
||||
- Docker with BuildKit enabled
|
||||
- A local [`.npmrc`](.gitignore) with GitHub Packages auth for `@tria-plc/*` (required for **freight** API and web images)
|
||||
- External Postgres for each API (compose does **not** include databases)
|
||||
- Copy `apps/edr-freight-api/.env.example` → `.env` and `apps/edr-passenger-api/.env.example` → `.env` with real connection strings
|
||||
|
||||
### Build and run (all apps)
|
||||
|
||||
```bash
|
||||
# From monorepo root
|
||||
docker build -f apps/edr-passenger-api/Dockerfile -t edr-passenger-api .
|
||||
DOCKER_BUILDKIT=1 pnpm docker:build
|
||||
pnpm docker:up
|
||||
```
|
||||
|
||||
### Run Container
|
||||
Or without pnpm scripts:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name edr-api \
|
||||
-p 4000:4000 \
|
||||
--env-file apps/edr-passenger-api/.env \
|
||||
edr-passenger-api
|
||||
DOCKER_BUILDKIT=1 docker compose build
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Docker Compose (Recommended)
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
environment:
|
||||
POSTGRES_USER: edr
|
||||
POSTGRES_PASSWORD: edr_secret
|
||||
POSTGRES_DB: edr_passenger
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
| Service | URL (default) |
|
||||
|---------|----------------|
|
||||
| Freight API | http://localhost:3001 |
|
||||
| Passenger API | http://localhost:4000 |
|
||||
| Freight portal | http://localhost:5173 |
|
||||
| Freight backoffice | http://localhost:5183 |
|
||||
| Passenger portal | http://localhost:5174 |
|
||||
| Passenger backoffice | http://localhost:5184 |
|
||||
|
||||
api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/edr-passenger-api/Dockerfile
|
||||
ports:
|
||||
- "4000:4000"
|
||||
environment:
|
||||
DATABASE_URL: postgresql://edr:edr_secret@postgres:5432/edr_passenger
|
||||
JWT_SECRET: your-secret-key
|
||||
PORT: 4000
|
||||
depends_on:
|
||||
- postgres
|
||||
### Build a single service
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```bash
|
||||
docker compose build freight-api
|
||||
docker compose build passenger-portal
|
||||
```
|
||||
|
||||
Freight images mount `.npmrc` as a BuildKit secret during `pnpm install`. Passenger web images do not require private packages.
|
||||
|
||||
### `VITE_API_URL` (frontends)
|
||||
|
||||
API URLs are **baked in at image build time** (`import.meta.env.VITE_API_URL`). Defaults in [`docker-compose.yaml`](docker-compose.yaml) use `http://localhost:3001/api` (freight) and `http://localhost:4000` (passenger) for local smoke tests. Override build args for production, e.g.:
|
||||
|
||||
```bash
|
||||
docker compose build freight-portal \
|
||||
--build-arg VITE_API_URL=https://freight-api.example.com/api
|
||||
```
|
||||
|
||||
### Migrations
|
||||
|
||||
- **Freight API:** TypeORM migrations are not run on container startup — apply them separately before deploy.
|
||||
- **Passenger API:** On each container start, the entrypoint runs `npm run prisma:migrate` and `npm run prisma:seed` (same `package.json` scripts as `pnpm run`) before starting the server. Ensure `DATABASE_URL` in `.env` points at a reachable Postgres instance.
|
||||
|
||||
For local development, use `pnpm --filter @edr/passenger-api run prisma:migrate:dev` instead of `prisma:migrate`.
|
||||
|
||||
### GitHub Actions (self-hosted runner)
|
||||
|
||||
Two workflows deploy independently on push to `main`, `develop`, or `staging`:
|
||||
|
||||
| Workflow | Services | Server env root |
|
||||
|----------|----------|-----------------|
|
||||
| [`.github/workflows/deploy-freight.yml`](.github/workflows/deploy-freight.yml) | freight-api, freight-portal, freight-backoffice | `/home/user/environmen/edr-freight/<branch>/` |
|
||||
| [`.github/workflows/deploy-passenger.yml`](.github/workflows/deploy-passenger.yml) | passenger-api, passenger-portal, passenger-backoffice | `/home/user/environmen/edr-passenger/<branch>/` |
|
||||
|
||||
**On the runner**, place env files before the first deploy (example for branch `main`):
|
||||
|
||||
```text
|
||||
/home/user/environmen/edr-freight/main/
|
||||
freight-api.env
|
||||
freight-portal.env # optional runtime env for Vite/nginx
|
||||
freight-backoffice.env
|
||||
freight-web.build.env # exports FREIGHT_VITE_API_URL=...
|
||||
|
||||
/home/user/environmen/edr-passenger/main/
|
||||
passenger-api.env
|
||||
passenger-portal.env
|
||||
passenger-backoffice.env
|
||||
passenger-web.build.env # exports PASSENGER_VITE_API_URL=...
|
||||
```
|
||||
|
||||
Example `freight-web.build.env`:
|
||||
|
||||
```bash
|
||||
export FREIGHT_VITE_API_URL=https://freight-api.example.com/api
|
||||
```
|
||||
|
||||
The workflow copies `*.env` into each app directory, creates `.npmrc` from the `NPM_TOKEN` repository secret, then runs `docker compose build` and `docker compose up -d` for that stack.
|
||||
|
||||
## 🔒 Security Best Practices
|
||||
|
||||
1. **Environment Variables** - Never commit `.env` files. Use secrets management in production.
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
# App
|
||||
NODE_ENV=development
|
||||
# Copy to .env for local/docker compose (not committed).
|
||||
PORT=3001
|
||||
|
||||
# Database
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5433
|
||||
DB_NAME=edr_freight
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=
|
||||
|
||||
# JWT (provided by external auth package — placeholder only)
|
||||
JWT_SECRET=
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
DB_NAME=edr_freight
|
||||
|
||||
37
apps/edr-freight-api/Dockerfile
Normal file
37
apps/edr-freight-api/Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
# Build from monorepo root: docker build -f apps/edr-freight-api/Dockerfile .
|
||||
|
||||
FROM node:22-alpine AS base
|
||||
RUN apk add --no-cache libc6-compat
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS pruner
|
||||
COPY . .
|
||||
RUN pnpm dlx turbo prune "@edr/freight-api" --docker
|
||||
|
||||
FROM base AS installer
|
||||
COPY --from=pruner /app/out/json/ .
|
||||
COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
|
||||
RUN --mount=type=secret,id=npmrc,target=./.npmrc,required=false \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS builder
|
||||
COPY --from=installer /app/ .
|
||||
COPY --from=pruner /app/out/full/ .
|
||||
RUN pnpm turbo build --filter="@edr/freight-api..."
|
||||
|
||||
FROM base AS deployer
|
||||
COPY --from=builder /app/ .
|
||||
RUN pnpm deploy --filter="@edr/freight-api" --prod --legacy /deploy
|
||||
|
||||
FROM node:22-alpine AS runner
|
||||
RUN apk add --no-cache libc6-compat
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /app
|
||||
RUN addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --uid 1001 --ingroup nodejs nestjs
|
||||
COPY --from=deployer --chown=nestjs:nodejs /deploy .
|
||||
USER nestjs
|
||||
EXPOSE 3001
|
||||
CMD ["node", "dist/main.js"]
|
||||
@@ -1,96 +1,4 @@
|
||||
# App
|
||||
NODE_ENV=development
|
||||
# Copy to .env for local/docker compose (not committed).
|
||||
PORT=4000
|
||||
|
||||
# Database (Prisma)
|
||||
DATABASE_URL=postgresql://edr:edr_secret@localhost:5432/edr_passenger?schema=edr_passenger
|
||||
|
||||
# CORS
|
||||
FRONTEND_URL=http://localhost:3000
|
||||
PORTAL_URL=http://localhost:3001
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=edr-platform-secret-change-in-production
|
||||
JWT_EXPIRES_IN=7d
|
||||
|
||||
# SendGrid
|
||||
SENDGRID_API_KEY=
|
||||
SENDGRID_FROM_EMAIL=noreply@edr-platform.com
|
||||
|
||||
# SMS Configuration
|
||||
SMS_PROVIDER=twilio
|
||||
SMS_API_KEY=
|
||||
|
||||
# Twilio (if SMS_PROVIDER=twilio)
|
||||
TWILIO_ACCOUNT_SID=
|
||||
TWILIO_AUTH_TOKEN=
|
||||
TWILIO_FROM_NUMBER=
|
||||
|
||||
# Africa's Talking (if SMS_PROVIDER=africastalking)
|
||||
AFRICASTALKING_USERNAME=
|
||||
AFRICASTALKING_FROM=
|
||||
|
||||
# Telebirr
|
||||
TELEBIRR_BASE_URL=
|
||||
TELEBIRR_WEB_BASE_URL=
|
||||
TELEBIRR_FABRIC_APP_ID=
|
||||
TELEBIRR_APP_SECRET=
|
||||
TELEBIRR_MERCHANT_APP_ID=
|
||||
TELEBIRR_MERCHANT_CODE=
|
||||
TELEBIRR_NOTIFY_URL=
|
||||
TELEBIRR_RETURN_URL=
|
||||
TELEBIRR_TIMEOUT_EXPRESS=15m
|
||||
TELEBIRR_PRIVATE_KEY=
|
||||
TELEBIRR_PUBLIC_KEY=
|
||||
TELEBIRR_INSECURE_TLS=false
|
||||
|
||||
# CBE Birr
|
||||
CBE_BASE_URL=
|
||||
CBE_MERCHANT_ID=
|
||||
CBE_SECRET_KEY=
|
||||
CBE_NOTIFY_URL=
|
||||
CBE_RETURN_URL=
|
||||
|
||||
# eBirr
|
||||
EBIRR_BASE_URL=
|
||||
EBIRR_MERCHANT_CODE=
|
||||
EBIRR_SECRET_KEY=
|
||||
EBIRR_NOTIFY_URL=
|
||||
EBIRR_RETURN_URL=
|
||||
|
||||
# Card Gateway (Stripe-like)
|
||||
CARD_BASE_URL=
|
||||
CARD_API_KEY=
|
||||
CARD_WEBHOOK_SECRET=
|
||||
CARD_WEBHOOK_URL=
|
||||
CARD_RETURN_URL=
|
||||
|
||||
# Waafi (Djibouti Mobile Money)
|
||||
WAAFI_BASE_URL=https://api.waafipay.net
|
||||
WAAFI_MERCHANT_UID=
|
||||
WAAFI_API_USER_ID=
|
||||
WAAFI_API_KEY=
|
||||
WAAFI_NOTIFY_URL=
|
||||
WAAFI_RETURN_URL=
|
||||
|
||||
# Payment Configuration
|
||||
PAYMENT_PROVIDERS_ENABLED=TELEBIRR,CBE_BIRR,EBIRR,CARD,WALLET,WAAFI
|
||||
|
||||
# Session Configuration
|
||||
SESSION_INACTIVITY_MINUTES=30
|
||||
|
||||
# i18n Configuration
|
||||
DEFAULT_LOCALE=en
|
||||
SUPPORTED_LOCALES=en,am,fr,om
|
||||
|
||||
# Corporate IAM Configuration (for back-office authentication)
|
||||
IAM_ENABLED=false
|
||||
IAM_API_URL=https://iam.tria-plc.com/api
|
||||
IAM_API_KEY=
|
||||
|
||||
# Verifayda 2.0 Configuration (Ethiopian National ID Verification)
|
||||
VERIFAYDA_ENABLED=false
|
||||
VERIFAYDA_API_URL=https://api.verifayda.gov.et/v2
|
||||
VERIFAYDA_API_KEY=
|
||||
|
||||
GITHUB_PACKAGE_TOKEN=
|
||||
DATABASE_URL=postgresql://user:password@host:5432/edr_passenger
|
||||
JWT_SECRET=change-me-in-production
|
||||
|
||||
50
apps/edr-passenger-api/Dockerfile
Normal file
50
apps/edr-passenger-api/Dockerfile
Normal file
@@ -0,0 +1,50 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
# Build from monorepo root: docker build -f apps/edr-passenger-api/Dockerfile .
|
||||
# On start: runs prisma migrate deploy + seed, then the API.
|
||||
|
||||
FROM node:22-alpine AS base
|
||||
RUN apk add --no-cache libc6-compat
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS pruner
|
||||
COPY . .
|
||||
RUN pnpm dlx turbo prune "@edr/passenger-api" --docker
|
||||
|
||||
FROM base AS installer
|
||||
COPY --from=pruner /app/out/json/ .
|
||||
COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
|
||||
RUN --mount=type=secret,id=npmrc,target=./.npmrc,required=false \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS builder
|
||||
COPY --from=installer /app/ .
|
||||
COPY --from=pruner /app/out/full/ .
|
||||
RUN pnpm --filter "@edr/passenger-api" exec prisma generate
|
||||
RUN pnpm turbo build --filter="@edr/passenger-api..."
|
||||
|
||||
FROM base AS deployer
|
||||
COPY --from=builder /app/ .
|
||||
RUN pnpm deploy --filter="@edr/passenger-api" --legacy /deploy
|
||||
RUN if [ -d node_modules/.prisma ]; then \
|
||||
mkdir -p /deploy/node_modules && \
|
||||
cp -r node_modules/.prisma /deploy/node_modules/.prisma; \
|
||||
fi
|
||||
|
||||
FROM node:22-alpine AS runner
|
||||
RUN apk add --no-cache libc6-compat
|
||||
RUN corepack enable && corepack prepare pnpm@11.1.1 --activate
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /app
|
||||
RUN addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --uid 1001 --ingroup nodejs nestjs
|
||||
COPY --from=deployer /deploy .
|
||||
COPY apps/edr-passenger-api/docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh \
|
||||
&& chown -R nestjs:nodejs /app
|
||||
USER nestjs
|
||||
ENV CI=true
|
||||
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
|
||||
EXPOSE 4000
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["node", "dist/main.js"]
|
||||
11
apps/edr-passenger-api/docker-entrypoint.sh
Normal file
11
apps/edr-passenger-api/docker-entrypoint.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
cd /app
|
||||
|
||||
# npm run executes the same package.json scripts as pnpm run (pnpm reinstalls in deploy layout)
|
||||
npm run prisma:generate
|
||||
npm run prisma:migrate
|
||||
npm run prisma:seed
|
||||
|
||||
exec "$@"
|
||||
@@ -12,7 +12,8 @@
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"type-check": "tsc --noEmit",
|
||||
"prisma:generate": "prisma generate",
|
||||
"prisma:migrate": "prisma migrate dev",
|
||||
"prisma:migrate": "prisma migrate deploy",
|
||||
"prisma:migrate:dev": "prisma migrate dev",
|
||||
"prisma:seed": "ts-node prisma/seed.ts",
|
||||
"prisma:backfill": "ts-node prisma/backfill-fields.ts",
|
||||
"prisma:verify": "ts-node prisma/verify-backfill.ts"
|
||||
@@ -42,7 +43,8 @@
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"tsconfig-paths": "^4.2.0"
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"@prisma/client": "^6.19.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@edr/eslint-config": "workspace:*",
|
||||
@@ -50,7 +52,6 @@
|
||||
"@nestjs/cli": "^11.0.21",
|
||||
"@nestjs/schematics": "^11.1.0",
|
||||
"@nestjs/testing": "^11.1.19",
|
||||
"@prisma/client": "^6.19.3",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/node": "^20.10.6",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PrismaClient, SeatKind } from '@prisma/client';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
@@ -136,11 +136,11 @@ async function seedCoachesAndSeats(seatClasses: any[]) {
|
||||
col,
|
||||
label: `${row}${col}`,
|
||||
seatNumber: `${config.label}${row}${col}`,
|
||||
kind: (row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD') as SeatKind,
|
||||
kind: row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD',
|
||||
});
|
||||
}
|
||||
}
|
||||
await prisma.seat.createMany({ data: seats });
|
||||
await prisma.seat.createMany({ data: seats as any });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ async function seedSchedules(trains: any[], stations: any[]) {
|
||||
const existingScheduleIds = (await prisma.trainSchedule.findMany({
|
||||
where: { trainId: { in: [train301.id, train302.id, train303.id] } },
|
||||
select: { id: true },
|
||||
})).map((s) => s.id);
|
||||
})).map((s: { id: string }) => s.id);
|
||||
|
||||
if (existingScheduleIds.length > 0) {
|
||||
await prisma.fareRule.deleteMany({ where: { tripId: { in: existingScheduleIds } } });
|
||||
|
||||
@@ -1,21 +1,84 @@
|
||||
# EDR Platform — application containers only (no Postgres).
|
||||
# Requires a local .npmrc with GitHub Packages auth for @tria-plc (freight API + freight web).
|
||||
# Copy apps/*/env.example to .env and set real values before `docker compose up`.
|
||||
#
|
||||
# Build: DOCKER_BUILDKIT=1 docker compose build
|
||||
# Run: docker compose up -d
|
||||
|
||||
services:
|
||||
freight-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile
|
||||
target: freight-api
|
||||
env_file:
|
||||
- .env
|
||||
dockerfile: apps/edr-freight-api/Dockerfile
|
||||
secrets:
|
||||
- npmrc
|
||||
ports:
|
||||
- ${PORT}:${PORT}
|
||||
restart: unless-stopped
|
||||
- "3001:3001"
|
||||
environment:
|
||||
PORT: "3001"
|
||||
env_file:
|
||||
- apps/edr-freight-api/.env
|
||||
|
||||
passenger-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile
|
||||
target: passenger-api
|
||||
env_file:
|
||||
- .env
|
||||
dockerfile: apps/edr-passenger-api/Dockerfile
|
||||
ports:
|
||||
- ${PORT}:${PORT}
|
||||
restart: unless-stopped
|
||||
- "4000:4000"
|
||||
environment:
|
||||
PORT: "4000"
|
||||
env_file:
|
||||
- apps/edr-passenger-api/.env
|
||||
|
||||
freight-portal:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: infrastructure/docker/Dockerfile.web
|
||||
args:
|
||||
TURBO_FILTER: "@edr/freight-portal"
|
||||
APP_PATH: apps/edr-freight-web/portal
|
||||
# Browser-reachable URL; override for production deployments
|
||||
VITE_API_URL: ${FREIGHT_VITE_API_URL:-http://localhost:3001/api}
|
||||
secrets:
|
||||
- npmrc
|
||||
ports:
|
||||
- "5173:80"
|
||||
|
||||
freight-backoffice:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: infrastructure/docker/Dockerfile.web
|
||||
args:
|
||||
TURBO_FILTER: "@edr/freight-backoffice"
|
||||
APP_PATH: apps/edr-freight-web/backoffice
|
||||
VITE_API_URL: ${FREIGHT_VITE_API_URL:-http://localhost:3001/api}
|
||||
secrets:
|
||||
- npmrc
|
||||
ports:
|
||||
- "5183:80"
|
||||
|
||||
passenger-portal:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: infrastructure/docker/Dockerfile.web
|
||||
args:
|
||||
TURBO_FILTER: "@edr/passenger-portal"
|
||||
APP_PATH: apps/edr-passenger-web/portal
|
||||
VITE_API_URL: ${PASSENGER_VITE_API_URL:-http://localhost:4000}
|
||||
ports:
|
||||
- "5174:80"
|
||||
|
||||
passenger-backoffice:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: infrastructure/docker/Dockerfile.web
|
||||
args:
|
||||
TURBO_FILTER: "@edr/passenger-backoffice"
|
||||
APP_PATH: apps/edr-passenger-web/backoffice
|
||||
VITE_API_URL: ${PASSENGER_VITE_API_URL:-http://localhost:4000}
|
||||
ports:
|
||||
- "5184:80"
|
||||
|
||||
secrets:
|
||||
npmrc:
|
||||
file: .npmrc
|
||||
|
||||
37
infrastructure/docker/Dockerfile.web
Normal file
37
infrastructure/docker/Dockerfile.web
Normal file
@@ -0,0 +1,37 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG TURBO_FILTER=@edr/freight-portal
|
||||
ARG APP_PATH=apps/edr-freight-web/portal
|
||||
ARG VITE_API_URL=http://localhost:3001/api
|
||||
|
||||
FROM node:22-alpine AS base
|
||||
RUN apk add --no-cache libc6-compat
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS pruner
|
||||
ARG TURBO_FILTER
|
||||
COPY . .
|
||||
RUN pnpm dlx turbo prune "${TURBO_FILTER}" --docker
|
||||
|
||||
FROM base AS installer
|
||||
COPY --from=pruner /app/out/json/ .
|
||||
COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
|
||||
RUN --mount=type=secret,id=npmrc,target=./.npmrc,required=false \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS builder
|
||||
ARG TURBO_FILTER
|
||||
ARG APP_PATH
|
||||
ARG VITE_API_URL
|
||||
ENV VITE_API_URL=${VITE_API_URL}
|
||||
COPY --from=installer /app/ .
|
||||
COPY --from=pruner /app/out/full/ .
|
||||
RUN pnpm turbo build --filter="${TURBO_FILTER}..."
|
||||
|
||||
FROM nginx:alpine AS runner
|
||||
ARG APP_PATH
|
||||
COPY infrastructure/nginx/spa.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=builder /app/${APP_PATH}/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,126 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
edr-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres-freight-data:
|
||||
postgres-passenger-data:
|
||||
redis-data:
|
||||
|
||||
services:
|
||||
postgres-freight:
|
||||
image: postgres:17-alpine
|
||||
container_name: edr-postgres-freight
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: edr_freight
|
||||
ports:
|
||||
- "5433:5432"
|
||||
volumes:
|
||||
- postgres-freight-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
postgres-passenger:
|
||||
image: postgres:17-alpine
|
||||
container_name: edr-postgres-passenger
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: edr_passenger
|
||||
ports:
|
||||
- "5434:5432"
|
||||
volumes:
|
||||
- postgres-passenger-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: edr-redis
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-freight-api:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-freight-api/Dockerfile
|
||||
container_name: edr-freight-api
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- postgres-freight
|
||||
- redis
|
||||
environment:
|
||||
NODE_ENV: development
|
||||
PORT: 3001
|
||||
DB_HOST: postgres-freight
|
||||
DB_PORT: 5432
|
||||
DB_NAME: edr_freight
|
||||
DB_USER: postgres
|
||||
DB_PASSWORD: postgres
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
ports:
|
||||
- "3001:3001"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-freight-web:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-freight-web/Dockerfile
|
||||
container_name: edr-freight-web
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- edr-freight-api
|
||||
ports:
|
||||
- "5173:5173"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-passenger-api:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-passenger-api/Dockerfile
|
||||
container_name: edr-passenger-api
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- postgres-passenger
|
||||
- redis
|
||||
environment:
|
||||
NODE_ENV: development
|
||||
PORT: 3002
|
||||
DB_HOST: postgres-passenger
|
||||
DB_PORT: 5432
|
||||
DB_NAME: edr_passenger
|
||||
DB_USER: postgres
|
||||
DB_PASSWORD: postgres
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
ports:
|
||||
- "3002:3002"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-passenger-web:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-passenger-web/Dockerfile
|
||||
container_name: edr-passenger-web
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- edr-passenger-api
|
||||
ports:
|
||||
- "5174:5174"
|
||||
networks:
|
||||
- edr-network
|
||||
@@ -1,134 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
edr-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres-freight-data:
|
||||
postgres-passenger-data:
|
||||
redis-data:
|
||||
|
||||
services:
|
||||
postgres-freight:
|
||||
image: postgres:17-alpine
|
||||
container_name: edr-postgres-freight
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_DB: ${DB_NAME_FREIGHT}
|
||||
volumes:
|
||||
- postgres-freight-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
postgres-passenger:
|
||||
image: postgres:17-alpine
|
||||
container_name: edr-postgres-passenger
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_DB: ${DB_NAME_PASSENGER}
|
||||
volumes:
|
||||
- postgres-passenger-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: edr-redis
|
||||
restart: always
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-freight-api:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-freight-api/Dockerfile
|
||||
container_name: edr-freight-api
|
||||
restart: always
|
||||
depends_on:
|
||||
- postgres-freight
|
||||
- redis
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: 3001
|
||||
DB_HOST: postgres-freight
|
||||
DB_PORT: 5432
|
||||
DB_NAME: ${DB_NAME_FREIGHT}
|
||||
DB_USER: ${DB_USER}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
REDIS_HOST: redis
|
||||
expose:
|
||||
- "3001"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-freight-web:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-freight-web/Dockerfile
|
||||
container_name: edr-freight-web
|
||||
restart: always
|
||||
depends_on:
|
||||
- edr-freight-api
|
||||
expose:
|
||||
- "5173"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-passenger-api:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-passenger-api/Dockerfile
|
||||
container_name: edr-passenger-api
|
||||
restart: always
|
||||
depends_on:
|
||||
- postgres-passenger
|
||||
- redis
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: 3002
|
||||
DB_HOST: postgres-passenger
|
||||
DB_PORT: 5432
|
||||
DB_NAME: ${DB_NAME_PASSENGER}
|
||||
DB_USER: ${DB_USER}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
REDIS_HOST: redis
|
||||
expose:
|
||||
- "3002"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
edr-passenger-web:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/edr-passenger-web/Dockerfile
|
||||
container_name: edr-passenger-web
|
||||
restart: always
|
||||
depends_on:
|
||||
- edr-passenger-api
|
||||
expose:
|
||||
- "5174"
|
||||
networks:
|
||||
- edr-network
|
||||
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
container_name: edr-nginx
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- edr-freight-web
|
||||
- edr-freight-api
|
||||
- edr-passenger-web
|
||||
- edr-passenger-api
|
||||
volumes:
|
||||
- ../../infrastructure/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
networks:
|
||||
- edr-network
|
||||
@@ -1,63 +0,0 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
server_tokens off;
|
||||
|
||||
upstream edr_freight_api {
|
||||
server edr-freight-api:3001;
|
||||
}
|
||||
upstream edr_freight_web {
|
||||
server edr-freight-web:5173;
|
||||
}
|
||||
upstream edr_passenger_api {
|
||||
server edr-passenger-api:3002;
|
||||
}
|
||||
upstream edr_passenger_web {
|
||||
server edr-passenger-web:5174;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name freight.edr.local;
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://edr_freight_api/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://edr_freight_web/;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name passenger.edr.local;
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://edr_passenger_api/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://edr_passenger_web/;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
infrastructure/nginx/spa.conf
Normal file
13
infrastructure/nginx/spa.conf
Normal file
@@ -0,0 +1,13 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
"lint": "turbo run lint",
|
||||
"type-check": "turbo run type-check",
|
||||
"format": "prettier --write \"**/*.{ts,tsx,json,md}\"",
|
||||
"docker:build": "docker compose build",
|
||||
"docker:up": "docker compose up -d",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -305,6 +305,9 @@ importers:
|
||||
'@nestjs/swagger':
|
||||
specifier: ^7.4.0
|
||||
version: 7.4.2(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)
|
||||
'@prisma/client':
|
||||
specifier: ^6.19.3
|
||||
version: 6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)
|
||||
'@sendgrid/mail':
|
||||
specifier: ^8.1.0
|
||||
version: 8.1.6
|
||||
@@ -357,9 +360,6 @@ importers:
|
||||
'@nestjs/testing':
|
||||
specifier: ^11.1.19
|
||||
version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)
|
||||
'@prisma/client':
|
||||
specifier: ^6.19.3
|
||||
version: 6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)
|
||||
'@types/bcrypt':
|
||||
specifier: ^5.0.2
|
||||
version: 5.0.2
|
||||
|
||||
19
scripts/deploy/create-npmrc.sh
Normal file
19
scripts/deploy/create-npmrc.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create .npmrc_temp and .npmrc for Docker BuildKit / compose secrets.
|
||||
# Requires NPM_TOKEN in the environment.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${NPM_TOKEN:-}" ]]; then
|
||||
echo "NPM_TOKEN is not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF > .npmrc_temp
|
||||
@tria-plc:registry=https://npm.pkg.github.com
|
||||
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
|
||||
always-auth=true
|
||||
EOF
|
||||
|
||||
cp .npmrc_temp .npmrc
|
||||
echo "Created .npmrc_temp and .npmrc for private @tria-plc packages"
|
||||
68
scripts/deploy/sync-env-from-server.sh
Normal file
68
scripts/deploy/sync-env-from-server.sh
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
# Sync .env files from the self-hosted runner filesystem into the repo.
|
||||
#
|
||||
# Usage:
|
||||
# PROJECT=edr-freight BRANCH=main ./scripts/deploy/sync-env-from-server.sh freight-api freight-portal freight-backoffice
|
||||
#
|
||||
# Server layout (one file per service):
|
||||
# /home/user/environmen/<project>/<branch>/freight-api.env
|
||||
# /home/user/environmen/<project>/<branch>/freight-portal.env
|
||||
# /home/user/environmen/<project>/<branch>/freight-web.build.env (optional, exports VITE_API_URL etc.)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DEPLOY_USER="${DEPLOY_USER:-tria}"
|
||||
ENV_ROOT="${ENV_ROOT:-/home/${DEPLOY_USER}/environmen/${PROJECT:?PROJECT is required}/${BRANCH:?BRANCH is required}}"
|
||||
|
||||
if [[ ! -d "${ENV_ROOT}" ]]; then
|
||||
echo "Environment directory not found: ${ENV_ROOT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Using environment directory: ${ENV_ROOT}"
|
||||
|
||||
declare -A SERVICE_ENV_TARGET=(
|
||||
["freight-api"]="apps/edr-freight-api/.env"
|
||||
["freight-portal"]="apps/edr-freight-web/portal/.env"
|
||||
["freight-backoffice"]="apps/edr-freight-web/backoffice/.env"
|
||||
["passenger-api"]="apps/edr-passenger-api/.env"
|
||||
["passenger-portal"]="apps/edr-passenger-web/portal/.env"
|
||||
["passenger-backoffice"]="apps/edr-passenger-web/backoffice/.env"
|
||||
)
|
||||
|
||||
for service in "$@"; do
|
||||
src="${ENV_ROOT}/${service}.env"
|
||||
dest="${SERVICE_ENV_TARGET[${service}]:-}"
|
||||
|
||||
if [[ -z "${dest}" ]]; then
|
||||
echo "Unknown service: ${service}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${src}" ]]; then
|
||||
echo "Missing env file: ${src}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${dest}")"
|
||||
cp "${src}" "${dest}"
|
||||
echo "Synced ${src} -> ${dest}"
|
||||
done
|
||||
|
||||
# Optional build-time variables (VITE_API_URL, etc.)
|
||||
# Set BUILD_ENV_FILE=freight-web.build.env or passenger-web.build.env per workflow.
|
||||
build_env_file="${BUILD_ENV_FILE:-web.build.env}"
|
||||
build_env="${ENV_ROOT}/${build_env_file}"
|
||||
if [[ -f "${build_env}" ]]; then
|
||||
echo "Loading build variables from ${build_env}"
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "${build_env}"
|
||||
set +a
|
||||
|
||||
if [[ -n "${GITHUB_ENV:-}" ]]; then
|
||||
grep -E '^[[:space:]]*export[[:space:]]+[A-Za-z_][A-Za-z0-9_]*=' "${build_env}" \
|
||||
| sed -E 's/^[[:space:]]*export[[:space:]]+//' >> "${GITHUB_ENV}"
|
||||
echo "Wrote build variables to GITHUB_ENV"
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user