Skip to main content

Configuration

All runtime configuration comes from environment variables. Docker Compose reads them from a local .env file.

Never commit secrets

.env is git-ignored and must stay that way — it holds JWT_SECRET, CONFIG_ENCRYPTION_KEY, SMTP and payment credentials. API responses never echo secrets back (a stored secret is reported as a has_secret boolean).

Required​

VarNotes
DATABASE_URLPostgres DSN. Boot fails without it.
JWT_SECRETHMAC signing key for all session tokens and capability URLs. 32+ characters in production.
CONFIG_ENCRYPTION_KEYSeals tenant credentials at rest. Required in production and must differ from JWT_SECRET.
SUPERADMIN_EMAIL / SUPERADMIN_PASSWORDThe platform superadmin created by the seed. Production requires a strong password (12+ characters, no defaults).

Core​

VarDefaultNotes
HTTP_PORT8080API listen port.
ENVdevelopmentproduction switches logs to JSON and turns on the production guards.
LOG_LEVELinfodebug / info / warn / error.
JWT_TTL24hStaff and vendor token lifetime.
STOREFRONT_SESSION_TTL720hBuyer session lifetime. Active buyers slide it forward via POST /storefront/auth/refresh, so only 30 days of inactivity signs them out.
PLATFORM_BASE_DOMAINsokisoko.localThe platform's own domain; tenant storefronts live on their own domains or under this one.
ADMIN_APP_URLhttp://localhost:5173Where invite and reset emails send staff.
VENDOR_PORTAL_URLhttp://localhost:5174Where vendor invites send applicants.
SIGNUP_VERIFY_URLhttp://localhost:5173/verify-signupSelf-serve organization signup verification link.
SEED_DEMOoffCreates demo logins and data. Must be off in production.

Database pool​

VarDefault
DB_MAX_CONNS20
DB_MAX_CONN_IDLE_TIME5m

PDF & email​

VarDefaultNotes
GOTENBERG_URL(empty)Empty → stub PDF renderer.
MAILGUN_API_KEY / MAILGUN_DOMAIN—Both set → Mailgun HTTPS API transport (preferred).
MAILGUN_BASE_URLhttps://api.mailgun.netUse https://api.eu.mailgun.net for EU domains.
SMTP_HOST / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD— / 587 / — / —SMTP fallback, used only when Mailgun is unset. Neither set → log transport (emails printed, not sent).
EMAIL_FROMSokisoko <no-reply@sokisoko.local>Platform sender identity.
PLATFORM_LEADS_EMAIL(empty)Where enquiries from the platform site are mailed.

Transport order: Mailgun API → SMTP → log. These are the platform defaults; each tenant can set its own sender identity and bring its own mailbox or Mailgun account from Admin → Settings → Configuration, in which case the worker sends through the tenant's account.

Storage, payments, procurement​

VarDefaultNotes
MEDIA_ROOT/data/mediaBlob directory for uploads; a shared volume in multi-node deploys.
PAYMENTS_GATEWAYmockmock, or a real provider; STRIPE_SECRET_KEY for Stripe.
PAYOUT_PROVIDERmanualHow marketplace payouts are disbursed.
PUNCHOUT_STOREFRONT_URL/Landing URL after a punchout session starts.
PUNCHOUT_TTL1hPunchout session lifetime.
EDI_SENDER_IDSOKISOKOOur identity on outbound X12 documents.

ERP providers (platform app credentials)​

Only the OAuth-based providers need anything here; a provider without credentials is shown in the admin catalog but cannot be connected.

VarProvider
QBO_CLIENT_ID / QBO_CLIENT_SECRET / QBO_REDIRECT_URI / QBO_ENVIRONMENT (sandbox) / QBO_WEBHOOK_VERIFIER_TOKENQuickBooks Online
XERO_CLIENT_ID / XERO_CLIENT_SECRET / XERO_REDIRECT_URI / XERO_WEBHOOK_KEYXero
BC_CLIENT_ID / BC_CLIENT_SECRETMicrosoft Dynamics 365 Business Central

AI​

VarDefaultNotes
AI_PROVIDERdeterministicNarrator/designer provider; deterministic needs no key and is always the fallback.
ANTHROPIC_API_KEY / AI_MODEL— / claude-opus-4-8Anthropic provider.
AI_CHAT_BASE_URL / AI_CHAT_API_KEY / AI_CHAT_MODELGroq OpenAI-compatible endpoint / — / openai/gpt-oss-120bThe assistant's chat model.
AI_FALLBACK_BASE_URL / AI_FALLBACK_API_KEY / AI_FALLBACK_MODELOpenRouter / — / —Used when the chat provider fails.
AI_WRITER_MODEL / AI_DESIGNER_MODEL(empty)Override models for copywriting and page design.
ASSISTANT_INTERNAL_URLhttp://api:8080Loopback the assistant uses to execute actions through the real routes.

Agent API, realtime, push​

VarNotes
API_PUBLIC_URLThe public URL clients dial for the API (e.g. https://api.example.com). Unset → the OAuth 2.1 server and MCP endpoint are not mounted. Must equal the issuer clients see.
SITE_PUBLIC_URLThe platform site URL advertised in agent metadata.
MCP_RESOURCE_ORIGINSExtra origins allowed to present as the MCP resource.
PUSHER_APP_ID / PUSHER_KEY / PUSHER_SECRET / PUSHER_CLUSTERLive updates in the apps (optional; polling otherwise).
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECTWeb push for buyer message alerts.

Observability​

Metrics are opt-in: set OTEL_EXPORTER_OTLP_ENDPOINT and the API exports via OTLP (database-pool gauges and HTTP metrics). Unset → no exporter, zero overhead.

Search engines: Google Search Console​

Google verifies a storefront domain by fetching /google<token>.html. Put the 16-character token from Search Console's "HTML file" method into the tenant's seo.google_site_verification setting (org scope); the storefront then serves https://<store>/google<token>.html with the body Google expects. Tenants without the setting keep answering 404 there. Bing uses the same pattern through seo.bing_verification and /BingSiteAuth.xml.

Search engines: IndexNow​

Every tenant storefront tells Bing, Yandex and the engines built on them which URLs changed, through IndexNow. Nothing to configure: a key is generated into the seo.indexnow_key setting the first time a store submits, and the storefront serves it at /{key}.txt as the ownership proof.

What submits, and when:

  • Product changes from every writer — an ERP sync (push or poll), AI description drafting, the spec backfill, and product edits in the console. Writers send product ids; the indexnow_submit job resolves them to /p/{slug} and posts once per batch.
  • Category create, rename (old and new slug) and delete → /c/{slug}.
  • Page publish and withdraw → /{slug}.
  • Nightly sweep (indexnow_sweep, 03:00 UTC) — every product, category, page and facet landing that changed since the last sweep, straight from the same listings the sitemap serves. This is the net under the per-write pings.

Submissions are skipped for localhost and unverified hosts, and never fail the write that triggered them. The landing site (a static build) is submitted by the landing deploy role after each publish, using landing_indexnow_key and landing_indexnow_host from the deploy variables; the key file lives in web/landing/public/.