Purpose
This issue is the implementation guide for v2.3.0. It defines the exact order work should proceed across the milestone issues, which components are shared, what to build first to avoid rework, and how features compose together.
v2.3.0 focuses on shot analysis intelligence, beginner guidance, and run experience — transforming MeticAI from a profile generation tool into an iterative brewing coach. It builds directly on v2.2.0's profile editing (#257 ), shot analysis view (#259 ), catalogue management (#192 ), and temporary profile infrastructure (pour-over).
Issue Map
#
Title
Type
Stream
Status
#175
Refactor ShotHistoryView monolith
Frontend refactor
A
⬜ Not started
#186
Accessibility pass (ARIA, landmarks, keyboard)
Frontend quality
A
⬜ Not started
#95
Recommend existing profiles during generation
Feature (Profile)
B
⬜ Not started
#258
AI analysis → profile editing pipeline
Feature (Analysis)
C
⬜ Not started
#281
Temporary variable adjustments when running a shot
Feature (Run)
D
⬜ Not started
#261
Espresso Compass taste input
Feature (Analysis)
E
⬜ Not started
#260
Dial-In Guide for Beginners
Feature (Home)
E
⬜ Not started
Implementation Streams
Five independent work streams enable high parallelism:
Stream A (Frontend Quality): #175 (refactor) ──→ #186 (a11y)
Stream B (Profile Intelligence): #95 (recommend profiles) [standalone]
Stream C (Analysis Pipeline): #258 (analysis → edit pipeline) [standalone]
Stream D (Run Experience): #281 (temporary variable adjustments) [standalone]
Stream E (Brewing Coach): #261 (compass) ──→ #260 (dial-in wizard)
Cross-version Dependencies (all satisfied by v2.2.0 PR #262 )
2.3 Issue
Depends on v2.2 Feature
v2.2 Status
#258
#257 — PUT /api/profile/{name}/edit endpoint
✅ Built
#95
#192 — Profile catalogue with managed profiles
✅ Built
#260
#259 — Shot analysis view + recent shots endpoints
✅ Built
#281
#257 — PUT /api/profile/{name}/edit endpoint
✅ Built
#281
temp_profile_service.py — Temporary profile lifecycle (pour-over)
✅ Built
#281
coffee.py:105-145 — Adjustable vs info variable classification
✅ Built
Intra-milestone Dependencies
Issue
Must complete first
Reason
#186 (a11y)
#175 (refactor)
a11y attributes must target the final sub-component structure, not the pre-refactor monolith
#260 (dial-in)
#261 (compass)
Dial-in wizard Step 5 uses the TasteCompassInput component from #261
Note: #281 has no intra-milestone dependencies. It modifies RunShotView.tsx (not ShotHistoryView.tsx), so it is independent of all other streams.
Phased Implementation Order
Phase 1: ShotHistoryView Refactor (#175 )
Current state: 2,545 lines. Chart extraction already complete (no direct recharts imports). Remaining work is pure sub-component decomposition.
Phase 2: Profile Recommendations (#95 )
Can run in parallel with Phase 1
Phase 3: Analysis → Profile Edit Pipeline (#258 )
Can run in parallel with Phases 1–2
Phase 4: Temporary Variable Adjustments (#281 )
Can run in parallel with Phases 1–3 — standalone
Key infrastructure to reuse:
temp_profile_service.py — temp profile lifecycle (create → load → cleanup)
pour_over.py + PourOverView.tsx — reference implementation of the full temp profile UX pattern
PUT /api/profile/{name}/edit — variable update logic (key/value matching)
coffee.py:105-145 — adjustable vs info variable classification
Phase 5: Espresso Compass Taste Input (#261 )
Can start in parallel; must complete before Phase 6
Phase 6: Dial-In Guide for Beginners (#260 )
Depends on Phase 5 (#261 ) — largest feature in the milestone
dialin_service.py — session management + AI integration
dialin.py models — DialInSession, DialInIteration, TasteFeedback
6 API endpoints (POST /api/dialin/session, etc.)
DialInWizard.tsx — 7-step wizard with state machine
7 step components (CoffeeStep, ProfileStep, PrepStep, BrewStep, TasteStep, RecommendStep, HistoryStep)
'dial-in' ViewState + "Dial In" button on home page
Dial-in-specific Gemini prompt template
i18n, unit tests, frontend tests
Phase 7: Accessibility Pass (#186 )
Depends on Phase 1; should be last to cover all new components including #281 's VariableAdjustPanel
Sub-phase 1: Landmarks & structure (<main>, <nav>, <aside>, skip nav, tab roles)
Sub-phase 2: Live regions (aria-live on metrics, shot completion, machine state)
Sub-phase 3: Interactive elements (aria-label, aria-describedby, keyboard handlers)
Sub-phase 4: Charts & visualization (role="img", text summaries, keyboard legends)
Sub-phase 5: Testing (axe-core in Playwright, screen reader manual test, keyboard walkthrough)
Shared Components
Component
Built in
Consumed by
TasteCompassInput
#261
#260 (DialInTasteStep)
RecommendationSelectionDialog
#258
Standalone (ExpertAnalysisView)
VariableAdjustPanel
#281
RunShotView; potentially reusable for profile editing
DialInWizard + step components
#260
Standalone (StartView)
useAnnounce hook
#186
All components with dynamic updates
ShotList, ShotDetail, ShotComparison
#175
ShotHistoryView, potentially #260
v2.2.0 Compatibility Items
These should be verified before v2.2.0 merges:
PUT /api/profile/{name}/edit response format — must return enough metadata for Integrate AI shot analysis recommendations with profile editing pipeline #258 's apply-recommendations to chain (updated profile JSON, change summary)
GET /api/shots/recent metadata — must include enough shot info for Add Dial-In Guide for Beginners to Home Page #260 's dial-in wizard to reuse
parseStructuredAnalysis() extensibility — must handle N sections (not hardcoded to 5) for Integrate Espresso Afficionados Compass Guide for taste-based shot analysis #261 's 6th section
GET /api/machine/profiles detail level — must return full parameters (temperature, variables, stages) for Recommend existing profiles during generation and in catalogue #95 's scoring and feat: temporary variable adjustments when running a shot #281 's variable adjustment panel
temp_profile_service.py extensibility — must support arbitrary profile JSON overrides (not just pour-over templates) for feat: temporary variable adjustments when running a shot #281 's temporary variable adjustments
Risk Assessment
Risk
Impact
Mitigation
#260 (Dial-In) is very large (~20+ new files)
Schedule slip
Sub-phase: steps 1–3 can ship independently of 4–7
Compass UI (#261 ) is complex touch/drag component
UX quality
Prototype early; consider existing React 2D picker lib
#186 a11y pass touches nearly every component
Merge conflicts
Schedule last; one focused sprint
Gemini structured JSON output (#258 ) may be inconsistent
Reliability
Response validation + retry with format correction prompt
#281 temp profile cleanup on abort/error
Data integrity
Reuse proven pour-over cleanup pattern; add startup orphan cleanup for "MeticAI Override:" prefix
Done When
Purpose
This issue is the implementation guide for v2.3.0. It defines the exact order work should proceed across the milestone issues, which components are shared, what to build first to avoid rework, and how features compose together.
v2.3.0 focuses on shot analysis intelligence, beginner guidance, and run experience — transforming MeticAI from a profile generation tool into an iterative brewing coach. It builds directly on v2.2.0's profile editing (#257), shot analysis view (#259), catalogue management (#192), and temporary profile infrastructure (pour-over).
Issue Map
Implementation Streams
Five independent work streams enable high parallelism:
Cross-version Dependencies (all satisfied by v2.2.0 PR #262)
PUT /api/profile/{name}/editendpointPUT /api/profile/{name}/editendpointtemp_profile_service.py— Temporary profile lifecycle (pour-over)coffee.py:105-145— Adjustable vs info variable classificationIntra-milestone Dependencies
TasteCompassInputcomponent from #261Phased Implementation Order
Phase 1: ShotHistoryView Refactor (#175)
ShotList.tsx— shot selection list with search, filtering, date groupingShotDetail.tsx— individual shot view (chart + metadata + analysis)ShotComparison.tsx— side-by-side comparison modeShotHistoryView/directory with barrel exportShotHistoryView.tsxto orchestration (<1,000 lines)bun run build+bun run lint+bun run test:runall passCurrent state: 2,545 lines. Chart extraction already complete (no direct recharts imports). Remaining work is pure sub-component decomposition.
Phase 2: Profile Recommendations (#95)
Can run in parallel with Phase 1
POST /api/profiles/recommendendpoint with profile scoringFormView.tsxafter roast + ≥2 tagsProfileCatalogueView.tsxPhase 3: Analysis → Profile Edit Pipeline (#258)
Can run in parallel with Phases 1–2
POST /api/shots/analyze-recommendations— structured JSON recommendations from GeminiPOST /api/profile/{name}/apply-recommendations— batch-applies patchable recommendationsprompt_builder.pywithRECOMMENDATIONS_JSONformatRecommendationSelectionDialog.tsx— grouped checkboxes, confidence badges, value previewsExpertAnalysisView.tsxPhase 4: Temporary Variable Adjustments (#281)
Can run in parallel with Phases 1–3 — standalone
POST /api/machine/run-profile-with-overridesendpoint inscheduling.py"temporary"mode: fetch profile JSON → apply variable overrides →temp_profile_service.create_and_load()→ register cleanup"save_original"mode: call existingPUT /api/profile/{name}/edit→ run normally"save_as_new"mode: clone profile → apply overrides → save with new name → runtemp_profile_service.pyif needed for variable-override use caseVariableAdjustPanel.tsx— expandable panel showing adjustable variables (filterinfo_prefix)RunShotView.tsx— show panel after profile selectionKey infrastructure to reuse:
temp_profile_service.py— temp profile lifecycle (create → load → cleanup)pour_over.py+PourOverView.tsx— reference implementation of the full temp profile UX patternPUT /api/profile/{name}/edit— variable update logic (key/value matching)coffee.py:105-145— adjustable vs info variable classificationPhase 5: Espresso Compass Taste Input (#261)
Can start in parallel; must complete before Phase 6
TasteCompassInput.tsx— interactive 2D draggable compassPOST /api/shots/analyze-llmwith optional taste parametersPhase 6: Dial-In Guide for Beginners (#260)
Depends on Phase 5 (#261) — largest feature in the milestone
dialin_service.py— session management + AI integrationdialin.pymodels — DialInSession, DialInIteration, TasteFeedbackPOST /api/dialin/session, etc.)DialInWizard.tsx— 7-step wizard with state machine'dial-in'ViewState + "Dial In" button on home pagePhase 7: Accessibility Pass (#186)
Depends on Phase 1; should be last to cover all new components including #281's VariableAdjustPanel
<main>,<nav>,<aside>, skip nav, tab roles)aria-liveon metrics, shot completion, machine state)aria-label,aria-describedby, keyboard handlers)role="img", text summaries, keyboard legends)Shared Components
TasteCompassInputRecommendationSelectionDialogVariableAdjustPanelDialInWizard+ step componentsuseAnnouncehookShotList,ShotDetail,ShotComparisonv2.2.0 Compatibility Items
These should be verified before v2.2.0 merges:
PUT /api/profile/{name}/editresponse format — must return enough metadata for Integrate AI shot analysis recommendations with profile editing pipeline #258'sapply-recommendationsto chain (updated profile JSON, change summary)GET /api/shots/recentmetadata — must include enough shot info for Add Dial-In Guide for Beginners to Home Page #260's dial-in wizard to reuseparseStructuredAnalysis()extensibility — must handle N sections (not hardcoded to 5) for Integrate Espresso Afficionados Compass Guide for taste-based shot analysis #261's 6th sectionGET /api/machine/profilesdetail level — must return full parameters (temperature, variables, stages) for Recommend existing profiles during generation and in catalogue #95's scoring and feat: temporary variable adjustments when running a shot #281's variable adjustment paneltemp_profile_service.pyextensibility — must support arbitrary profile JSON overrides (not just pour-over templates) for feat: temporary variable adjustments when running a shot #281's temporary variable adjustmentsRisk Assessment
Done When