Conversation
WalkthroughThis PR unifies role and bet data models across frontend and backend by replacing loose string/untyped representations with strongly-typed schemas and enums. The frontend adopts Zod-based validation schemas for bets and auth roles; the backend consolidates role representation into a domain enum, removes string type casts from database queries, and threads the typed role through JWT claims and middleware. Documentation clarifies the new module structure. ChangesRole Type System Unification
Bet Schema Definition and Data Model Migration
Sequence Diagram(s)sequenceDiagram
participant Browser as Browser
participant FrontendAPI as Frontend (getMe)
participant Backend as Backend (Auth Service)
participant Database as Database
participant JWT as JWT / Middleware
Browser->>FrontendAPI: Request user data
FrontendAPI->>Backend: GET /api/me with token
Backend->>JWT: Verify AccessClaims with role: UserRole
JWT-->>Backend: Valid claims (role typed as enum)
Backend->>Database: SELECT * FROM users WHERE id=?
Database-->>Backend: User { role: UserRole } (no string cast)
Backend-->>FrontendAPI: MeResponse { role: UserRole }
FrontendAPI-->>Browser: Update UI with typed role (GUEST|PAID|BOSS)
sequenceDiagram
participant Component as Dashboard Component
participant Store as Data Store
participant BetService as Bet Service
participant Formatter as Bet Constants
Component->>BetService: Request latest bets
BetService-->>Component: Bet[] with betDetails[]
Component->>Component: Read from bet.betDetails[0]
Component->>Formatter: Look up BET_STATUS_LABELS[bet.status]
Formatter-->>Component: Display label (e.g., "Won")
Component->>Component: Use bet.betFinalOdds for calculation
Component-->>Store: Render with typed metadata and odds
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Reasoning: This refactoring touches 20+ files across frontend and backend, affecting core auth and bet data flows. While the pattern is consistent (string → enum/Zod type), you'll need to verify:
Professional Dev WisdomThis PR teaches a valuable lesson: Type-driven refactoring at scale requires consistency across stack layers. You've done something pro here:
Next level: Consider whether your form-value types ( Possibly Related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
rust-server/src/middleware/auth.rs (1)
57-64: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueSmall mentor nudge on
require_role.The implementation is idiomatic —
allowed.contains(&auth.role)is exactly the right shape now thatUserRole: Eq + Copy, and it reads better than the old string slice version. Two seasoned-dev habits worth adopting here:
- Drop
#[allow(dead_code)]the moment you have a first caller. That attribute is a future-proofing band-aid; if it lingers, it hides genuinely dead helpers from the compiler. A common pattern is to introduce the helper in the same PR that wires the first protected route, so the lint stays honest.- Consider an ergonomic call-site macro/helper later. Once you have several protected routes, writing
require_role(&auth, &[UserRole::Boss, UserRole::Paid])?;at the top of every handler gets repetitive. A tower/axum-style layer or extractor wrapper (e.g.AuthUser<{Role::Boss}>) is a great next-level move — but only worth doing once the duplication actually shows up. YAGNI until then.No blocker — just markers on the road to "pro" 🙂.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust-server/src/middleware/auth.rs` around lines 57 - 64, Remove the unnecessary #[allow(dead_code)] on the require_role function so the compiler will warn if it becomes unused; locate the require_role(auth: &AuthUser, allowed: &[UserRole]) -> Result<(), AppError> helper and simply delete the attribute line above it (keep the function body as-is), and keep in mind later you can replace repeated call-sites like require_role(&auth, &[UserRole::Boss, UserRole::Paid])? with a layer/extractor or macro once duplication appears.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@client/documentation.md`:
- Line 14: Update the tree header entry for "lib/" to match the actual contents
described later: replace "API clients, auth helpers, hooks, schemas, stores,
types, utils" with the accurate list used by the code (e.g., "auth, constants,
hooks, stores, types, utils") so the top-level line for "lib/" is consistent
with the detailed section below; edit the string in client/documentation.md
where the tree header line contains "lib/" to reflect the new wording.
In `@client/src/features/bets/schemas.ts`:
- Around line 43-45: The numeric bet fields allow invalid negatives—update the
Zod schemas for odds, stake, homeScore, and awayScore so they enforce domain
bounds: use z.number().positive() for stake and odds (must be >0), and use
z.number().int().nonnegative() for homeScore and awayScore (scores >=0); apply
these changes in the same schema objects where the symbols odds, stake,
homeScore, and awayScore are defined so runtime validation rejects negative or
fractional scores and zero/negative stakes/odds.
In
`@client/src/features/dashboard/components/big-cards/monthly-latest/LatestBet.tsx`:
- Line 13: The betDetails array schema currently allows empty arrays which lets
LatestBet (where detail is read via const detail = bet.betDetails[0]) render
blank fields; update the Zod definition (the betDetails array created from
betDetailsSchema) to require at least one entry by adding .min(1) to the
z.array(...) declaration, or alternatively add explicit handling in the
LatestBet component to check bet.betDetails.length before accessing index 0 and
render a clear fallback/error UI; target the betDetailsSchema array definition
and the LatestBet access site when making the change.
In `@client/src/lib/auth/getMe.ts`:
- Line 4: The `/me` response currently assumes backend returns a valid UserRole
but res.json() can contain invalid values; add runtime validation with Zod
before returning. Define a Zod schema (e.g., MeSchema) that validates at least
data.role as the union or enum matching UserRole, parse the fetched payload (the
object returned by res.json()) inside the getMe function, and throw or handle
validation errors if parsing fails; return the parsed/validated result instead
of the raw payload so callers receive a type-safe object. Ensure you reference
and validate data.role and adjust the function return flow in getMe accordingly.
In `@rust-server/src/features/auth/tokens/jwt.rs`:
- Around line 8-20: Changing AccessClaims.role to UserRole will break existing
tokens; update the JWT schema to be versioned: add a ver: u8 field to
AccessClaims, set ver = 1 in sign_access_token, and update verify_access_token
to accept tokens with ver == 1 while treating missing/other versions as
expired/unauthorized (so clients are forced to refresh rather than failing to
deserialize), or alternatively implement a deploy-time secret roll or shortened
TTL before this change — pick one strategy and implement it. Also, preserve
diagnostic errors from jsonwebtoken by logging the original error with
tracing::error! inside sign_access_token and verify_access_token before mapping
to AppError::internal/unauthorized so you can debug signing/verifying failures.
Ensure references: AccessClaims, sign_access_token, verify_access_token,
UserRole, and AppError are updated accordingly.
---
Outside diff comments:
In `@rust-server/src/middleware/auth.rs`:
- Around line 57-64: Remove the unnecessary #[allow(dead_code)] on the
require_role function so the compiler will warn if it becomes unused; locate the
require_role(auth: &AuthUser, allowed: &[UserRole]) -> Result<(), AppError>
helper and simply delete the attribute line above it (keep the function body
as-is), and keep in mind later you can replace repeated call-sites like
require_role(&auth, &[UserRole::Boss, UserRole::Paid])? with a layer/extractor
or macro once duplication appears.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: a79ebcee-67c2-41b4-b91f-b86c3b0ce3c1
📒 Files selected for processing (22)
README.mdclient/AGENTS.mdclient/documentation.mdclient/src/components/ui/bets/BetStatusBall.tsxclient/src/features/auth/types.tsclient/src/features/bets/constants.tsclient/src/features/bets/schemas.tsclient/src/features/bets/types.tsclient/src/features/dashboard/components/big-cards/monthly-latest/LatestBet.tsxclient/src/features/dashboard/components/big-cards/monthly-latest/LatestCard.tsxclient/src/lib/auth/getMe.tsclient/src/lib/types/bets.tsclient/src/lib/utils/betHelpers.tsrust-server/AGENTS.mdrust-server/documentation.mdrust-server/src/db/queries.rsrust-server/src/features/auth/handlers/me.rsrust-server/src/features/auth/service.rsrust-server/src/features/auth/tokens/jwt.rsrust-server/src/features/auth/types.rsrust-server/src/middleware/auth.rsrust-server/src/types.rs
💤 Files with no reviewable changes (1)
- client/src/lib/types/bets.ts
Summary by CodeRabbit
Documentation
Refactor