# Copy to .env for local/docker compose (not committed). PORT=3001 # @tria-plc/auditlog's client interceptor stamps every AuditLog row's # `application` from this env var directly, bypassing MezgebModule.forRoot's # applicationName option (package quirk). audit.controller.ts reads the same # var when filtering reads, so this can be anything as long as it's set. APPLICATION_NAME=freight-api # Also required for @tria-plc/auditlog: its producer (AuditClientModule) # reads the RMQ URL at package IMPORT time, before MezgebModule.forRoot's # rmqUrl option ever runs, so only an env var reaches it — an in-code # override is too late. Without this, audit events are silently dropped # (no error, nothing published). Point it at whatever broker/vhost your # RabbitMQ actually has a user provisioned on. RABBITMQ_URL=amqp://localhost:5672 # GT06 GPS tracker TCP listener port (raw TCP, must be reachable by tracker SIMs). 0 disables. GT06_TCP_PORT=5023 DB_HOST=localhost DB_PORT=5433 DB_USER=postgres DB_PASSWORD= DB_NAME=edr_freight # Telebirr payment gateway (freight merchant credentials) TELEBIRR_BASE_URL= TELEBIRR_WEB_BASE_URL= TELEBIRR_FABRIC_APP_ID= TELEBIRR_APP_SECRET= TELEBIRR_MERCHANT_APP_ID= TELEBIRR_MERCHANT_CODE= TELEBIRR_NOTIFY_URL=https://freight-api.edr.et/payments/webhooks/telebirr TELEBIRR_RETURN_URL= TELEBIRR_TIMEOUT_EXPRESS=15m TELEBIRR_PRIVATE_KEY= TELEBIRR_PUBLIC_KEY= TELEBIRR_INSECURE_TLS=false # Public origin of the freight customer portal. Password-reset links sent to # customers are built against this — it must be browser-reachable. FREIGHT_PORTAL_URL=http://localhost:5173 # Portal pages the payment provider redirects the browser to after payment. # Point these at the freight portal's public payment result routes. PAYMENT_RETURN_URL=http://localhost:5173/payment/success PAYMENT_FAILURE_URL=http://localhost:5173/payment/failure # Drain tail (minutes) added to every booking pay window before anything expires: # settlement is asynchronous, so a payment made in the window's last seconds lands # after the deadline. Nothing is expired, no wagons are resold and no window cycle # concludes until the tail passes. Defaults to 5 when unset. FREIGHT_PAYMENT_DRAIN_MINUTES=5 # JWT (used by @tria-plc/api-common SharedAuthModule) JWT_SECRET= JWT_ACCESS_TOKEN_SECRET= JWT_REFRESH_TOKEN_SECRET= JWT_EXPIRES_IN=3600 # JWT expiry for @tria-plc/api-common token utils (jsonwebtoken timespan format) JWT_ACCESS_TOKEN_EXPIRES=1h JWT_REFRESH_TOKEN_EXPIRES=7d # IAM seed defaults (used by @tria-plc/iamapi-common on first boot) SUPER_ADMIN_EMAIL=superadmin@tria.com SUPER_ADMIN_PHONE= # Super-admin password. Falls back to DEFAULT_PASSWORD when empty. SUPER_ADMIN_DEFAULT_PASSWORD= DEFAULT_PASSWORD=password@tria # IAM baseline shared with edr-passenger-api (roles, IAM app + permissions, # position types, organization types + default units, org/unit settings, super # admin). Replaces the seeder that shipped inside @tria-plc/iamapi-common — see # packages/iam-seed. Seeds by DEFAULT when unset; every write is insert-only. # Set to false to opt out. SEED_IAM_BASELINE=true # Freight org + staff (bookings / rule-engine IAM) SEED_EDR_ORG=true SEED_FREIGHT_STAFF=true SEED_EXPORT_DJIBOUTI_INTERCHANGE_DEMO=false # MinIO (used by @tria-plc/iamapi-common for file storage) MINIO_ENDPOINT=localhost MINIO_PORT=9000 MINIO_USE_SSL=false MINIO_ACCESS_KEY= MINIO_SECRET_KEY= # Preset region so signed URLs are generated locally (no GetBucketLocation # network call per sign). MinIO's default is us-east-1. MINIO_REGION=us-east-1 # Redis REDIS_HOST=localhost REDIS_PORT=6379 # --- Notification broker (RabbitMQ) --------------------------------------------- # SMS/email OTP + notifications are queued to RabbitMQ (consumed by the shared # SMS/email services). Set RABBITMQ_ENABLED=false to skip the broker entirely # (dev without a local broker). RABBITMQ_ENABLED=false RABBITMQ_URL=amqp://localhost:5672 SMS_QUEUE=sms_queue # ── VeriFayda 2.0 (eSignet OIDC) identity verification ────────────────────── # Disabled by default; /fayda/verification/start returns 503 until enabled. FAYDA_ENABLED=false FAYDA_CLIENT_ID= FAYDA_AUTHORIZATION_ENDPOINT= FAYDA_TOKEN_ENDPOINT= FAYDA_USERINFO_ENDPOINT= # Base64-encoded RSA private JWK used for the private_key_jwt client assertion FAYDA_PRIVATE_KEY_BASE64= # OAuth redirect_uri for MOBILE clients (must be registered with eSignet) FAYDA_REDIRECT_URI=http://localhost:3001/api/fayda/verification/complete # OAuth redirect_uri for WEB clients. Defaults to FAYDA_REDIRECT_URI when unset. FAYDA_WEB_REDIRECT_URI=http://localhost:3000/fayda/callback # OAuth redirect_uri for the customer portal (its own origin — must also be # registered with eSignet). Defaults to FAYDA_WEB_REDIRECT_URI when unset. FAYDA_PORTAL_REDIRECT_URI=http://localhost:5173/fayda/callback CLIENT_ASSERTION_TYPE=urn:ietf:params:oauth:client-assertion-type:jwt-bearer FAYDA_SCOPE=openid profile email phone address FAYDA_ACR_VALUES=mosip:idp:acr:generated-code FAYDA_CLAIMS_LOCALES=en am FAYDA_SESSION_TTL_MINUTES=10 EXPIRATION_TIME=15 ALGORITHM=RS256 EMAIL_QUEUE=email_queue # Shared secret for service-to-service calls (payment microservice <-> freight). # Required at boot; set ALLOW_UNAUTH_INTERNAL=true instead ONLY for local dev. SERVICE_AUTH_TOKEN=change-me # ── MoR EIMS e-invoicing (core.mor.gov.et) ───────────────────────────────── # Disabled by default; every EIMS call fails fast with EIMS_NOT_CONFIGURED until enabled. EIMS_ENABLED=false EIMS_BASE_URL=https://core.mor.gov.et EIMS_CLIENT_ID= EIMS_CLIENT_SECRET= EIMS_API_KEY= EIMS_TIN= # MoR-issued source-system identifiers (used once invoice registration lands) EIMS_SYSTEM_NUMBER= EIMS_SYSTEM_TYPE= # Absolute paths to the INSA-issued credentials. Keep them OUTSIDE the repo; the file # patterns are gitignored, but a path outside the working tree is safer still. # The certificate is transmitted as base64 of this file's exact bytes — do not convert it. EIMS_PRIVATE_KEY_PATH= EIMS_CERTIFICATE_PATH= # Optional tuning EIMS_HTTP_TIMEOUT_MS=30000 EIMS_TOKEN_SKEW_SECONDS=45 # ── EIMS invoice registration (required only to register invoices) ───────── # Seller identity: EDR's own legal details are not modelled anywhere in the DB. # Region and Wereda are MoR *codes* (e.g. 13 / 574), not names. EIMS_SELLER_LEGAL_NAME= EIMS_SELLER_VAT_NUMBER= EIMS_SELLER_PHONE= EIMS_SELLER_EMAIL= EIMS_SELLER_REGION= EIMS_SELLER_WEREDA= # Optional seller address parts; sent as null when unset. EIMS_SELLER_CITY= EIMS_SELLER_SUBCITY= EIMS_SELLER_HOUSE_NUMBER= EIMS_SELLER_LOCALITY= # Tax treatment — REQUIRES FINANCE SIGN-OFF. The application models no tax at all # (invoice.taxAmount is always 0), so nothing here is defaulted: registration fails # locally, naming the missing variables, until these are set. EIMS_TAX_CODE= EIMS_TAX_RATE_PERCENT= EIMS_EXCISE_TAX_VALUE=0 EIMS_INCOME_WITHHOLD_VALUE=0 EIMS_TRANSACTION_WITHHOLD_VALUE=0 # Document classification and payment presentation. EIMS_TRANSACTION_TYPE=B2B EIMS_NATURE_OF_SUPPLIES=Service EIMS_PAYMENT_MODE=CASH EIMS_PAYMENT_TERM=IMMIDIATE EIMS_UNIT_DEFAULT=PCS # MoR numeric country code for the buyer; our companies store the country name. EIMS_BUYER_COUNTRY_CODE= EIMS_CASHIER_NAME= EIMS_SALESPERSON_NAME=