Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copy to `.env.development` / `.env.production`.
# Docker Compose reads `./.docker/.env` instead (POSTGRES_*, REDIS_*, PORT, ...).
# Every key below is validated at boot by `src/common/config/env.validation.ts`.

# --- Required: infrastructure ---
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/hambaar-db
REDIS_URL=redis://:redis@localhost:6379
OTP_REDIS_URL=redis://:redis@localhost:6379/1
SESSION_REDIS_URL=redis://:redis@localhost:6379/2

# --- Required: secrets (min 16 chars where noted) ---
SESSION_SECRET=change-me-min-16-chars
COOKIE_SECRET=change-me
JWT_ACCESS_SECRET_KEY=change-me-min-16-chars
JWT_TEMP_SECRET_KEY=change-me-min-16-chars
JWT_PROGRESS_SECRET_KEY=change-me-min-16-chars

# --- Required: storage / external APIs ---
AWS_ACCESS_KEY=change-me
AWS_SECRET_KEY=change-me
AWS_BUCKET_NAME=hambaar
AWS_ENDPOINT=https://s3.example.com
MAP_API_KEY=change-me
MAP_API_URL=https://api.neshan.org/v1
SMS_API_KEY=change-me

# --- Optional: runtime (defaults shown) ---
# MAX_UPLOAD_SIZE_MB=10
# JWT_ACCESS_EXPIRES_IN=20d
# JWT_TEMP_EXPIRES_IN=20m
# JWT_PROGRESS_EXPIRES_IN=1d
# PORT=3000
# API_PREFIX=api
# CORS_ORIGINS=http://localhost:8080
# LOG_LEVEL=log
# TIMEOUT_MS=30000
# RESPONSE_WRAPPER_ENABLED=true
# MEMORY_HEAP_THRESHOLD_MB=150
# COOKIE_MAX_AGE=1296000000
# COOKIE_SECURE=false
# COOKIE_SAMESITE=lax
# COOKIE_DOMAIN=
# THROTTLE_TTL=60
# THROTTLE_LIMIT=100
# PRISMA_TX_TIMEOUT_MS=
# AWS_REGION=default

# --- Optional: OTP flow ---
# OTP_EXPIRATION_TIME=120000
# MAX_SEND_ATTEMPTS=5
# MAX_CHECK_ATTEMPTS=10
# SEND_WINDOW=1800000
# BASE_BLOCK_TIME=1200000

# --- Optional: pricing (defaults mirror the legacy service) ---
# PRICING_BASE_PRICE=50000
# PRICING_FUEL_RATE=200
# PRICING_WEIGHT_BASE_RATE=10000
# NOTE: both keys below are validated as @IsInt, so fractional values fail
# boot (known quirk — see REFACTOR.md). Only DRIVER_SHARE is read (0.7);
# PLATFORM_COMMISSION is currently unused by the engine.
# PRICING_PLATFORM_COMMISSION=0.3
# PRICING_DRIVER_SHARE=0.7
# PRICING_FRAGILE_MULTIPLIER=1.25
# PRICING_PERISHABLE_MULTIPLIER=1.35
# PRICING_BOTH_FRAGILE_PERISHABLE=1.5
# PRICING_MAJOR_CITY_ORIGIN=0.9
# PRICING_MAJOR_CITY_DESTINATION=1.3
# PRICING_BOTH_MAJOR_CITIES=1.0
# PRICING_SMALL_CITY_FACTOR=1.2
# PRICING_DEVIATION_RATE=15000
# PRICING_TIME_DEVIATION_RATE=5000
# PRICING_TIER_1_RATE=1000
# PRICING_TIER_2_RATE=950
# PRICING_TIER_3_RATE=850
# PRICING_TIER_4_RATE=750
# PRICING_TIER_5_RATE=600
# PRICING_MAJOR_CITIES=تهران,اصفهان,مشهد
# CORRIDOR_WIDTH=10

# --- Optional: boot behavior ---
# SEED_ON_BOOT=false
123 changes: 84 additions & 39 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,135 @@ on:
pull_request:
branches: [ "master" ]

env:
NODE_ENV: production
DATABASE_URL: postgresql://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@hambaar.postgres:5432/${{ secrets.POSTGRES_DB }}
REDIS_URL: redis://:${{ secrets.REDIS_PASSWORD }}@hambaar.redis:6379
JWT_ACCESS_SECRET_KEY: ${{ secrets.JWT_ACCESS_SECRET_KEY }}
JWT_PROGRESS_SECRET_KEY: ${{ secrets.JWT_PROGRESS_SECRET_KEY }}
JWT_TEMP_SECRET_KEY: ${{ secrets.JWT_TEMP_SECRET_KEY }}
COOKIE_SECRET: ${{ secrets.COOKIE_SECRET }}
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME }}
AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
MAP_API_KEY: ${{ secrets.MAP_API_KEY }}
MAP_API_URL: ${{ secrets.MAP_API_URL }}
SMS_API_KEY: ${{ secrets.SMS_API_KEY }}

jobs:
test:
runs-on: ubuntu-latest
container: node:22-bookworm-slim
# Unit suite is fully mocked (no DB/Redis/network): the only env it may
# see is NODE_ENV. No secrets here (T-6).
env:
NODE_ENV: test
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Update and Upgrade image
run: apt-get update -y
&& apt-get upgrade -y
&& apt-get install -y openssl
&& apt-get install -y bash

- name: Install Dependencies
run: npm ci --include=dev

- name: Generate Prisma Client
run: npm run prisma:generate

# No lint gate: repo-wide CRLF/prettier debt predates the refactor
# and would fail a clean check. Local workflow stays `npm run lint`
# (--fix). Tracked for a whitespace-normalization pass post-refactor.
- name: Type check
run: npx tsc --noEmit

- name: Run Unit Tests with Coverage
run: npm test -- --coverage

- name: Upload Coverage Report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/

integration:
runs-on: ubuntu-latest
needs: test
container: node:22-bookworm-slim
services:
postgres:
image: postgres
image: postgres:17
env:
POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: hambaar_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

redis:
image: redis
image: redis:8
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

# Dummy (non-secret) values only — SMS/Neshan/S3 are faked at the port
# boundary inside the suite. NOTE: `npm run test:integration` carries
# localhost defaults for local runs, so CI invokes push + jest directly.
env:
NODE_ENV: test
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/hambaar_test
REDIS_URL: redis://redis:6379
OTP_REDIS_URL: redis://redis:6379/1
SESSION_REDIS_URL: redis://redis:6379/2
SESSION_SECRET: ci-session-secret-min-16-chars
COOKIE_SECRET: ci-cookie-secret
JWT_ACCESS_SECRET_KEY: ci-jwt-access-secret-min-16
JWT_TEMP_SECRET_KEY: ci-jwt-temp-secret-min-16
JWT_PROGRESS_SECRET_KEY: ci-jwt-progress-secret-min-16
AWS_ACCESS_KEY: ci
AWS_SECRET_KEY: ci
AWS_BUCKET_NAME: ci-bucket
AWS_ENDPOINT: https://s3.ci.local
MAP_API_KEY: ci
MAP_API_URL: https://maps.ci.local
SMS_API_KEY: ci
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Update and Upgrade image
run: apt-get update -y
&& apt-get upgrade -y
&& apt-get install -y openssl
&& apt-get install -y bash

- name: Install Dependencies
run: npm ci --include=dev

# TODO: Uncomment when add e2e tests
# - name: Push DB with prisma
# run: npm run prisma:push


- name: Generate Prisma Client
run: npm run prisma:generate

- name: Run Unit Tests
run: npm test
- name: Push Test Schema
run: npx prisma db push --skip-generate

- name: Run Integration Tests
run: npx jest --config ./test/jest-integration.json

- name: Run e2e Smoke Tests
run: npm run test:e2e

build:
runs-on: ubuntu-latest
needs: test
needs: integration
if: github.event_name == 'push' && github.ref == 'refs/heads/master'

steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
Expand All @@ -99,7 +144,7 @@ jobs:
type=ref,event=branch
type=sha,prefix=main-
latest

- name: Build Image and Push to DockerHub
uses: docker/build-push-action@v5
with:
Expand All @@ -108,4 +153,4 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
target: runtime
target: runtime
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ coverage-*.txt

# dotenv environment variable files
.env*
!.env.example

# temp directory
.temp
Expand All @@ -52,5 +53,4 @@ pids
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

/generated
/docs
/generated
Loading
Loading