# App NODE_ENV=development PORT=4000 # Database (Prisma) — owns the `passenger` schema in edr_database # Production: append ?sslmode=require&connection_limit=10&pool_timeout=20 to enforce SSL and connection pooling DATABASE_URL=postgresql://edr:edr_secret@localhost:5432/edr_database?schema=passenger # Database (TypeORM / @tria-plc IAM) — shared `iam` schema in the SAME edr_database. # These mirror the connection vars read by @tria-plc/api-common's TypeORM DataSource. DATABASE_HOST=localhost DATABASE_PORT=5432 DATABASE_NAME=edr_database DATABASE_USER=edr DATABASE_PASSWORD=edr_secret DATABASE_SCHEMA=iam # RabbitMQ — the @tria-plc IAM/notification modules register RMQ clients (SMS/notifications). # Connects lazily; a broker is only needed when those features actually send. Placeholder for dev. RABBITMQ_URL=amqp://localhost:5672 # MinIO — the @tria-plc file/notification modules construct a MinIO client at boot (validates these). # Placeholders for dev; only contacted when file upload/download features are actually used. MINIO_ENDPOINT=localhost MINIO_PORT=9000 MINIO_USE_SSL=false MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_BUCKET=edr-dev # CORS — comma-separated list of allowed origins (add more, comma-separated) CORS_ORIGINS=http://localhost:5174,http://localhost:5184 # JWT (legacy passenger auth — being replaced by IAM) # REQUIRED in production — use a random 32+ character string (e.g. openssl rand -hex 32) JWT_SECRET= JWT_EXPIRES_IN=7d # @tria-plc IAM token contract — REQUIRED in production. MUST match the IAM issuer's secret. JWT_ACCESS_TOKEN_SECRET= JWT_ACCESS_TOKEN_EXPIRES=1h JWT_REFRESH_TOKEN_SECRET= JWT_REFRESH_TOKEN_EXPIRES=7d # @tria-plc IAM forgot-password flow — the reset link sent via SMS is # ${FE_BASE_URL}/reset-password?email=..&userId=..&verificationCode=.. # Point at the backoffice web app. Without it the link starts with "undefined/". FE_BASE_URL=http://localhost:5184 # OTP/reset-link TTL in minutes (IAM default: 30) INVITATION_EXPIRY_DATE=30 # 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 — credentials live in edr-payment-api only; the passenger API never calls providers # directly. eBirr has no redirect, so there is no EBIRR_RETURN_URL. See docs/ebirr/INTEGRATION.md. # Card Gateway (Stripe-like) CARD_BASE_URL= CARD_API_KEY= CARD_WEBHOOK_SECRET= CARD_WEBHOOK_URL= CARD_RETURN_URL= # Waafi (Djibouti Mobile Money — Hosted Payment Page) # Sandbox: https://sandbox.waafipay.net | Production: https://api.waafipay.net WAAFI_BASE_URL=https://sandbox.waafipay.net WAAFI_MERCHANT_UID= WAAFI_STORE_ID= WAAFI_HPP_KEY= # HMAC secret returned once by WEBHOOK_REGISTER — verifies inbound webhooks WAAFI_WEBHOOK_SECRET= WAAFI_PAYMENT_METHOD=MWALLET_ACCOUNT # Waafi has no ETB; overrides booking currency (USD/DJF/SLSH) WAAFI_CURRENCY=DJF WAAFI_HPP_SUCCESS_URL= WAAFI_HPP_FAILURE_URL= # 1 = POST, 2 = GET, 4 = Result Token WAAFI_HPP_RESP_FORMAT=1 # Registered webhook URL (registration done out-of-band) WAAFI_NOTIFY_URL= # DEV ONLY — disable TLS cert verification (sandbox serves a *.waafi.com cert). Never true in prod. WAAFI_INSECURE_TLS=false # Payment Configuration PAYMENT_PROVIDERS_ENABLED=TELEBIRR,CBE_BIRR,EBIRR,CARD,WALLET,WAAFI # Portal domains the browser-facing redirects (telebirr, waafi, Fayda WEB) may be rebased onto: # the API swaps the configured URL's host for whichever of these the request came from. Comma- # separated exact origins (scheme + host, no trailing slash). Leave empty to always use the # configured URLs below. DMONEY is a server webhook and is never rebased. PAYMENT_REDIRECT_ALLOWED_ORIGINS= # Browser return targets after a hosted payment page (UX only — payment is confirmed by the # webhook/queryStatus, never this redirect). Global fallback used when a method-specific URL # below is unset. Most providers use a single redirect; Waafi takes separate success/failure. PAYMENT_RETURN_URL= PAYMENT_FAILURE_URL= TELEBIRR_RETURN_URL= WAAFI_SUCCESS_REDIRECT= WAAFI_FAIL_REDIRECT= DMONEY_RETURN_URL= CBE_RETURN_URL= CARD_RETURN_URL= # 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 (eSignet) OIDC integration --- FAYDA_ENABLED=true FAYDA_CLIENT_ID= FAYDA_AUTHORIZATION_ENDPOINT= FAYDA_TOKEN_ENDPOINT= FAYDA_USERINFO_ENDPOINT= # Base64 of the RSA private JWK (JSON). Secret — never commit a real value. FAYDA_PRIVATE_KEY_BASE64= # OAuth redirect_uri passed to eSignet for MOBILE clients (the app calls /complete directly). FAYDA_REDIRECT_URI= # OAuth redirect_uri passed to eSignet for WEB clients. Defaults to FAYDA_REDIRECT_URI when unset. FAYDA_WEB_REDIRECT_URI= # Optional (defaults shown) FAYDA_SCOPE=openid profile email FAYDA_ACR_VALUES=mosip:idp:acr:generated-code FAYDA_CLAIMS_LOCALES=en am FAYDA_SESSION_TTL_MINUTES=10 GITHUB_PACKAGE_TOKEN= # --- Seeding ----------------------------------------------------------------- # Set both to true on first run (or when resetting) to seed org, roles, and # default backoffice staff users. Safe to leave true — all operations are idempotent. # Login endpoint for backoffice users: POST /v1/auth/login SEED_EDR_PASSENGER_ORG=false SEED_PASSENGER_STAFF=false # IAM baseline shared with edr-freight-api (roles, IAM app + permissions, position # types, organization types + default units, org/unit settings, super admin). # Replaces the seeder that used to ship 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 # Super-admin account seeded by the above. Shared across the apps on this schema. SUPER_ADMIN_EMAIL=superadmin@tria.com SUPER_ADMIN_PHONE= # Falls back to DEFAULT_PASSWORD when empty. SUPER_ADMIN_DEFAULT_PASSWORD= # Plain-text password set on seeded staff accounts. Defaults to '12345678' if unset. DEFAULT_PASSWORD=Admin@1234 # --- Notification broker (RabbitMQ) ----------------------------------------------------------------- # Set RABBITMQ_ENABLED=false to skip connection entirely (dev without a local broker). RABBITMQ_ENABLED=false RABBITMQ_URL=amqp://localhost:5672 EMAIL_QUEUE=email_queue SMS_QUEUE=sms_queue # --- Payment event consumer (RabbitMQ) ------------------------------------------------------- # Consumes payment.succeeded / payment.failed events from the payment microservice. Separate # from any RABBITMQ_URL used by the IAM/notification modules so the two connections are # independent. Points at the dedicated `payment` vhost on the (shared) broker. # Local dev broker (docker): amqp://edr:edr_secret@localhost:5672/payment PAYMENT_RABBITMQ_URL=amqp://edr:edr_secret@localhost:5672/payment # Max unacknowledged payment events this consumer holds at once. PAYMENT_EVENTS_PREFETCH=10