# Database configuration POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres POSTGRES_DB=goldbank # Host port for PostgreSQL. Each copy of this stack on the same machine # must use a different port (the apps talk to hostname "db", not this port). EXTERNAL_DB_PORT=5432 # Prisma connection string (inside Docker network use hostname "db") DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public # --------------------------------------------------------------------------- # Dev server ports — SINGLE SOURCE OF TRUTH for this monorepo. # Every app's dev script/config reads its port from here. Do not hardcode a # port anywhere else. strictPort is enabled everywhere: if a port below is # already taken, the dev server fails with a clear error instead of silently # picking another port. # --------------------------------------------------------------------------- API_PORT=3000 ADMIN_PANEL_PORT=5180 USER_APP_PORT=5181 USER_APP_V2_PORT=5182 # API Configuration (kept for any tooling that still reads bare PORT) PORT=3000 # --------------------------------------------------------------------------- # Authentication # --------------------------------------------------------------------------- # Admin JWT signing secret. REQUIRED in any real deployment — without it the # API falls back to a well-known development string. JWT_SECRET= # Admin token lifetime (default 12h). JWT_EXPIRES_IN= # Customer JWT signing secret. Deliberately SEPARATE from JWT_SECRET so an # admin token can never validate as a customer token (T1). JWT_CUSTOMER_SECRET= # Customer token lifetime (default 30d). JWT_CUSTOMER_EXPIRES_IN= # --------------------------------------------------------------------------- # Accounting software integration (Tahesab / Zarrin, D27). Everything else — # which software, address, token, mappings — is set in the admin panel # («پیکر بندی ← اتصال حسابداری»), and the integration is off until then. # --------------------------------------------------------------------------- # Encrypts the accounting token at rest. Set a long random value. Blank falls # back to a key derived from JWT_SECRET (with a boot warning); changing that # key later means re-entering the token in the admin panel. ACCOUNTING_SECRET_KEY= # "off" keeps this API instance out of the background sync (only needed when # several instances run and you want exactly one doing it; a lease already # stops two from running the same job). ACCOUNTING_WORKER= # --------------------------------------------------------------------------- # Central IAM — delegated admin login (docs/iam-sso.md) # --------------------------------------------------------------------------- # OFF by default. When off, nothing changes: admin login stays a local bcrypt # check and no request ever leaves this server. # # When on, the admin's phone + password are verified against the central # identity service instead. There is NO UI change: no SSO button, no redirect. # If the identity service is unreachable or does not know the account, the # local password check still runs (see IAM_LOGIN_DELEGATION). IAM_ENABLED=false IAM_ISSUER= # The client must be registered there as confidential AND trusted. IAM_CLIENT_ID= IAM_CLIENT_SECRET= # One of the two; tenant_id wins when both are set. IAM_TENANT_ID= IAM_TENANT_SLUG= # off | fallback (default, safest) | exclusive (local password no longer accepted) IAM_LOGIN_DELEGATION=fallback IAM_HTTP_TIMEOUT_MS=8000 # صفحه callback اپ کاربر. باید در کلاینت IAM دقیقاً ثبت شود. IAM_REDIRECT_URI= # callbackهای اضافه (دولوپ و دامنه دیگر) با کاما. آدرس ناشناس جایگزین نمی‌شود. IAM_REDIRECT_URIS= # بعد از ورود محلی، مرورگر برای کوکی نشست مشترک به اینجا برمی‌گردد. IAM_BROWSER_RETURN_URL= # خروج سراسری فقط اگر این آدرس در post_logout کلاینت ثبت شده باشد برمی‌گردد. IAM_POST_LOGOUT_REDIRECT_URI= # مقصدهای مجاز خروج اپ کاربر، با کاما. باید عیناً در post_logout کلاینت باشند. IAM_ALLOWED_RETURN_URLS= # پنل ادمین. خالی یعنی بررسی بی‌صدای ورود در پنل انجام نمی‌شود. IAM_ADMIN_REDIRECT_URI= IAM_ADMIN_REDIRECT_URIS= IAM_ADMIN_BROWSER_RETURN_URL= IAM_ADMIN_POST_LOGOUT_REDIRECT_URI= IAM_ADMIN_ALLOWED_RETURN_URLS= # Revocable admin sessions (AdminSession table). # # An admin token is self-contained and lives for JWT_EXPIRES_IN (12h), so until # this existed nothing could end a session early — not disabling the account, not # a central sign-out. Every issued token now carries a `jti` recorded in the # database, and a revoked row is refused on the next request. # # Unset = follows IAM_ENABLED (on with the IAM, so central revocation reaches # here). `true` turns it on without the IAM; `false` opts out of the per-request # lookup and central revocation then cannot end a session here. AUTH_SESSION_TRACKING= # To let the IAM end sessions here, register this path on the client there as its # backchannel_logout_uri: # https:///api/iam/backchannel-logout # --------------------------------------------------------------------------- # ⚠ DELIVERY ONLY — REMOVE BEFORE THE REAL RELEASE (D20 / ISSUES REL-01) # --------------------------------------------------------------------------- # A fixed OTP that signs in ANY active customer, alongside the real code. # MUST BE EXACTLY 4 DIGITS: the apps' login box has four single-character # inputs and only submits at four (LoginView.vue:43). A longer code still works # over the API but cannot be typed into either app. # Leave it EMPTY or unset to disable it completely — that is the correct state # for production. While it is set, the API prints a warning banner at boot. OTP_MASTER_CODE= # --------------------------------------------------------------------------- # SMS gateway. The default "relay" driver works with everything blank (D26). # A failed SMS never stops the server or an operation (D20). # --------------------------------------------------------------------------- # "relay" (default), "trez", or "none" to disable explicitly. SMS_PROVIDER= # relay — the owner's createsms gateway. All four are optional. # URL and secret have built-in defaults. SMS_RELAY_URL= SMS_RELAY_SECRET= # The "host" field. Blank sends this machine's first external IPv4 — inside # Docker that is the container's address. SMS_RELAY_HOST= # trez — only used with SMS_PROVIDER=trez. Never commit real values. # Override only for staging; defaults to the provider's live endpoint. SMS_TREZ_URL= SMS_TREZ_USERNAME= SMS_TREZ_PASSWORD= SMS_TREZ_SENDER_LINE= # --------------------------------------------------------------------------- # Uploads # --------------------------------------------------------------------------- # Absolute path for uploaded files; defaults to /storage/uploads. UPLOAD_DIR= # --------------------------------------------------------------------------- # Profile completion ("تکمیل پروفایل") # --------------------------------------------------------------------------- # Comma-separated admin mobiles told when a customer uploads their documents. # The reference hardcoded four numbers in its source # (henza_server Major/CustomerController::sendSmsToAdmin); they live here # instead so no personal number is committed. Blank means nobody is notified — # the upload and the customer's own SMS still go through (D20). PROFILE_ADMIN_MOBILES= # --------------------------------------------------------------------------- # Order placement # --------------------------------------------------------------------------- # Comma-separated admin mobiles told when a customer places an order. The # reference hardcoded four numbers (henza_server # Api/ApiMobileController::setOrder:740-743). Blank means nobody is notified — # the order, the customer's SMS and the sales expert's SMS still go through. ORDER_ADMIN_MOBILES=