Skip to content

Documentation

Admin settings and operational status

The admin workspace uses separate pages for protected search-scope settings and operational status. Settings can be changed; operational metrics, diagnostics, provenance, and saved benchmarks remain read-only. Public search routes remain unauthenticated.

Page Route Contents
Overview /admin Service/release, database and dataset, cache/lifecycle, known limitations
Search settings /admin/settings Default country, country-first search, global fallback
Diagnostics /admin/diagnostics Recent requests and performance cohorts
Benchmarks /admin/benchmarks Saved baseline and cache-cohort filter

Navigation between these pages shares the current in-memory login and snapshot without automatic refresh or settings writes. Direct links are supported. A successfully authenticated token is retained in tab-local sessionStorage and restored to the input after reload or returning to admin. The snapshot is not persisted: click Connect to fetch it again. Unknown admin paths return to Overview.

The web Worker requires ADMIN_TOKEN. The page sends it in Authorization: Bearer <token> to GET /api/admin. Only a successfully authenticated token is saved under geonames.adminToken in sessionStorage; input edits alone do not overwrite it. No token is stored in cookies, localStorage, or URL parameters. Disconnect and HTTP 401 clear both stored and in-memory credentials and the loaded snapshot. If browser storage is unavailable, the page continues with memory-only credentials. Connect and Refresh remain explicit; there is no automatic fetch or polling.

Session storage is readable by same-origin JavaScript and normally ends when the tab closes. It is not an XSS protection boundary. Use HTTPS outside loopback and share the token only with operators. A shared bearer token does not provide individual accounts or an audit trail.

For local development, create the ignored apps/web/.dev.vars with a strong, independently generated value:

ADMIN_TOKEN=<your-local-admin-token>

From the repository root:

Terminal window
bun install --frozen-lockfile
bun run --cwd apps/web dev --host 127.0.0.1

The deployed admin workspace is at https://geonames-global-demo.vimaksh.workers.dev/admin and requires the production admin token. For local development, open /admin on the demo’s port 3000 and enter the local token. Local metrics require the existing populated D1 state in apps/service/.wrangler/global-state; this feature neither imports nor changes data. A separate worktree needs its own consistent SQLite copy, not a shared live database file.

Production configuration and deployment are user-run. From apps/web/, the following stores a secret on the existing geonames-global-demo Worker; it changes hosted configuration and must not be executed by an agent without authorization:

Terminal window
bunx wrangler secret put ADMIN_TOKEN

Do not put this secret in wrangler.jsonc, committed files, browser code, or deployment command-line arguments. Deploy both Workers using the repository-root MANUAL_VERIFICATION.md, section Deployment (user-run). The admin API fails closed until the secret is configured.

GET /api/admin returns the versioned AdminPayload operational snapshot. GET /api/admin/search-settings and a successful PUT /api/admin/search-settings return { "settings": SearchSettings }. All responses use Cache-Control: no-store and Vary: Authorization. Both settings routes require Authorization: Bearer <ADMIN_TOKEN>; missing configuration returns 503, missing/invalid token 401, and unsupported methods 405 with Allow.

Successful settings response:

{
"settings": {
"defaultCountryCode": "IN",
"defaultScopeEnabled": true,
"fallbackToGlobal": true
}
}

The PUT body must provide all three fields. defaultCountryCode is the country applied to otherwise-unscoped searches when defaultScopeEnabled is true. fallbackToGlobal permits a global search only after the default-country query has zero matches across the whole query. Explicit geographic and parent scopes remain strict regardless of these settings. Settings are persisted in the service D1 singleton table; the AdminServiceSnapshot includes the current searchSettings.

Examples:

Terminal window
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://geonames-global-demo.vimaksh.workers.dev/api/admin/search-settings"
curl -X PUT -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
--data '{"defaultCountryCode":"IN","defaultScopeEnabled":true,"fallbackToGlobal":true}' \
"https://geonames-global-demo.vimaksh.workers.dev/api/admin/search-settings"

These are examples only; do not run against production without explicit approval. Missing/invalid bearer tokens return 401; missing token configuration returns 503. Error response contains an error string; callers should rely on status rather than a specific message.

Authentication error examples:

GET /api/admin/search-settings

HTTP 401 Unauthorized (missing or invalid bearer token):

{"error":"A valid admin token is required."}

With no ADMIN_TOKEN configured, the same request returns HTTP 503 Service Unavailable:

{"error":"Admin access is not configured. Set ADMIN_TOKEN on the web Worker."}

These examples show the current error bodies. Callers should branch on status; all responses include Cache-Control: no-store and Vary: Authorization.

Apply apps/service/migrations/0003_search_settings.sql before deploying service code that reads the settings table. From the repository root, use the shared-persistence local migration command for local D1:

Terminal window
bun run --cwd apps/service db:migrations:local

For the existing remote D1 database, only after explicit authorization:

Terminal window
bunx wrangler d1 migrations apply geonames-global --remote --config apps/service/wrangler.jsonc

Apply the migration for the intended environment before deploying the provider, then deploy the demo consumer. Never substitute an ID copied from a different Cloudflare account.

  • Authenticated service failure in the operational snapshot: 200 with service: null and serviceError; benchmark and limitations remain available. This is not a claim of service health.

  • D1 query failures: nullable metrics plus named database.errors and degraded status, rather than invented zero counts.

  • Service/release status comes from the actual Service Binding and CF_VERSION_METADATA. development means local runtime, not a deployed release. production-build identifies a production bundle, not proof of production verification.

  • D1 size comes from real response meta.size_after, in bytes. Missing metadata remains unknown. Counts come from the named tables; FTS indexed documents are counted through locations_fts_docsize and compared with location count.

  • Dataset version is a SHA-256 fingerprint of sorted seed_chunks markers, not an official GeoNames release date or a checksum of every current database row.

  • Database counts and marker status are cached for 60 seconds per isolate, with a single in-flight collection. The collection timestamp is displayed. Search diagnostics are read fresh on every refresh.

  • Seed status compares recorded source/table row totals and FTS count parity. The existing marker schema has no application timestamp, so last applied remains not recorded. It does not replace seed:verify integrity/index/trigger checks.

  • Incremental updates explicitly report not configured and no last run. No updater, scheduling, or ingestion control is implemented.

The service and HTTP Worker can log structured outcomes to the console; optional Better Stack forwarding is prepared but not active until configured. Set BETTER_STACK_SOURCE_TOKEN as a secret and BETTER_STACK_INGEST_URL to the source’s ingest endpoint for each Worker that should forward events. The token and endpoint are pending operator provisioning; do not commit them. Forwarding is bounded and best-effort; shipping failure does not fail a request. Events must not include raw queries, aliases, authorization/header bodies, or raw error contents.

Read the Better Stack teaching guide for the architecture, field meanings, secret setup on both named Workers, deployment sequence, privacy/cost limits, and tomorrow’s delivery checks. The standalone copy is also saved in the operator’s Downloads folder.

From the repository root, and only after explicit approval of the exact external changes:

Terminal window
bunx wrangler d1 migrations apply DB --remote --config apps/service/wrangler.jsonc
bun run --cwd apps/web build
bun run --cwd apps/service deploy
bun run --cwd apps/web deploy

The migration creates the persisted settings table. Service deploy precedes the demo consumer. If Better Stack credentials are provisioned, set them with Wrangler secret/variable commands against each named Worker before deployment; no values are currently available. Admin remains read-only for operational status even though scope settings are editable.

The service retains the latest 50 searches in an in-memory ring buffer. Queries, errors, and operation details are bounded. It adds no D1/KV calls to the search path. Rows show outcome, pagination, cache state, result count, service/D1 durations, D1 query count, and operations. HTTP validation failures that never reach the service are outside this scope.

Recent performance uses nearest-rank p50/p95/p99, grouped separately by MISS/HIT/BYPASS/ERROR. Samples are current-isolate, volatile, and not fleet-wide; a restart, deployment, or another isolate can yield empty or different history. Small samples are descriptive, not SLO evidence.

The saved benchmark is an immutable summary of recorded HTTP measurements, separate from recent service diagnostics. It includes recording date, endpoint, mode, pagination, sample count, total/service/D1 p50/p95/p99, and D1 query-count range. The committed baseline has 18 cohorts: nine queries, 100 MISS and 100 HIT samples each. Its dataset fingerprint was not recorded and remains unknown. It is local evidence, not deployed latency. Checks use strict D1 p95 <50 ms and service p95 <75 ms; equality fails. No total-time or RPC target is invented.

To replace the saved summary with a real recorded run, first use the existing benchmark command. Then, from apps/service/:

Terminal window
bun run admin:benchmark -- .import/benchmark-search.json

This validates and exports the recording to src/admin/benchmark.ts; it does not run a benchmark, modify the database/cache, or deploy. Review and commit the generated snapshot with its provenance. The UI also lists source coverage, alias/fuzzy/category/ranking limitations; absent dates and unavailable metrics remain explicit.