Add roaster (machine) management, mobile header-tools redesign, and profile pictures
Test and deploy / test-and-deploy (push) Successful in 1m0s

Machines:
- roasters table + actual_roasts.roaster_id (migrations 009): per-user
  machines with a default; uploads attach to the default roaster and are
  reassignable from the roast detail view
- Learning is now per machine: /api/roaster-profile scopes to a roaster
  (default when unspecified) and applies the user's override tweaks
  (milestone temps, TP time, pace factor) on top of learned medians
- /roasters page: machine list + analysis report showing learned vs
  applied values with editable tweaks, typical RoR, and a plain-language
  list of the adjustments applied to plans; planner honors a manual pace
  override; evaluations use the roast's own machine profile

Mobile header redesign:
- The planner's header tools collapse behind a single 'Tools ▾'
  disclosure (dropdown card) at ≤720px, keeping the fixed three-row
  mobile header with no wrapped or scrolling button rows; desktop
  renders inline via display:contents (same DOM, same handlers)

Profile pictures:
- users.avatar (migration 010) + PUT/GET/DELETE /api/account/avatar;
  client-side centre-crop resize to 128px JPEG; avatar shows in the nav
  chip on every page; included in full backups

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Shane Maynard
2026-08-09 08:17:10 -04:00
co-authored by Claude Fable 5
parent e62b9601a2
commit a341d67467
15 changed files with 1291 additions and 62 deletions
+150
View File
@@ -0,0 +1,150 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Machines — Roast Planner</title>
<link rel="stylesheet" href="/app.css?v=__ASSET_VERSION__" />
<link rel="icon" href="/icon.svg?v=__ASSET_VERSION__" type="image/svg+xml" />
<meta name="theme-color" content="#A8481A" />
</head>
<body>
<div class="app-shell">
<nav class="side-nav" id="side-nav" aria-label="Main navigation">
<div class="side-nav-brand">
<span class="brand-mark" aria-hidden="true"></span>
<span class="brand-name">Roast Planner</span>
</div>
<div id="nav-links"></div>
<div class="nav-spacer"></div>
<button
class="icon-btn nav-collapse-toggle"
type="button"
id="nav-collapse"
aria-label="Collapse navigation"
title="Collapse navigation"
>
«
</button>
<div class="nav-user">
<div class="nav-user-avatar" id="nav-user-avatar" aria-hidden="true"></div>
<div class="nav-user-detail">
<span class="nav-user-email" id="account-email"></span>
<button class="nav-user-logout" type="button" id="btn-logout">
Log out
</button>
</div>
</div>
</nav>
<div class="app-workspace" id="app-workspace">
<header class="app-header">
<div class="header-row-top">
<button
class="icon-btn nav-hamburger"
type="button"
id="nav-hamburger"
aria-label="Open navigation"
aria-expanded="false"
>
</button>
<div class="brand">
<div class="brand-text">
<h1>Machines</h1>
<p class="brand-sub">
Your roasters — what the app has learned from each, and your
tweaks to it
</p>
</div>
</div>
</div>
</header>
<div class="drawer-overlay hidden" id="drawer-overlay"></div>
<main class="page-content">
<section class="panel-card" id="roasters-card">
<div class="panel-head"><h2>Your roasters</h2></div>
<div class="panel-body">
<div class="table-wrap">
<table class="data-table" id="roasters-table">
<thead>
<tr>
<th>Roaster</th>
<th>Default</th>
<th class="num">Logged roasts</th>
<th></th>
</tr>
</thead>
<tbody id="roasters-body"></tbody>
</table>
</div>
<form
id="roaster-form"
style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:12px"
>
<input
class="text-input"
name="name"
placeholder="Name (e.g. Hottop)"
required
style="max-width:200px"
/>
<input
class="text-input"
name="model"
placeholder="Model (e.g. KN-8828B-2K+)"
style="max-width:220px"
/>
<button class="ghost-btn" type="submit">Add roaster</button>
</form>
<p class="field-note">
Uploaded .alogs attach to the default roaster (you can reassign
any roast from its detail view on the Roasts page). Learning,
the planner's suggested curve, and roast reviews all use the
selected machine's own history.
</p>
</div>
</section>
<section class="panel-card hidden" id="report-card">
<div class="panel-head">
<h2 id="report-title">Analysis</h2>
<span class="muted" id="report-count"></span>
</div>
<div class="panel-body">
<p class="field-note" id="report-empty" hidden>
No roasts logged against this machine yet — upload finished
.alogs on the Roasts page and the analysis fills in.
</p>
<div id="report-body">
<div class="table-wrap">
<table class="data-table" id="report-table">
<thead>
<tr>
<th>What the plans use</th>
<th>Learned from your roasts</th>
<th>Your tweak</th>
<th>Applied</th>
</tr>
</thead>
<tbody id="report-rows"></tbody>
</table>
</div>
<p class="field-note" id="report-ror"></p>
<div id="report-adjustments" style="margin-top:8px"></div>
<button class="primary-btn" type="button" id="save-overrides" style="margin-top:10px">
Save tweaks
</button>
<button class="ghost-btn" type="button" id="clear-overrides" style="margin-top:10px">
Clear all tweaks (use learned values)
</button>
</div>
</div>
</section>
</main>
</div>
</div>
<script type="module" src="/js/roasters.js?v=__ASSET_VERSION__"></script>
</body>
</html>