Skip to content

Commit f627ddc

Browse files
InfantLabclaude
andcommitted
feat(api): live OpenAPI docs at /api-docs (Scalar) and /api/openapi.json
Enables Nitro's experimental OpenAPI generation and serves the spec + Scalar UI from the app itself, in both dev and production. Subscribed users can now browse the REST API without leaving the site; admin endpoints are included with tags + security metadata so they render distinctly. Adds a defineRouteMeta example to the new admin ourmoji daily endpoint as a template — future endpoints can opt in to richer request/response schema documentation by following the same pattern. The ourmoji agent walkthrough now links to the live docs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 46bb4ea commit f627ddc

3 files changed

Lines changed: 88 additions & 1 deletion

File tree

app/nuxt.config.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,30 @@ export default defineNuxtConfig({
157157

158158
// Nitro server configuration
159159
nitro: {
160-
// Enable SQLite in production
160+
// Enable SQLite in production + OpenAPI/Scalar docs
161161
experimental: {
162162
database: true,
163+
openAPI: true,
164+
},
165+
166+
// Public API documentation — served from the app itself so subscribed
167+
// users can browse endpoints without leaving the site. Admin endpoints
168+
// are listed but tagged so they're visually separated.
169+
openAPI: {
170+
route: "/api/openapi.json",
171+
production: "runtime",
172+
meta: {
173+
title: "Ta-Da! API",
174+
description:
175+
"REST API for Ta-Da! — authenticate with a Bearer API key (tada_key_…). Admin endpoints require the caller's user id to be in ADMIN_USER_IDS on the server.",
176+
version: pkg.version,
177+
},
178+
ui: {
179+
scalar: {
180+
route: "/api-docs",
181+
},
182+
swagger: false,
183+
},
163184
},
164185
// Externalize native bindings - they can't be bundled, must use node_modules at runtime
165186
externals: {

app/server/api/v1/admin/ourmoji/daily.post.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,62 @@
1414

1515
import { defineEventHandler, readBody, createError } from "h3";
1616

17+
defineRouteMeta({
18+
openAPI: {
19+
tags: ["Ourmoji", "Admin"],
20+
summary: "Ingest a daily Ourmoji on behalf of a user (admin)",
21+
description:
22+
"Posts a single day's Ourmoji payload for a target user. Intended " +
23+
"for trusted server-to-server agents authenticated with an admin " +
24+
"API key. Idempotent per (userId, date).",
25+
security: [{ bearerAuth: ["admin:users:write"] }],
26+
requestBody: {
27+
required: true,
28+
content: {
29+
"application/json": {
30+
schema: {
31+
type: "object",
32+
required: [
33+
"userId",
34+
"date",
35+
"emoji",
36+
"reflection",
37+
"moonPhase",
38+
"timezone",
39+
],
40+
properties: {
41+
userId: { type: "string" },
42+
date: { type: "string", format: "date" },
43+
emoji: { type: "string", minLength: 1, maxLength: 16 },
44+
reflection: { type: "string", minLength: 1, maxLength: 5000 },
45+
moonPhase: { type: "string" },
46+
moonIllumination: {
47+
type: "number",
48+
minimum: 0,
49+
maximum: 100,
50+
nullable: true,
51+
},
52+
wheelOfYear: { type: "string", nullable: true },
53+
wheelCategory: { type: "string", nullable: true },
54+
timezone: { type: "string" },
55+
},
56+
},
57+
},
58+
},
59+
},
60+
responses: {
61+
"200": { description: "Ourmoji entry upserted" },
62+
"400": {
63+
description:
64+
"Validation error or target user does not have ourmoji enabled",
65+
},
66+
"401": { description: "Missing or invalid Bearer token" },
67+
"403": { description: "Caller is not an admin" },
68+
"404": { description: "Target user not found" },
69+
},
70+
},
71+
});
72+
1773
import { requireAdmin } from "~/server/utils/admin";
1874
import {
1975
notFound,

docs/modules/ourmoji-agent-setup.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,14 @@ co-ordination across users.
208208

209209
---
210210

211+
## Reference: live API docs
212+
213+
Interactive docs for this endpoint (and the rest of the API) are served from
214+
the app itself — no local setup needed:
215+
216+
- **Scalar UI:** https://tada.living/api-docs
217+
- **OpenAPI JSON:** https://tada.living/api/openapi.json
218+
219+
---
220+
211221
[Back to Ourmoji](./ourmoji.md)

0 commit comments

Comments
 (0)