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.
Access and local setup
Section titled “Access and local setup”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:
bun install --frozen-lockfilebun run --cwd apps/web dev --host 127.0.0.1The 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:
bunx wrangler secret put ADMIN_TOKENDo 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.
API and operational meaning
Section titled “API and operational meaning”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:
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-settingsHTTP 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:
bun run --cwd apps/service db:migrations:localFor the existing remote D1 database, only after explicit authorization:
bunx wrangler d1 migrations apply geonames-global --remote --config apps/service/wrangler.jsoncApply 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: nullandserviceError; benchmark and limitations remain available. This is not a claim of service health. -
D1 query failures: nullable metrics plus named
database.errorsand degraded status, rather than invented zero counts. -
Service/release status comes from the actual Service Binding and
CF_VERSION_METADATA.developmentmeans local runtime, not a deployed release.production-buildidentifies 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 throughlocations_fts_docsizeand compared with location count. -
Dataset version is a SHA-256 fingerprint of sorted
seed_chunksmarkers, 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:verifyintegrity/index/trigger checks. -
Incremental updates explicitly report not configured and no last run. No updater, scheduling, or ingestion control is implemented.
Observability setup
Section titled “Observability setup”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.
Deployment order and commands
Section titled “Deployment order and commands”From the repository root, and only after explicit approval of the exact external changes:
bunx wrangler d1 migrations apply DB --remote --config apps/service/wrangler.jsoncbun run --cwd apps/web buildbun run --cwd apps/service deploybun run --cwd apps/web deployThe 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.
Diagnostics and performance
Section titled “Diagnostics and performance”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/:
bun run admin:benchmark -- .import/benchmark-search.jsonThis 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.