Docs

What you are actually running

Armory is a single deployable that serves a React client and an Express server from the production build. TypeScript compiles on the server side; Vite bundles the client. Persistence is SQLite via better-sqlite3, with WAL enabled for the main Armory database and for the Codex export mirror.

That sounds boring until you realize the payoff: no separate “API server” and “frontend host” unless you decide to split them behind a reverse proxy. For a small team, that simplicity is a feature.

Three databases, one story

In a typical production layout you will hear people refer to three SQLite files:

  1. Armory application database - mods, weapons, warframes, user builds, loadouts, and the rest of the planner domain.
  2. Central database - shared with Auth: users, sessions, and which apps a user may access. Armory opens this file read/write according to the same deployment conventions as the other apps (see your .env and ops runbook).
  3. Codex export database - a mirror shaped for Codex imports. Armory creates the schema and fills rows as part of its data pipeline; Codex reads it as a downstream consumer.

If you are sketching architecture for management, draw three boxes and label them “planner,” “identity,” and “handoff.” The arrows are more important than the filenames.

Data freshness: imports without drama

Game data arrives from DE’s export, with selective enrichment from wiki and related sources. Operators run the manual import path when it is time to refresh:

pnpm run build 
 pnpm run data:import


The import job is intentionally manual in spirit: it is the moment you accept “today we trust this snapshot.” Automating that is possible, but automation without observability is how silent drift happens.

Authentication: redirect, then resume

Armory delegates identity to the central Auth service. In practice the browser visits Auth’s login route with a next parameter that points back to a path on Armory’s public base URL. After a successful login, the user should land where they intended - often deep in the builder - without Armory re-implementing password flows.

Production requires a real APP_PUBLIC_BASE_URL and a production-grade AUTH_SERVICE_URL (HTTPS). If those are missing or mis-set, you will see the kind of failure that looks like “the SPA loaded but nothing works” - which is correct behaviour for a misconfigured trust boundary.

Helminth and the long tail of “special” data

Some systems in Warframe do not serialize as neatly as a table of mods. Helminth-related wiki fetches are isolated behind configuration (including an optional User-Agent) so polite crawling stays polite. If you are extending Armory, treat anything that touches external HTML as guarded IO: timeouts, caching where sensible, and logs that tell you which upstream failed.

Builds, sharing, and the social layer

User-created builds and loadouts live in the Armory schema with visibility flags and optional share tokens. The product goal is pragmatic: let people save work, revisit it, and share a link without standing up a separate “content platform.” From an engineering perspective, that means careful validation of serialized mod configuration JSON and conservative defaults for anything public-facing.

Operating checklist

  • Confirm TLS end-to-end in production; set TRUST_PROXY when TLS terminates upstream.
  • Treat SESSION_SECRET as a rotation candidate, not a tattoo.
  • Keep Codex export paths consistent across the machines that run Armory and Codex if they share a volume.
  • Run pnpm run validate before tagging a release; it is the honest “does CI agree with my laptop?” button.