Files
Shane MaynardandClaude Fable 5 38c7d01e03
Test and deploy / test-and-deploy (push) Successful in 1m6s
Add brewing section, plan chat, roaster learning, API tokens, Swagger docs, and full backup
Brewing:
- roasted_beans + brews tables; /beans (bean management with LLM URL
  prefill) and /brews (silhouette brewer picker across immersion/
  percolation/espresso, recipe fields, auto ratio, 0-10 rating, tasting
  notes); bean remaining weight derived from logged brew doses
- Green inventory lot form also prefills from a product URL

Navigation/UX:
- Side nav is now generated from one definition in nav.js, grouped
  Roasting / Brewing / account, consistent on every page

LLM:
- 'Ask the LLM' chat drawer on the planner (stateless /api/plan-chat)
  grounded in the plan, computed ledger, learned pace, and a new
  roaster-behavior profile aggregated from uploaded .alogs
  (/api/roaster-profile: TP lag, phase RoR, median milestone temps)
- The profile also feeds roast reviews and the planner curve's fallback
  milestone temps

API platform:
- User-generated bearer tokens (rpt_…) with account-page management;
  token requests skip CSRF; hand-authored OpenAPI 3 spec at
  /api/openapi.json rendered by self-hosted Swagger UI at /api-docs
- Full-database backup export/import (admin) + per-user data export

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-08 22:37:42 -04:00

24 lines
784 B
JavaScript

// Boots the self-hosted Swagger UI (the app's CSP forbids inline scripts and CDNs).
// "Try it out" calls run same-origin, so the browser session cookie authenticates them;
// write endpoints additionally need the x-csrf-token header, which is injected below.
/* global SwaggerUIBundle */
const csrf = () =>
document.cookie
.split("; ")
.find((v) => v.startsWith("rp_csrf="))
?.split("=")[1] || "";
window.addEventListener("DOMContentLoaded", () => {
SwaggerUIBundle({
url: "/api/openapi.json",
dom_id: "#swagger-ui",
docExpansion: "none",
defaultModelsExpandDepth: -1,
requestInterceptor: (request) => {
if (!/^(GET|HEAD)$/i.test(request.method) && !request.headers.Authorization)
request.headers["x-csrf-token"] = csrf();
return request;
},
});
});