Explorer deployment
Bringing up the Explorer's own infrastructure and the ownership rule that governs its two databases.
This page covers the Explorer's own infrastructure: the database and search
index it needs, the order to bring them up in, and a warning worth reading
before the first docker compose up. It does not cover the oracle; the
Explorer reaches the oracle as a black box, over HTTP, and adds nothing to it.
Topology
The Explorer is one Next.js application, backed by a Postgres database and an Elasticsearch index, calling the oracle over HTTP. Four pieces, three of which the Explorer owns:
- Next.js application: the pages, API routes, and the process that talks to the other three.
- Postgres: the Explorer's own database, source of truth for everything it records.
- Elasticsearch: a search index over the same records, owned by the Explorer, rebuildable from Postgres.
- The oracle: reached at
ORACLE_URL, treated as a black box. The Explorer does not modify it, extend it, or add state to it; it only calls its HTTP endpoints and records what came back.
Environment variables
Three variables configure the Explorer, all read from .env.local:
ORACLE_URL: the oracle's HTTP address, for examplehttp://127.0.0.1:8080. The Explorer calls this and nothing else to reach the network.DATABASE_URL: the Postgres connection string, for examplepostgres://explorer:explorer@127.0.0.1:5432/explorer.ELASTICSEARCH_URL: the Elasticsearch address, for examplehttp://127.0.0.1:9200.
Bring-up order
Three steps, run in this order. Each corresponds to a script in the Explorer's
package.json.
-
Start the infrastructure.
pnpm infraRuns
docker compose up -d. Before running this, read the warning below; it concerns exactly this step. -
Run the database migration.
pnpm db:migrateApplies every
.sqlfile undermigrations/, in sorted order, againstDATABASE_URL. This has to succeed before the application can write a single record. -
Initialise the search index.
pnpm es:initCreates the Elasticsearch index with its mapping if it does not already exist, and does nothing if it does. Safe to run more than once.
With the infrastructure up, the schema applied, and the index created, the
application itself starts the same way any Next.js app does: pnpm dev for
local development, or pnpm build followed by pnpm start for a production
run.
Ownership: which database is truth
This is the one rule an operator must not get wrong.
Postgres is the source of truth. Elasticsearch is a rebuildable view of it, not a second source. Every write goes to Postgres first; only after a record is committed there does the Explorer index it into Elasticsearch, and that indexing step is best effort. A failed or delayed index does not lose a visitor's answer, because the record it describes already exists in Postgres.
The consequence follows directly: if the Elasticsearch index drifts from Postgres, or is lost outright, it is rebuilt from Postgres. The reverse never happens. Nothing is recovered from Elasticsearch into Postgres, and no visitor-facing data is allowed to live only in the index. If a page depends on data that exists solely in Elasticsearch, that is a defect to fix, not a tradeoff to document.
Warning: check the port before starting the infrastructure
The Explorer's docker-compose.yml defines Elasticsearch only, and it is
worth knowing why.
A Postgres service used to be defined there as well. It bound port 5432, the
same port a native Postgres instance on the same machine was already using.
Bringing the compose stack up did not fail or warn; it simply shadowed the
real database. Migrations and application writes went into the container's
volume, while every other process on the machine kept talking to the native
instance. Both were named explorer. Both looked correct in isolation. They
diverged silently, and nothing about the setup surfaced the problem until the
two were compared directly.
The Postgres service was removed from the compose file for this reason;
Postgres on this machine runs natively, and DATABASE_URL in .env.local
points at it directly. The lesson generalises beyond this one file: before
running pnpm infra, check what is already listening on the ports the
compose file will bind. A container that starts cleanly is not evidence that
it is the only thing there.
Status
The Explorer has not yet been run end to end against live services. Treat this page as a deployment design, written from the application's source, configuration, and design document, rather than a runbook that has been exercised in production.