1- # ─── Server ───────────────────────────────────────
1+ # ─────────────────────────────────────────────────────────────────────
2+ # HiTechCloud — environment configuration
3+ #
4+ # CONFIG-IN-DB DOCTRINE: platform configuration lives in the settings
5+ # table (admin dashboard → Settings, or GET/PUT /api/v1/admin/config).
6+ # Precedence is: DB value > env var > built-in default. Everything in
7+ # this file except the eight BOOTSTRAP variables below is only a
8+ # FALLBACK for installs that predate config-in-DB — prefer the
9+ # dashboard. When an env var carries a value that the database does
10+ # not override, the server logs one deprecation line per variable at
11+ # boot. Secret values are sealed at rest (SECRET_ENCRYPTION_KEY) and
12+ # are never returned by any API.
13+ #
14+ # BOOTSTRAP (stay in the environment forever — key material and
15+ # infrastructure addresses needed BEFORE the database is reachable,
16+ # deliberately absent from the settings catalog):
17+ # PORT, DATABASE_URL, JWT_SECRET, LICENSE_SIGNING_KEY,
18+ # SECRET_ENCRYPTION_KEY, RELEASE_KEY_ENCRYPTION_KEY,
19+ # REFERRAL_HASH_SALT, REDIS_URL
20+ # ─────────────────────────────────────────────────────────────────────
21+
22+ # ─── Server ───────────────────────────────────────────────
223PORT = 9000
24+ # catalog: app.environment (restart-scoped)
325ENVIRONMENT = development # development | staging | production
26+ # catalog: app.base_url (restart-scoped)
427BASE_URL = http://localhost:9000
528
629# ─── Database ─────────────────────────────────────
@@ -32,8 +55,9 @@ RELEASE_KEY_ENCRYPTION_KEY=
3255STRIPE_SECRET_KEY =
3356# Optional: set explicitly when running multiple instances behind a
3457# shared Stripe webhook endpoint configuration.
35- STRIPE_WEBHOOK_SECRET =
36-
58+ STRIPE_WEBHOOK_SECRET = # Optional: trust live-mode events. Unset = derived from the secret
59+ # key prefix (sk_live_ → live, sk_test_ → test).
60+ STRIPE_LIVEMODE =
3761# ─── Payments (Vietnamese gateways, one-off VND) ─
3862# Pay2S (bank transfer / Napas 247 QR): https://docs.pay2s.vn
3963# A gateway is active only when ALL of its credentials are set. Leave
@@ -42,6 +66,8 @@ STRIPE_WEBHOOK_SECRET=
4266# Bank accounts: repeated "bankId|accountNumber|accountName|bankName"
4367# separated by commas — these are the accounts buyers transfer to.
4468PAY2S_PARTNER_CODE =
69+ # Display name shown to the buyer at Pay2S checkout.
70+ PAY2S_PARTNER_NAME = HiTechCloud
4571PAY2S_ACCESS_KEY =
4672PAY2S_SECRET_KEY =
4773PAY2S_BANK_ACCOUNTS =
@@ -87,8 +113,10 @@ RATE_LIMIT_AUTH=60
87113# Login codes per IP per HOUR. Deliberately tight: this endpoint mails
88114# an address the caller supplies, so a loose budget lets someone use
89115# your server (and your sending reputation) to spam third parties.
90- RATE_LIMIT_OTP_SEND = 30
91-
116+ RATE_LIMIT_OTP_SEND = 30 # Brute-force guard on /license/*: failed license keys per IP before a
117+ # lockout, and the lockout duration in seconds.
118+ BF_MAX_FAILS = 5
119+ BF_LOCKOUT_SECONDS = 30
92120# ─── Webhooks ────────────────────────────────────
93121WEBHOOK_MAX_ATTEMPTS = 5
94122WEBHOOK_RETRY_INTERVAL = 30s
@@ -101,6 +129,12 @@ WEBHOOK_HTTP_TIMEOUT=10s
101129WEBHOOK_ALLOW_PRIVATE = false
102130
103131# ─── Quotas ──────────────────────────────────────
132+ # catalog: app.quota_warning_threshold — quota usage (basis points,
133+ # 10000 = 100%) that triggers the quota-warning email. This bps form
134+ # is canonical and wins at boot.
135+ QUOTA_WARNING_THRESHOLD_BPS = 8000
136+ # Legacy float fraction form (0.8 = 80%), read only when the bps form
137+ # is unset. Kept for installs that predate config-in-DB.
104138QUOTA_WARNING_THRESHOLD = 0.8
105139
106140# ─── Admin Bootstrap ─────────────────────────────
@@ -130,11 +164,50 @@ STORAGE_DOWNLOAD_TTL=10m
130164# Lifetime of artifact URLs inside public update feeds (Sparkle/Velopack/Tauri).
131165# Users may click Install long after the feed was fetched.
132166STORAGE_FEED_URL_TTL = 24h
167+ # Largest artifact (MB) the server will sign in-memory (Ed25519).
168+ MAX_RELEASE_SIGN_SIZE_MB = 500
133169
134- # Master key that encrypts secrets at rest: release-signing keys, email
135- # provider credentials and license keys. Required when release storage
136- # is enabled; recommended in any production install.
137- # Generate with: openssl rand -hex 32
138- # Keep it safe and stable: losing or changing it makes existing signing
139- # keys undecryptable, and signing then fails.
140- RELEASE_KEY_ENCRYPTION_KEY =
170+ # ─── Domains / surfaces (the 5-domain split + extras) ───
171+ # catalog: domain.* — hostname map for surface routing. When unset the
172+ # install is single-host (no enforcement). domain.base derives the
173+ # standard set: payments./dashboard./merchant./customer./verify.
174+ # DOMAIN_BASE=example.com
175+ # Per-host overrides (win over the derived names) + optional extras:
176+ # DOMAIN_APEX=example.com
177+ # DOMAIN_PAYMENTS=payments.example.com
178+ # DOMAIN_DASHBOARD=dashboard.example.com
179+ # DOMAIN_MERCHANT=merchant.example.com
180+ # DOMAIN_CUSTOMER=customer.example.com
181+ # DOMAIN_VERIFY=verify.example.com
182+ # DOMAIN_HOOKS=hooks.example.com
183+ # DOMAIN_DOCS=docs.example.com
184+ # DOMAIN_STATUS=status.example.com
185+ # DOMAIN_GO=go.example.com
186+ # DOMAIN_AUTH=auth.example.com
187+ # DOMAIN_CDN=cdn.example.com
188+ # catalog: session_cookie_domain — lets the session cookie roam the
189+ # site's subdomains (e.g. example.com). Unset = host-only cookies.
190+ # SESSION_COOKIE_DOMAIN=example.com
191+
192+ # ─── Data retention (days; plan §92) ────────────────────
193+ # catalog: retention.* — batched pruning of non-financial rows.
194+ # Financial records (orders, invoices, refunds, audit) are never pruned.
195+ RETENTION_NOTIFICATIONS_DAYS = 90
196+ RETENTION_PROCESSED_EVENTS_DAYS = 30
197+ RETENTION_WEBHOOK_DELIVERIES_DAYS = 90
198+ RETENTION_AUDIT_LOGS_DAYS = 365
199+
200+ # ─── Observability ─────────────────────────────────────────
201+ # catalog: observability.log_level — slog level of the JSON stdout
202+ # stream: debug | info | warn | error.
203+ LOG_LEVEL = info
204+
205+ # ─── Branding ────────────────────────────────────────────
206+ # catalog: site_name / timezone / brand_color / language / logo_url.
207+ # NOTE: the "Powered by Keygate" attribution notice is a license
208+ # obligation (AGPL v3 Section 7(b)) and is NOT configurable here.
209+ SITE_NAME = HiTechCloud
210+ TIMEZONE = UTC
211+ BRAND_COLOR = #2563eb
212+ LANGUAGE = en
213+ LOGO_URL =
0 commit comments