Public Access
f94e0aff159af450aeb14bdd9ccbe41bb0b4601a
Detail page gets an edit card. The library gets status badges, status filter chips and a debounced name search, both kept in the URL.
To Be Played - Frontend
A modern web application to manage your game backlog, built with React and Vite.
🚀 Tech Stack
- Framework: React
- Build Tool: Vite
- Styling: Tailwind CSS 4
- Icons: Material Design Icons (MDI)
📂 Project Structure
├── public/ # Static assets (favicons, icons)
├── src/
│ ├── assets/ # Images and global media
│ ├── components/ # Reusable React components
│ ├── App.jsx # Main application layout and entry component
│ ├── main.jsx # App initialization (React DOM, Styles)
│ └── style.css # Global Tailwind and custom CSS
├── index.html # Entry HTML file
├── package.json # Dependencies and scripts
└── vite.config.js # Vite configuration
🛠️ Development
Setup
npm install
Start Development Server
npm run dev
Build for Production
npm run build
🗺️ Roadmap / Open Topics
Tracking known work that is not yet implemented. Each item is independently actionable.
Security
- Move JWT out of
localStorage. Today the token is stored underlocalStorage["tbp_jwt"], which makes it readable by any script running on the page — a single XSS in an npm dependency exfiltrates every session. Switch to an httpOnlySecureSameSite=Laxcookie set bytbp-auth-serviceon login. The SPA no longer touches the token directly; the browser attaches it automatically to requests to*.tbp.andreas-dahm.eu. Requires coordinated changes in Auth (set the cookie) and Deployment (cookie domain + CORSallowCredentials=true). - Add CSRF handling. Once auth rides on a cookie, the SPA must echo a CSRF token in a header on state-changing requests. Spring Security's
CookieCsrfTokenRepository.withHttpOnlyFalse()on the server pairs with a smallfetchinterceptor on the client that readsXSRF-TOKENand setsX-XSRF-TOKEN. - Content Security Policy. Add a CSP header in
nginx.confso XSS exfiltration paths are blocked even if a vulnerability slips in. Minimum starting point:default-src 'self'; img-src 'self' data: https://*.steamstatic.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'. Tighten further by replacing inline styles/scripts (Tailwind is already build-time, so this should be feasible).
Testing
The project has no test runner today. Suggested setup:
- Unit / component tests: Vitest + React Testing Library. Tests live next to the component (
Component.test.jsx). - API mocking: MSW (Mock Service Worker) so component tests don't hit the real backend and the same handlers can drive Storybook later.
- End-to-end tests: Playwright, scoped to the golden paths (login → see library → log out, registration with invitation code, settings update). Run against the real
tbp-auth-service+tbp-core-serviceviadocker-compose.dev.ymlin CI. - First test targets: the auth context / token-handling code, the dark-mode toggle (
localStorage["tbp_dark_mode"]), and i18n string resolution.
Other
- Audit
localStorageusage. Currently used fortbp_jwt(planned to move) andtbp_dark_mode. Document any other keys before they accumulate. - API base URL handling.
VITE_API_URLcovers Auth; Core's base URL is implicit. Make both explicit (e.g.VITE_AUTH_URL,VITE_API_URL) so dev / prod / preview environments are unambiguous.
🎯 Product Roadmap (Frontend-owned slices)
The full cross-service product roadmap lives in ToBePlayed-Deployment/README.md. This section lists only the UI / UX slices that land in the Frontend.
1. Backlog tracking UI
Today GameLibrary.jsx is a paginated grid of synced Steam games — there is no per-game state. Once Core exposes status + notes + rating, the Frontend needs:
- Status chips on each game card (
BACKLOG / PLAYING / COMPLETED / DROPPED / ON_HOLD / WISHLIST) with one-click cycling or a popover for explicit selection. - Status filter bar above the grid; multi-select; persisted to URL search params so links are shareable and back-button works.
- Game detail page (
GameDetail.jsxexists — extend it) with rating widget (stars or 1–10), completion date picker, markdown notes editor with preview. Optimistic update on save, server reconciliation on failure. - Drag-to-reorder within
BACKLOGfor priority. Use a small library (@dnd-kit/core) — well-maintained, accessible.
2. "What to play next" page
- New route:
/play-next(or surface from Dashboard). - Form: time budget radio (15 min / 1 h / weekend), mood tag multi-select.
- On submit: call Core's picker endpoint, render 3 cards. "Reroll" button calls again.
- One-tap "Start playing" sets game status to
PLAYING.
This page is the single best mobile entry point — design mobile-first.
3. Achievement views
Data is already in Core. The Frontend needs:
- Achievement progress ring on each game card + game detail.
- New route
/achievementsshowing library-wide unlocked / total / percent. - "Closest to 100%" widget on Dashboard.
4. Public profile + sharing
- New route
/u/:usernamerendered server-friendly (consider SSR / pre-render for SEO, or at least set proper<title>/<meta>viareact-routerloaders so link previews work). - "Currently playing" + "Recently completed" sections.
- "Share my profile" button (copies URL).
- Settings toggle for
profile_public.
5. Friends + compare
/friendspage: list, request, accept, remove.- "Add friend" search by username (autocomplete against Auth endpoint).
- "Compare backlogs with X" page: lists games both own, intersected with
BACKLOGstatus on either side — i.e. "next co-op night candidates".
6. Mobile / PWA
- Verify the SPA is installable as a PWA: manifest, icons (already in
public/?), service worker viavite-plugin-pwa. - Test core flows (login, picker, status update) on a real phone, not just devtools. The "what to play tonight" use case is mobile-primary.
7. UX details that compound
- Search: client-side fuzzy search across library (Fuse.js or similar) on the already-loaded page; server-side search if the library gets large enough that pagination hurts.
- Empty states: every list should have an empty state with a clear next action ("Connect Steam to import games", "No completed games yet — mark one!").
- Optimistic updates for any status / rating / notes change — they should feel instant.
- Keyboard shortcuts for power users (
j/kto navigate,sto set status,?to show shortcut list). - i18n is already wired (
i18next); make sure every new string lands in the translation files, not hardcoded.
Languages
JavaScript
96.7%
CSS
3.2%