Skip to content

Encinet/mikdata

Repository files navigation

Mik Data

Cloudflare Worker data API for MikWeb.

The Worker is published as https://data.mcmik.top/api. It forwards a small allowlisted API surface to the Minecraft data service and caches public JSON responses with the Worker Cache API. Buildings and building submissions are persisted in Worker KV. Public building reads use short-lived in-memory summary cache, Worker Cache API entries for lists/details, and a KV summary snapshot.

Public API details are documented in openapi.yaml.

Routes

Public API:

  • GET /api/players
  • GET /api/buildings
  • GET /api/buildings/:id
  • GET /api/bans
  • GET /api/announcements
  • GET /health

Admin UI and write API:

  • GET /admin
  • POST /admin/api/buildings
  • PUT /admin/api/buildings/:id
  • PATCH /admin/api/buildings/:id
  • DELETE /admin/api/buildings/:id
  • POST /admin/api/buildings/import
  • GET /admin/api/building-submissions
  • POST /admin/api/building-submissions/repair-approved
  • PUT /admin/api/building-submissions/:id
  • PUT /admin/api/building-submissions/:id/approve
  • PUT /admin/api/building-submissions/:id/reject

Authenticated MikWeb account API:

  • POST /api/account/building-submissions
  • POST /api/account/building-submissions/mine
  • POST /api/account/players/resolve

Security Model

  • No arbitrary proxying. Every public route is allowlisted in src/index.ts.
  • Public API routes only accept GET and OPTIONS.
  • Buildings read routes are public GET routes.
  • Public API routes allow browser requests from any origin.
  • Admin routes live under /admin* and require Cloudflare Access. The Worker validates the Access JWT issuer and AUD before serving any /admin* response.
  • Buildings write routes reject cross-site browser requests and do not expose CORS preflight headers.
  • /admin/api is not listed in openapi.yaml. Treat it as an operational interface, not as a public API contract.
  • workers_dev is disabled so the Worker is intended to be reached through the configured custom domain only.
  • Upstream responses must be successful JSON before being persisted.
  • Buildings and building submissions are stored in BUILDINGS_KV; there is no active building Durable Object binding.
  • Auth and admin JSON request bodies are read with a 64KB streaming limit before parsing.
  • Public building reads use layered cache: bounded in-isolate memory, Worker Cache API JSON entries for list/detail responses, and the authoritative building-summary:v1 KV snapshot. Filtered building-list cache keys include a hash of the current summary ids and updatedAt values, so readers that observe a newer summary stop hitting older filtered list entries.
  • Building records entering summary or cache must match the current building schema; malformed old records are ignored instead of being cached.
  • Admin building reads and building mutation checks read the KV summary snapshot directly so management views and duplicate checks are not served from stale public caches.
  • Admin building mutations are serialized through the global AuthStore Durable Object before touching KV. Buildings and submissions remain stored only in BUILDINGS_KV; the Durable Object is only a write coordinator so concurrent admins do not overwrite building-summary:v1 with stale read-modify-write results.
  • After a coordinated admin mutation succeeds, the front Worker refreshes its local building summary cache from KV so the isolate that handled the write does not keep serving a stale public summary.
  • Normal building create, update, delete, import, and submission approval paths update building-summary:v1 incrementally from the KV summary snapshot. Full building:* scans are reserved for missing-summary fallback and explicit repair operations.
  • Runtime hot paths use bounded TTL memory caches to reduce KV, Durable Object storage, and plugin request volume. These caches are deliberately small and expire quickly so they protect free-tier limits without becoming durable state.
  • Building mutations write audit logs with action, building id, and Cloudflare Access identity. Payloads are not logged.
  • Building image URLs must be relative paths or https:// URLs.
  • Player building submissions must come from authenticated MikWeb member accounts and use ImgBB WebP image URLs generated by MikWeb.
  • Submission listing uses secondary KV indexes: building-submission-player-pending:{uuid}:* for per-player pending limits and building-submission-status:{status}:* for admin submission lists. Pending limits count the pending index first and only read submission documents when the player is already at the limit. Submission creation is queued per player inside AuthStore so concurrent browser requests cannot pass the pending limit together. Do not remove these indexes without rebuilding them from submission documents.
  • POST /admin/api/building-submissions/repair-approved is an admin maintenance action. It scans old approved submissions, restores missing building:{id} records when needed, links duplicate existing buildings, deletes repaired approved submission records and stale approved indexes, then rebuilds building-summary:v1 and the public summary cache. Use it after a bad deploy or cache/index incident where approved submissions do not appear in the standard building list.
  • Rejected player building submissions are visible for 14 days. mikdata writes rejectedAt and expiresAt when rejecting, then stores the submission document, player index key, and status index key with KV expirationTtl.
  • Expired rejection cleanup normally relies on KV TTL. List reads still lazily delete stale rejected records and orphaned player index keys as a fallback. It does not delete already-uploaded ImgBB files because ImgBB delete URLs are not persisted in mikdata.

Configure a Cloudflare Access self-hosted application for data.mcmik.top/admin*. The Worker checks Cf-Access-Jwt-Assertion, so X-Admin-Token is not used.

To find the Access settings:

  • CLOUDFLARE_ACCESS_ISSUER: Zero Trust team domain, for example https://your-team.cloudflareaccess.com.
  • CLOUDFLARE_ACCESS_AUD: Access application AUD tag from the application page.

Runtime Configuration

Do not put upstream addresses or secrets in wrangler.jsonc. Store all runtime configuration as Cloudflare secrets:

Variable Required Purpose
MINECRAFT_SERVER_URL Yes Main upstream data service base URL
MINECRAFT_SERVER_ADDRESS Yes Minecraft status fallback host
MINECRAFT_SERVER_PORT Yes Minecraft status fallback port
CLOUDFLARE_ACCESS_ISSUER Yes Access issuer, for example https://your-team.cloudflareaccess.com
CLOUDFLARE_ACCESS_AUD Yes Access application AUD tag for /admin*
MIKWEB_AUTH_CLIENT_SECRET Yes Shared server-side secret for MikWeb /api/auth/* and /api/account/* BFF requests
WEBAUTHN_RP_ID No Passkey RP ID, defaults to mcmik.top. It must match the MikWeb hostname or a registrable parent domain
WEBAUTHN_ORIGIN No Allowed Passkey origins, defaults to https://mcmik.top. Use comma-separated values for multiple origins

Minecraft upstream requests use the VPC_SERVICE binding configured in wrangler.jsonc; MINECRAFT_SERVER_URL should be reachable through that VPC service. Buildings and building submissions require the BUILDINGS_KV binding. The only active Durable Object binding is AUTH_STORE.

Passkey registration and login must happen on an origin compatible with WEBAUTHN_RP_ID. Production should use WEBAUTHN_RP_ID=mcmik.top and WEBAUTHN_ORIGIN=https://mcmik.top. For local MikWeb development, run MikData locally too and set WEBAUTHN_RP_ID=localhost with WEBAUTHN_ORIGIN=http://localhost:3000.

bunx wrangler secret put MINECRAFT_SERVER_URL
bunx wrangler secret put MINECRAFT_SERVER_ADDRESS
bunx wrangler secret put MINECRAFT_SERVER_PORT
bunx wrangler secret put CLOUDFLARE_ACCESS_ISSUER
bunx wrangler secret put CLOUDFLARE_ACCESS_AUD
bunx wrangler secret put MIKWEB_AUTH_CLIENT_SECRET
bunx wrangler secret put WEBAUTHN_RP_ID
bunx wrangler secret put WEBAUTHN_ORIGIN

For local development, copy .dev.vars.example to .dev.vars and fill values. .dev.vars is ignored by git.

Setup

Install dependencies:

bun install

Create KV namespaces:

bunx wrangler kv namespace create BUILDINGS_KV

Put the generated id values into wrangler.jsonc.

wrangler.jsonc still keeps the historical BuildingsWriter migration and a later deleted_classes migration so Cloudflare can delete the old class. Do not add a BUILDINGS_WRITER binding back unless the storage design changes again.

Run locally:

bun run dev

Deploy:

bun run deploy

Refresh Behavior

Cloudflare Cron refreshes stable routes every five minutes:

  • players
  • bans
  • announcements

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Contributors