Operating OpenTerminal Responsibly: Security, Deployment, and Failure Judgment

OpenTerminal is designed to make a personal market workspace easy to run, but responsible use depends on understanding two boundaries: what the local deployment protects and what a displayed value actually represents. This chapter applies the earlier source-and-transformation model to security, exposure beyond one machine, instrument identity, and the common symptoms of missing, stale, or partial data. The goal is practical judgment: before relying on a panel, the operator should be able to identify the request's instrument, route, freshness, completeness, and intended use.

A local-first application can feel deceptively simple. The user clones the project, starts the web and API processes, and sees a terminal-like screen. That simplicity is valuable, but it can conceal decisions that become important as soon as the application is shared, placed behind a proxy, or used to support a financial conclusion. OpenTerminal's defaults narrow the initial risk. They do not remove the operator's responsibility to understand what changes when the boundary moves.

The safe local boundary is narrow by design

The API binds to 127.0.0.1 by default. In plain terms, it listens only on the machine running it, rather than advertising an API to every device on the local network. The browser origin is restricted to the configured web application, which defaults to http://localhost:3000. Together, those choices support the project's intended local workflow: the web interface can call the API on the same machine, while an unrelated website or another computer cannot casually treat the API as an open service.

The protection is layered but limited. Market routes are available through the API's general path, while portfolio and AI routes require an X-Api-Key header. If an operator does not set API_KEY, the server generates a random shared secret, writes it to data/.api-key with restrictive file permissions, and the bundled web process reads that file on the server side. The result is a zero-configuration local setup in which the browser does not need to know the secret directly.

This is a credential boundary, not a user-account boundary. Everyone who can use the shared key is equivalent to the API. There is no evidence here of per-user identities, roles, permission scopes, or an audit log. That is a reasonable fit for a private single-user workspace, where the main threat is accidental exposure of a locally running service. It would be an insufficient description of security for a public multi-user application.

The Docker configuration follows the same principle. Both web and API ports are published on 127.0.0.1 by default. The data volume persists SQLite records, while the web container mounts the shared data directory read-only so it can obtain the generated key without owning the database. This arrangement lets the API write portfolio data and the web service read the credential it needs, while preserving the local-only network posture.

The posture changes as soon as the operator wants access from another machine. The API must be deliberately bound more widely, the shared key should be set explicitly for both processes, and the allowed web origin must match the real origin rather than the localhost default. Those settings are not cosmetic.