Removable reference curves, audit fixes across pages, shaded Academy art
Test and deploy / test-and-deploy (push) Successful in 1m8s
Test and deploy / test-and-deploy (push) Successful in 1m8s
The planner's Artisan .alog drawer now shows what's attached with a "Remove reference curve" control (re-rendered per drawer open), so adding a reference curve is no longer a one-way door; /api/alog shares the 8 MB body cap so real-sized logs parse instead of failing with "bad_request". Deep-evaluation fixes: editing a brew of an archived bean no longer silently detaches the bean; the roasts pending-review poll no longer wipes in-progress after-roast edits; roasters gain an Edit (rename/model) action; the gear page refuses to autosave over a failed load; duplicating a plan carries its custom name; cupping sessions can attach a plan after creation (ownership-checked PUT + selector); admin user deletion also refreshes plans/audit; cupping cup-count subtitle stays live; roasts error-row colspan corrected. Regression tests cover the new cupping PUT and the /api/alog body cap. Academy scenes drop the flat paper-cutout look: shared defs provide radial-gradient shading on every bean/half-bean/particle, flame gradients with radiant halos, soft ground shadows, and a warm-lit stage background; fill-shift animations now ride a partial-opacity tint overlay so shading survives the color change. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
+24
-3
@@ -173,7 +173,8 @@ export function createApp({
|
||||
const parser =
|
||||
req.method === "POST" && req.path === "/api/admin/backup/import"
|
||||
? jsonBodyBackup
|
||||
: req.method === "POST" && req.path === "/api/roasts"
|
||||
: req.method === "POST" &&
|
||||
(req.path === "/api/roasts" || req.path === "/api/alog")
|
||||
? jsonBodyLarge
|
||||
: jsonBody;
|
||||
return parser(req, res, next);
|
||||
@@ -2483,10 +2484,30 @@ export function createApp({
|
||||
coerced.fault_cups,
|
||||
coerced.cup_count,
|
||||
);
|
||||
// Optional plan reattachment (mirrors PUT /api/roasts): a session created
|
||||
// without a plan would otherwise be stuck "Untitled" forever. Ownership of
|
||||
// the target plan is enforced; absent field leaves the link unchanged.
|
||||
let planClause = "";
|
||||
const params = [coerced, total, req.params.id, req.user.id];
|
||||
if (req.body.roastPlanId !== undefined) {
|
||||
const planId = req.body.roastPlanId;
|
||||
if (planId !== null) {
|
||||
if (!UUID_RE.test(String(planId)))
|
||||
return res.status(400).json({ ok: false, code: "bad_plan" });
|
||||
const owned = await db.query(
|
||||
"SELECT 1 FROM roast_plans WHERE id=$1 AND user_id=$2",
|
||||
[planId, req.user.id],
|
||||
);
|
||||
if (!owned.rowCount)
|
||||
return res.status(404).json({ ok: false, code: "plan_not_found" });
|
||||
}
|
||||
params.push(planId);
|
||||
planClause = ", roast_plan_id=$5";
|
||||
}
|
||||
const row = (
|
||||
await db.query(
|
||||
"UPDATE cupping_sessions SET data=$1, total_score=$2, updated_at=now() WHERE id=$3 AND user_id=$4 RETURNING *",
|
||||
[coerced, total, req.params.id, req.user.id],
|
||||
`UPDATE cupping_sessions SET data=$1, total_score=$2, updated_at=now()${planClause} WHERE id=$3 AND user_id=$4 RETURNING *`,
|
||||
params,
|
||||
)
|
||||
).rows[0];
|
||||
if (!row) return res.status(404).json({ ok: false, code: "not_found" });
|
||||
|
||||
Reference in New Issue
Block a user