Web dashboard: briefs for steps 2-7
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NHyYupFdBiR4VfoUM7NjSM
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# Step 2 — Full issue views, rating widget, POST /rate
|
||||
|
||||
Read `00-shared.md`, then the plan `docs/plans/2026-09-03-web-dashboard.md`
|
||||
(§3, §4.3–§4.4, §5.4, §6.3–§6.4, §8 including §8.1, §16, §17), then
|
||||
`handoff-step1.md` for what the foundation actually shipped. This is plan §19
|
||||
item 2. Build on the step 1 code as it exists; do not restructure it.
|
||||
|
||||
## Deliverables
|
||||
|
||||
1. `issue_full.html` (§8): masthead + dateline, The Brief (`front_page_html`
|
||||
`|safe`), download buttons (from `IssueView.downloads`), the per-section
|
||||
index like the EPUB's In-this-issue page (title → article page,
|
||||
`source · N min read`, summary, Why it's here), the rating widget for admins,
|
||||
links to World Briefing / Behind the paper (only when present), colophon
|
||||
facts footer. `/` and `/issues/{date}` render this for any signed-in viewer.
|
||||
2. `article.html` at `/issues/{date}/articles/{article_id}` (§8): header
|
||||
(title → source, byline, meta line, Why, social line via
|
||||
`chapters::social_line`, summary), body from `ammonia::clean` with the same
|
||||
configuration the EPUB uses (find it in `src/html.rs`/`src/epub`; do not run
|
||||
`to_xhtml`), `<img>` keep remote `src` and get `loading="lazy"
|
||||
referrerpolicy="no-referrer"`, the discussion via `comments::render_xhtml`
|
||||
when present, prev/next in issue order, "Read online ↗", rating widget for
|
||||
admins. 404 (site error page) when the article is not in that issue.
|
||||
3. `world.html` (`/issues/{date}/world`, `world::render_xhtml`, 404 when
|
||||
absent) and `behind.html` (`/issues/{date}/behind`, the same lines as the
|
||||
EPUB chapter via `chapters::behind_*_line`; near misses link to
|
||||
`/dashboard/articles/{id}` for admins).
|
||||
4. These three routes sit under the `login_required!` layer (§3).
|
||||
5. The HMAC confirmation page (`server::confirmation_page`) gains the
|
||||
"Open this issue on the site" link (§8).
|
||||
6. Rating widget partial `_rating_widget.html` + `src/web/rate.rs` (§8.1):
|
||||
`POST /rate` under the admin layer and the origin check; form and JSON
|
||||
variants; `RatingEvent { source: "dashboard", user_id: Some(viewer.id) }`;
|
||||
`cleared` writes value 0.0 with label `cleared`; `issue_date` optional with
|
||||
the dashboard fallback (`db::latest_issue_date_for_article`); JSON →
|
||||
`200 {"article_id","label","event_id"}`, form → flash + 303 to a validated
|
||||
same-site `next`. Check how the CLI (`main.rs` `cmd_ratings`) writes the
|
||||
`cleared` event and match it exactly.
|
||||
7. `app.js`: intercept `.rating` forms, `fetch` with
|
||||
`credentials: "same-origin"` and `Accept: application/json`, update the
|
||||
active button; keep the no-JS form path working.
|
||||
8. Tests (§17 "Full rendering", "Rating"): signed-in `/issues/{date}` contains
|
||||
Brief, summaries and why; article page contains body and discussion; the
|
||||
fallback loader (no `issue_json`) renders without world/discussion links;
|
||||
downloads listed only for files that exist; `POST /rate` as admin appends a
|
||||
`dashboard` event with `user_id`, as user → 403, anonymous → redirect/401,
|
||||
JSON and form variants, `next` validated, `cleared` value 0.
|
||||
Reference in New Issue
Block a user