Skip to main content

Operations and configuration

This page is the cross-service operating guide. Component pages explain feature behavior; this page explains how the deployed parts discover one another, which dependencies are hard requirements, where state lives, and how to investigate failures.

Deployment shape

All four application repositories provide container definitions. In the hosted layout, Traefik terminates TLS and routes host names to the frontend, Trader-BE, News-Analyzer, and LLM-Wrapper. Trader-BE may also sit behind its own Nginx response cache. Containers join the shared deployment network and address one another by service name in development or by HTTPS host in production.

Port numbers describe the process inside its container. A host, compose, or Traefik port can differ. In particular, News-Analyzer listens on 8080 in its current application configuration while older documentation and some deployment naming refer to 8087. Service discovery should use the actual container listener and router configuration, not an old diagram.

Dependency matrix

ComponentHard dependency for startupOptional or degradable dependency
Trader-FE browserStatic assets and reachable BFF for API workIndividual page APIs can fail independently
Trader-FE BFFListener and configured Trader-BE upstreamNo database or cache of its own
Trader-BERedisPostgreSQL can fall back in memory; provider and PayOS keys affect their features
News-AnalyzerRedis for normal context and stage operation, reachable LLM-Wrapper for model stagesPostgreSQL and individual data-provider keys can degrade coverage
LLM-WrapperReadable model file and at least one Gemini keyAdditional keys improve rate-limit capacity

Production should not intentionally use Trader-BE’s database-free mode. It loses balances, settings, packs, purchases, and history on restart and cannot provide reliable payment behavior.

Service discovery

The browser uses same-origin /api addresses. The production frontend server forwards those requests to the Rust BFF. The BFF forwards to Trader-BE using its configured upstream address.

Trader-BE uses SENTINEL_URL for authentication. For News-Analyzer it uses the internal service address in development and constructs an HTTPS host from DOMAIN_NAME outside development. News-Analyzer uses LLM_WRAPPER_URL. PostgreSQL and Redis use their connection URLs.

Check all of these from inside the calling container. A host-reachable URL can still be unreachable on the container network, and localhost inside a container refers to that container itself.

Secret and configuration ownership

Secret or settingConsumed byPurpose
FINAI_JWT_SECRETTrader-BE and the token issuerLocal verification of protected requests
NEWS_API_KEYNews-AnalyzerNewsAPI article coverage
FINNHUB_API_KEYNews-Analyzer and optionally Trader-BENews, fundamentals, and enrichment
Gemini key fileLLM-WrapperGoogle model access and rotation
PAYOS_CLIENT_ID, PAYOS_API_KEY, PAYOS_CHECKSUM_KEYTrader-BECheckout, status, signatures, and webhook handling
PostgreSQL URLsTrader-BE and News-AnalyzerDurable application and analyzer data
REDIS_URLTrader-BE and News-AnalyzerShared caches and temporary contexts

Secrets must be injected at deployment and excluded from images, repositories, logs, browser bundles, and documentation. The Gemini key file is mounted into LLM-Wrapper. Browser runtime configuration must contain only public values.

Database migrations

Trader-BE runs its SQL migrations when a PostgreSQL pool is established. The migrations create and evolve users and credits, analysis history, purchases, payment transactions, credit packs, roles, recent searches, popularity, settings, runtime cache settings, analysis summaries, overview payloads, and the link to News-Analyzer runs.

News-Analyzer migrations create historical market tables, ingestion-job coordination, analysis runs, and stage outputs. Migration permissions are therefore required for the service account during startup unless the deployment applies migrations separately.

Before rollback, verify whether the previous application version can read the newer schema. Database backups are more important than Redis backups because caches can be reconstructed while payment and history rows cannot.

Redis ownership and invalidation

Both Rust services can share a Redis deployment because their key prefixes distinguish domains. Market profiles intentionally use the shared profile: concept so a profile collected by News-Analyzer can serve Trader-BE enrichment.

Do not flush production Redis casually. A flush removes more than price acceleration: it also removes one-hour interactive analysis contexts and may force expensive fact, claim, and stage regeneration. It does not remove durable analysis runs or Trader-BE history.

When prompts, schemas, or calculation semantics change, increment the relevant cache version or version field. Time-to-live expiration alone can leave old semantic output visible for its entire lifetime.

Health and readiness

Process health endpoints show that the HTTP server is accepting requests. They do not prove every dependency works. A useful readiness suite checks Trader-BE health, a public price or asset request, Redis connectivity, PostgreSQL mode, News-Analyzer health, LLM-Wrapper model listing, and a small controlled structured model call.

Payment readiness additionally requires PayOS credentials, a public HTTPS webhook, correct signature handling, and a test transaction in the gateway environment. Historical-analysis readiness requires analyzer database connectivity and populated price history.

Logging and correlation

Trader-BE and News-Analyzer use structured tracing and include request middleware. LLM-Wrapper uses Go request and retry logs. The edge proxy and BFF should preserve or create a request identifier and forward it downstream.

For one failed analysis, collect the browser time and symbol, BFF status, Trader-BE request identifier and credit transaction, News-Analyzer context or run identifier, LLM model and retry outcome, and the final database state. This distinguishes a browser timeout from an upstream failure and a failed analysis from an analysis that completed after the browser disconnected.

Never log bearer tokens, refresh tokens, Gemini keys, PayOS checksum secrets, or full payment payloads containing sensitive details. Prompt logging should be disabled or redacted in production because collected articles and user-selected data flow through prompts.

Common investigations

The UI receives 401 repeatedly

Verify the access token is attached, the frontend has exactly one refresh in progress, the refresh contract uses the expected field names, Sentinel is reachable through Trader-BE, and FINAI_JWT_SECRET matches the issuer. A stale role in local storage affects display, but Trader-BE’s token claim decides authorization.

A user was charged but saw no result

Locate the negative credit transaction and its request identifier. Check whether News-Analyzer completed and persisted a run after the frontend’s five-minute timeout. Check Trader-BE history and analysis cache. The current system refunds only completed results below 0.25 confidence, not every downstream failure, so manual reconciliation may be required.

Supporting tabs fail after the overview works

Confirm the frontend retained the initialization context identifier rather than sending the analysis-run or history UUID. Check whether more than one hour elapsed or Redis was cleared. Start a new initialization when the context is gone.

Results look stale

Inspect browser page-local tab memory, Nginx response cache, Trader-BE Redis, News-Analyzer profile and stage caches, and runtime cache settings. Each layer has a different lifetime. Confirm the cache key includes the requested symbol, lookback, interval, range, and prompt or schema version where relevant.

News or fundamentals are thin

Check provider credentials and rate limits, symbol resolution, asset type, source filtering, extraction warnings, and provider-specific availability. Thin evidence should lower confidence and populate unavailable fields rather than be hidden.

Model calls fail intermittently

Inspect the requested model, local model configuration, key rotation logs, 429 exclusions, temporary Google server failures, and all-key exhaustion. A configured model can be unavailable to the Google project even though it appears in /v1/models.

Release verification

For every coordinated release, verify anonymous search, asset detail, prices, chart history, and news preview; registration, login, refresh, Google login where configured, and logout; analysis initialization and one paid overview; all five supporting tabs; low-balance 402 behavior; low-confidence refund behavior in a controlled test; history ownership and deletion; settings persistence; active pack listing and a gateway test payment; admin denial and admin workflows; English and Vietnamese rendering; service restart with persistent state; and a multi-replica preview refresh without duplicate work.

API-contract changes should be released from downstream to upstream when compatibility requires it: make the receiving service accept both forms, update the caller, then remove the old form in a later release.