[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. 🫖 Status page with uptime monitoring & API monitoring as code 🫖 openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
openstatus apps server AGENTS.md
1.7 kB

AGENTS.md — apps/server #

Hono, running on Deno. Four surfaces under apps/server/src/routes/: v1 (public REST), rpc (ConnectRPC), mcp, and slack.

API-key scopes #

Two layers enforce read / write, and both must stay:

  • Service level — requireScope(ctx, "write") inside every service verb. This is the real gate for anything routed through @openstatus/services.
  • Transport level — requireWriteScope() in apps/server/src/libs/middlewares/require-scope.ts, mounted on the V1 router after authMiddleware. V1 predates the services convention and still issues inline Drizzle queries, so service-level checks would skip its write handlers entirely. It maps method to scope: GET/HEAD are read, everything else is write. Adding a V1 route that mutates through a GET silently bypasses it.

New endpoints should call a service verb rather than query Drizzle directly; oxlint.config.ts already bans @openstatus/db and drizzle-orm imports in the handlers that have migrated, and that list grows one domain per PR.

Route config #

Resolve config once and pass it in; createSlackRoute(config) in apps/server/src/routes/slack/index.ts is the pattern — production calls slackConfigFromEnv() at module scope, tests build a route with explicit config. Reading env at request time is what made the slack route untestable under deno test --parallel, since the workers share one process environment.

MCP #

MCP tools declare scope: 'read' | 'write' and register via registerScopedTool, so a read-only key never sees a write tool in tools/list. A tool registered the plain way leaks regardless of the key.