@@ -88,10 +88,12 @@ The paper inventory correlates three sources:
8888- Events: job_queued, job_started, job_completed, job_failed, queue_drained
8989- NEVER bypass the queue. NEVER call the session directly.
9090
91- ## Two Pages
91+ ## Tabs
9292
93- - ` / ` - Dashboard: top bar (auth + summary pills), paper table, log, bottom status bar
94- - ` /settings ` - Settings: output dir, watch dirs, credentials, style
93+ - ** Folio** - paper inventory table with status badges, detail rows, upload
94+ - ** Render** - card-based drop targets for one-off preview rendering
95+ - ** Settings** - output dirs (folio + render), watch dirs, style, fonts, credentials
96+ - ** Log** - activity log with dimming
9597
9698Both pages use SSE (` /api/events ` ) for live updates. The SSE
9799connection is per-page - it reconnects on navigation. State is
@@ -103,33 +105,50 @@ markdown changed -> watchdog -> render worker -> PDF created ->
103105PDF watchdog -> dirty flag -> user clicks Upload -> IsoCppSession
104106queue -> isocpp.org
105107
106- ## Button UX Rules (TODO - not yet fully implemented)
108+ ## Button UX Rules
107109
108- Buttons that submit work to the IsoCppSession queue (docketeer)
109- or to the render worker follow this pattern:
110+ Buttons that submit work follow this pattern:
110111
1111121 . ** Press** -> button enters working state immediately:
112113 - Disabled (no re-click)
113114 - Animated glowing border (badge-working style)
114115 - 70% opacity
1151162 . ** Log** -> IsoCppSession's on_event fires job_queued, which
116117 the server logs automatically. Render worker logs "Starting..."
117- 3 . ** Event** -> button stays working until an SSE event confirms
118- completion (job_completed, job_failed, rendered, render_done)
119- 4 . ** Done** -> log entry for completion, button re-enables
120- 5 . ** Log styling** -> completion entries at 50% opacity to
118+ 3 . ** Event** -> button stays working until completion is
119+ confirmed (SSE event or HTTP response)
120+ 4 . ** Done** -> log entry for completion, button re-enables,
121+ ` _workingSet ` cleared for the doc number
122+ 5 . ** Failure** -> toast shown, button re-enables, working
123+ state cleared. Both HTTP errors and SSE failures clear state.
124+ 6 . ** Log styling** -> completion entries at 50% opacity to
121125 distinguish from active/error entries
122126
123- Buttons that go through the queue:
124- - Upload (IsoCppSession.submit upload - syncs title, author, abstract + PDF)
127+ Queue-based buttons (SSE confirms completion):
128+ - Upload (IsoCppSession.submit upload - syncs title, author,
129+ abstract + PDF)
125130- Draft/Review transition (IsoCppSession.submit transition)
126- - Render per-paper (render worker)
127- - Render All (render worker)
128- - Log In (blocks on login request, not queued but same UX)
131+ - Render per-paper (render worker via batch queue)
132+ - Render All (render worker via batch queue)
129133
130- Buttons that do NOT go through the queue (instant, no working
131- state needed): Log Out, Clear Log, Open Folder, Shut Down,
132- Save (settings), tab switches.
134+ Synchronous buttons (HTTP response confirms completion):
135+ - Render tab preview cards (render-preview endpoint with
136+ ` _preview_lock ` serialization)
137+ - Log In (blocks on login request)
138+
139+ Instant buttons (no working state needed): Log Out, Clear Log,
140+ Shut Down, Save (settings), tab switches.
141+
142+ ## Render Serialization
143+
144+ All ` build_pdf ` calls are serialized through ` _preview_lock ` .
145+ The batch render worker acquires it per file. The preview
146+ endpoint acquires it for the full render. This prevents
147+ concurrent ReportLab font registration corruption.
148+
149+ ` build_pdf ` is self-contained: it loads the font manifest,
150+ downloads missing fonts, registers them, and builds the PDF.
151+ Callers only need to provide a style dict.
133152
134153## No Public Scraping
135154
0 commit comments