Multi-user rentals with copy limits, bans and an admin panel - #174
Multi-user rentals with copy limits, bans and an admin panel#174devin-ai-integration[bot] wants to merge 8 commits into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…he store Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Original prompt from Ramiro
|
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
E2E validation on Okteto (namespace
|
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Summary
Turns the single-user demo into a multi-user rental store: users sign in with just an email, the catalog is shared with a limited number of copies per movie, and an admin panel (
admin/admin123) manages users, bans and the catalog.The core change is the rentals model. Today
rentals(id UNIQUE, price)has no notion of a user and a return deletes the row, so there is no history and no way to count copies. Now:A return sets
returned_at, so rows survive as history, and availability iscopies - count(active rentals for that movie). The worker no longer drops the rentals table on boot; bothapiandworkercalldatabase.EnsureSchema(idempotent) and migrate the legacy table.Auth lives in the existing Go
api(per the plan review): a base64url payload + HMAC-SHA256 signature inmovies_session/movies_admincookies, signed withSESSION_SECRET. Becauserent(Java) andcatalog(Node) must trust the same cookies, all three charts get the samesessionSecretvalue.Rentals are still async through Kafka, which used to mean a rejected rental just vanished into the worker's logs.
rentnow asks the api synchronously before publishing, so the UI gets an immediate409:The worker re-runs the same checks inside the insert transaction, since the pre-check is advisory and two requests can race for the last copy. Note the payload carries no price: the worker looks it up with
catalog.Lookup(movieID)and charges what the catalog says, so a client can't pick its own price.Movies gained a
copiesfield (seeded 1-4; missing/invalid falls back toDefaultCopies = 3), and the catalog service gained admin-onlyPOST/PUT/DELETE /catalog.The frontend is rewritten from the class component with the hardcoded Cindy session into a functional app: login, "my movies" with returns, history, availability badges/sold-out, the banned meme screen with a good-deed form, and
/admin(users + histories + ban/unban + redemption queue + catalog CRUD).Storere-fetches/meon mount and after every action so a user banned mid-session lands on the meme screen without a reload.Validated end to end on Okteto in a dedicated namespace (
devin-multiuser-rentals):okteto test e2epasses 8/8, plus a browser pass over the whole flow with two concurrent users and the admin panel.Note:
SESSION_SECRET,ADMIN_USERNAMEandADMIN_PASSWORDare plain chart values (demo defaultsokteto-movies-demo/admin/admin123) — fine for the demo, worth promoting to a Secret before anything real.Link to Devin session: https://app.devin.ai/sessions/04a3cbd2609a47509c195b95cc573235
Requested by: @rberrelleza