Skip to content

Operations

Railway operation and deploy

Status: destination confirmed; topology and configurations below proposed. No Railway service was created at this stage.

Publication update: project provisioned, services created and web online. Destinations, domain and effective configuration are in the checklist and ADR-0014. The historical text below does not describe the current state and should not guide variable configurations.

Implementation update: see the ROADMAP, ADR-0011, ADR-0012 and ADR-0013 for the effective state. The text below preserves the original requirements/designs, not a statement that all infrastructure or external validation details have already occurred.

Status: destination confirmed; topology and configurations below proposed. No Railway service was created at this stage.

Initial topology#

ServiceProcessExposure
webCurrent Vukem binary, /app/appPublic HTTPS; authenticated pages and APIs
engineFuture binary /app/engineNo public domain; connection to broker/feed
PostgreSQLPersistent servicePrivate network between services
backtestSeparate job/process if neededNo resource contention with execution

Keep the engine continuously active and disable hibernation/serverless on it. Initially one replica; locks and fencing remain necessary during rolling deploy. Do not scale the executor by simply changing replica counts. Additional cache/broker components are added only via ADR. Confirm region, plan, CPU/RAM, budget and backup before deploy, without assuming TimescaleDB is available.

Build and commands#

The current Dockerfile only compiles cmd/app; creating cmd/engine requires changing the build and image. Do not configure a non-existent start command. The web listens on 0.0.0.0:$PORT; Vite assets are embedded. Keep an unprivileged user.

Proposed pre-deploy: /app/app migrate. Migrations must be compatible with the old version during overlap and use serialization/lock. Expand the schema, publish consumers and only then remove fields. Migration failure blocks promotion. Do not run destructive migrations at the boot of each worker.

On Railway, a Docker start command overrides ENTRYPOINT; provide the full executable. Validate the configuration in staging, without assuming shell expansion. Record one configuration per service when implemented.

Proposed variables#

ServiceVariablesNote
webAPP_ENV, APP_DEBUG, APP_URL, HOST, PORTproduction, debug off, canonical HTTPS URL
webAPP_KEY, DATABASE_URLRailway secrets; persistent key across deploys
webSOCIAL_GOOGLE_CLIENT_ID, SOCIAL_GOOGLE_CLIENT_SECRETExisting names from the Vukem scaffold
webCACHE_STORE, SESSION_DRIVERDefine shared storage and migrations
engineDATABASE_URL, TRADING_MODETRADING_MODE is a proposed new contract
engineBROKER_API_KEY, BROKER_API_SECRETProposed generic names; paper only in the recommended scope
engineBROKER_BASE_URL, MARKET_DATA_FEEDValidated against the adapter/mode allowlist
engineENGINE_ACCOUNT_IDProposed new configuration, leadership scope
alertsTELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_IDOptional, after choosing the channel

Authorized user IDs and limits will be defined after Q1. Do not send secrets to Inertia props, Vite bundle, logs or documents. The Google callback must match the registered URI, including protocol, domain and path. Login does not require permanent Google access tokens if no Google API will be used.

Health, telemetry and recovery#

/up exists in the starter as liveness; do not expose balances or configurations there. Propose /ready for the web/dependencies. Railway uses healthcheck for deploy; continuous monitoring needs its own tool/alerts. The worker reports heartbeat in the database and internal readiness; it does not depend on public access to the endpoint.

Metrics: age of the last candle, feed delay, processing, broker latency, unknown intents, divergences, risk reservations, heartbeat, queue/outbox, login failures and connections. Structured logs with request/event/order IDs; redact tokens, headers and personal profiles. Retention and targets still pending.

Incident runbook: persist the account block → confirm new entries are blocked → query broker state → cancel according to policy → reconcile → verify positions and exposure → record the cause → resume explicitly. Closing all positions is a separate operation, subject to market/limits; failure or lack of connectivity must appear as pending, never as confirmation of flat.

Restart runbook: acquire leadership → load blocks/versions → reconcile orders and fills → rebuild exposure → validate feed/calendar → enable only if the policy allows. Restore is done in an isolated environment without execution enabled; reconcile against the broker before any resumption. Define RPO/RTO and rehearse the restore; a persistent volume alone is not a backup strategy.

Code rollback does not revert fills or cancel orders. Avoid downgrading the financial schema. The worker must react to SIGTERM by stopping new entries, preserving intents and finalizing a checkpoint; the broker remains the source of confirmation.

The pre-deploy runs in a separate container, with variables and private network, but without mounted volumes. Do not depend on disk writes at this stage. The absence of sticky sessions in the distribution of replicas reinforces shared sessions and states.

Adjustment after round 2#

US: secrets exclusive to Alpaca Paper and an allowlist of the paper host. B3: internal adapter without external order credentials. Web: OWNER_GOOGLE_EMAIL is a proposed configuration for the initial gate of the only authorized account. Once bound, the persisted Google identity prevails; recovery must be audited.