808b15bafb
Adds a long-lived bearer-token mechanism + scoped REST surface designed
for n8n-style automation: create a gallery, upload photos, fetch the
share URL — all via documented HTTPS endpoints instead of poking at the
admin UI's internal routes.
API
- Migration 081 adds `api_tokens` (hashed_token, scopes, owner FK,
last_used/expires/revoked timestamps).
- New apiTokenAuth middleware: parses `Authorization: Bearer pp_live_…`,
resolves to the owner admin user, attaches `req.admin` so existing
permission decorators (events.create etc.) still work. Token-level
scope check (read/write/admin) layers on top as defence in depth —
a leaked read-only token cannot mutate even if its owner is super_admin.
- adminApiTokens route exposes list/create/revoke for admins (cookie-
authed). Plaintext token is returned exactly once on creation.
- v1 surface mounted at /api/v1: POST/GET /events, GET /events/:id,
POST /events/:id/photos (multipart, single file), GET
/events/:id/share-link. Each endpoint annotated with @openapi JSDoc.
Documentation
- swagger-jsdoc + swagger-ui-express produce a live spec at
/api/openapi.json and a Swagger UI at /api/docs (admin-gated).
- backend/scripts/generate-openapi.js writes docs/openapi.{json,yaml}
to the repo so the spec is versioned.
- scripts/sync-api-docs.sh runs in pre-push: regenerates the spec and
copies it into the picpeak-docs Nextra site at app/api/. Writes only,
never commits or pushes the docs repo (PUSH_SKIP_DOCS=1 to bypass).
Frontend
- New Settings → API Tokens tab: generate, list, revoke. Plaintext
tokens are shown once with a copy-to-clipboard control.
31 lines
1.0 KiB
JavaScript
31 lines
1.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Generate the OpenAPI spec from JSDoc annotations in src/routes/v1/* and
|
|
* write it as YAML + JSON to ../docs/. Used by scripts/sync-api-docs.sh
|
|
* to keep the picpeak-docs site in lockstep with the running API.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Need yaml — runtime require so the script fails clearly with an
|
|
// install hint instead of an opaque MODULE_NOT_FOUND.
|
|
let yaml;
|
|
try {
|
|
yaml = require('js-yaml');
|
|
} catch {
|
|
console.error('generate-openapi: missing dependency `js-yaml`. Run `npm install --save-dev js-yaml` in /backend.');
|
|
process.exit(2);
|
|
}
|
|
|
|
const { getOpenApiSpec } = require('../src/openapi/spec');
|
|
|
|
const outDir = path.resolve(__dirname, '../../docs');
|
|
fs.mkdirSync(outDir, { recursive: true });
|
|
|
|
const spec = getOpenApiSpec();
|
|
fs.writeFileSync(path.join(outDir, 'openapi.json'), JSON.stringify(spec, null, 2));
|
|
fs.writeFileSync(path.join(outDir, 'openapi.yaml'), yaml.dump(spec, { lineWidth: 100 }));
|
|
|
|
console.log(`Wrote openapi.json + openapi.yaml to ${outDir}`);
|