feat(web): book reviews — markdown, sibling of ratings, full API + page surface
media_reviews table mirrors media_ratings' shape (unique per user+item, cascade deletes, updated_at for LWW) but standalone: a review without a rating must work. Body is RAW MARKDOWN — storage and every payload carry the source; rendering happens only at display sites (same doctrine as notes, same sanitization pipeline: markdown-it + DOMPurify). API: GET/PUT/DELETE /api/media-items/:id/review (PUT upserts; an empty body deletes — clearing via an editor is a delete, not an empty row). Book-detail page payload now carries the review beside the rating. Page: the review renders above the synopsis as a scrolling card (same max-height box as the summary), hydrated client-side through renderNoteHtml; 'Write review'/'Edit review' sits next to the rating stars and opens a raw-markdown editor dialog (save / delete / cancel). sqlc regenerated; schema applied to the dev DB. Live-verified: upsert, get, empty-delete, page markup, and the app round-trip against the dev server.
This commit is contained in:
1 parent
fd6f0e3353
commit
2117ec6181
13 files changed
+751
-352
No files matched your search
@@ -345,6 +345,20 @@ CREATE TABLE IF NOT EXISTS media_ratings (
|
||||
UNIQUE(media_item_id, user_id)
|
||||
);
|
||||
|
||||
-- Create media_reviews table: the user's markdown book review. Sibling of
|
||||
-- media_ratings (same uniqueness + cascade shape) but standalone — a review
|
||||
-- without a rating (and vice versa) must work. Stored as RAW markdown and
|
||||
-- rendered only at display sites (same doctrine as notes).
|
||||
CREATE TABLE IF NOT EXISTS media_reviews (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
media_item_id UUID NOT NULL REFERENCES media_items(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
review TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
UNIQUE(media_item_id, user_id)
|
||||
);
|
||||
|
||||
-- Create media_notes table for user notes on media items
|
||||
CREATE TABLE IF NOT EXISTS media_notes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
@@ -602,6 +616,10 @@ CREATE INDEX IF NOT EXISTS idx_reading_progress_user_id ON reading_progress(user
|
||||
CREATE INDEX IF NOT EXISTS idx_media_ratings_media_item_id ON media_ratings(media_item_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_ratings_user_id ON media_ratings(user_id);
|
||||
|
||||
-- Reviews indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_media_reviews_media_item_id ON media_reviews(media_item_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_reviews_user_id ON media_reviews(user_id);
|
||||
|
||||
-- Notes and highlights indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_media_notes_media_item_id ON media_notes(media_item_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_notes_user_id ON media_notes(user_id);
|
||||
|
||||
Reference in new issue
Block a user