26 KiB
Phase 4: Router Layer Test Report
Date: 2026-05-24
Project: mtgonline (/home/wall-o/projects/mtgonline/backend/)
Scope: All FastAPI routers in app/routers/ — correctness, consistency, and integration with schemas/services
Summary
| Router File | Status | Endpoints | Critical Issues | Warnings | Info |
|---|---|---|---|---|---|
main.py |
⚠️ FAIL | — | 1 | 2 | 2 |
auth.py |
✅ PASS | 4 | 0 | 1 | 0 |
users.py |
✅ PASS | 4 | 0 | 0 | 1 |
decks.py |
✅ PASS | 14 | 0 | 1 | 2 |
card_import.py |
⚠️ FAIL | 7 | 1 | 1 | 1 |
card_router.py |
⚠️ FAIL | 6 | 2 | 1 | 1 |
interactions.py |
⚠️ FAIL | 8 | 1 | 2 | 1 |
games/router.py |
⚠️ FAIL | 6 | 1 | 2 | 2 |
admin.py |
✅ PASS | 6 | 0 | 0 | 1 |
rooms.py |
✅ PASS | 5 | 0 | 0 | 1 |
refresh.py |
⚠️ FAIL | 3 | 1 | 1 | 0 |
user_data.py |
⚠️ FAIL | 28 | 3 | 5 | 4 |
Overall: FAIL — 7 out of 11 router files have critical or blocking issues.
1. main.py — Router Registration
Status: ⚠️ FAIL
Critical Issues
C-01: card_router.router double-prefix path conflict
card_router.pydefinesrouter = APIRouter(prefix="/api/cards", ...)main.pymounts it withapp.include_router(card_router.router, prefix="/api", ...)- Result: All card search endpoints resolve to
/api/api/cards/...instead of/api/cards/... - Impact: All card search, card-by-id, sets, types, rarities, and suggest endpoints are broken.
Warnings
W-01: interactions.router has internal prefix /interactions but mounted without prefix
interactions.py:router = APIRouter(prefix="/interactions", ...)main.py:app.include_router(interactions.router, ...)(no prefix)- Result: Paths resolve correctly to
/interactions/...— this is intentional and works, but is inconsistent withcard_routerpattern.
W-02: refresh.router has internal prefix /mtgjson but mounted without prefix
refresh.py:router = APIRouter(prefix="/mtgjson", ...)main.py:app.include_router(refresh.router)(no prefix)- Result: Paths resolve correctly to
/mtgjson/...— same pattern as W-01.
Info
I-01: games.router is imported as games (the package) and mounted with prefix="/games". The actual router is at app.routers.games.router.router. This works because FastAPI resolves games.router to the router attribute of the games module.
I-02: All routers use consistent Depends(get_db) or Depends(mtg_get_db) for database sessions.
2. auth.py — Authentication Router
Status: ✅ PASS
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| POST | /auth/login |
LoginResponse |
❌ (public) |
| POST | /auth/refresh |
TokenResponse |
❌ (token-based) |
| POST | /auth/register |
UserResponse |
❌ (public) |
| GET | /auth/me |
UserResponse |
✅ (token query param) |
Warnings
W-01: get_current_user endpoint uses query parameter for token
- The
/auth/meendpoint expectstoken: stras a query parameter rather than a Bearer token in the Authorization header. - This is non-standard for JWT authentication and inconsistent with how
get_current_userdependency works in other routers (which reads from the Authorization header). - Recommendation: Consider using
Authorization: Bearer <token>header for consistency, or document this as a deliberate design choice.
Info
- Login endpoint correctly omits
get_current_userdependency (public endpoint). - All response models match their schema definitions in
schemas.py. - Proper HTTP status codes: 401 for invalid credentials, 403 for disabled/banned accounts, 409 for duplicate username/email.
3. users.py — User Management Router
Status: ✅ PASS
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /users/{user_id} |
UserResponse |
✅ |
| PATCH | /users/{user_id} |
UserResponse |
✅ (self-only) |
| POST | /users/{user_id}/ban |
dict | ✅ (admin/judge) |
| POST | /users/{user_id}/unban |
dict | ✅ (admin/judge) |
Info
- Self-update protection is correctly implemented (users can only update their own profile).
- Ban/unban endpoints properly check for admin/judge privileges.
UserUpdateschema fields are correctly mapped to model fields.- Password hashing is applied only when
new_passwordis provided.
4. decks.py — Deck Management Router
Status: ✅ PASS
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /decks/ |
UserDeckListResponse |
✅ |
| POST | /decks/ |
UserDeckResponse |
✅ |
| GET | /decks/{deck_id} |
UserDeckResponse |
✅ |
| PATCH | /decks/{deck_id} |
UserDeckResponse |
✅ |
| DELETE | /decks/{deck_id} |
MessageResponse |
✅ |
| POST | /decks/{deck_id}/finalize |
DeckFinalizeResponse |
✅ |
| POST | /decks/{deck_id}/cards |
DeckCardResponse |
✅ |
| GET | /decks/{deck_id}/cards |
DeckCardListResponse |
✅ |
| PATCH | /decks/{deck_id}/cards/{card_id} |
DeckCardResponse |
✅ |
| DELETE | /decks/{deck_id}/cards/{card_id} |
MessageResponse |
✅ |
| GET | /decks/precedents |
PrecedentListResponse |
✅ |
| POST | /decks/precedents |
PrecedentResponse |
✅ |
| GET | /decks/precedents/{precedent_id} |
PrecedentResponse |
✅ |
| POST | /decks/precedents/{precedent_id}/use |
dict | ✅ |
| POST | /decks/search/cards |
CardSearchResponse |
✅ |
| GET | /decks/{deck_id}/suggestions |
SuggestionListResponse |
✅ |
| POST | /decks/{deck_id}/suggestions |
SuggestionResponse |
✅ |
Warnings
W-01: DeckPrecedent imported from app.models.user_deck
DeckPrecedentandDeckPrecedentCardare imported fromapp.models.user_deckbut may belong in a different model file. Verify model placement is correct.
Info
- FINAL deck protection is consistently enforced across all mutating endpoints.
- Owner verification is applied on all deck-access endpoints.
- Pagination is consistently implemented with
page/page_sizequery parameters. - Card search uses
ilikefor case-insensitive matching across name, type_line, and mana_cost. - Precedent cloning correctly copies cards from precedent to new deck.
5. card_import.py — Card Import Router
Status: ⚠️ FAIL
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| POST | /api/v1/card-import/import |
CardImportResponse |
✅ |
| GET | /api/v1/card-import/import/{import_id}/status |
CardImportStatusResponse |
✅ |
| GET | /api/v1/card-import/import/{import_id}/results |
CardImportSummary |
✅ |
| POST | /api/v1/card-import/import/{import_id}/confirm |
MessageResponse |
✅ |
| GET | /api/v1/card-import/user/cards |
List[Dict] |
✅ |
| DELETE | /api/v1/card-import/user/cards/{card_import_id} |
MessageResponse |
✅ |
| GET | /api/v1/card-import/user/decks |
List[Dict] |
✅ |
Critical Issues
C-01: get_user_cards endpoint has no response model
- Returns
List[Dict[str, Any]]instead of a proper Pydantic response model. - Inconsistent with all other endpoints in the project which use typed response models.
- Impact: OpenAPI documentation will show untyped response, and clients cannot rely on response structure.
- Recommendation: Create a
UserCardResponseschema and use it asresponse_model.
Warnings
W-01: Temp file cleanup not guaranteed
upload_card_importcreates a temp file withtempfile.NamedTemporaryFilebut only wraps parsing in a try/except. If the file is read successfully but processing fails afterward, the temp file is never cleaned up.- Recommendation: Use
with tempfile.NamedTemporaryFile(...)as a context manager, or add afinallyblock to delete the temp file.
Info
- File type validation correctly restricts to xlsx, csv, json, ods.
- Owner verification is applied on all import-related endpoints.
- Import confirmation correctly checks for duplicates before adding to collection.
6. card_router.py — Card Search Router
Status: ⚠️ FAIL
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /api/cards/search |
CardSearchResponse |
❌ |
| GET | /api/cards/{card_id} |
CardResponse |
❌ |
| GET | /api/cards/sets |
List[SetResponse] |
❌ |
| GET | /api/cards/types |
List[CardTypeResponse] |
❌ |
| GET | /api/cards/rarities |
List[str] |
❌ |
| GET | /api/cards/suggest |
List[Dict] |
❌ |
Critical Issues
C-01: Double-prefix path conflict (see main.py C-01)
- Router has
prefix="/api/cards"and is mounted atprefix="/api". - All endpoints resolve to
/api/api/cards/...— all 6 endpoints are broken.
C-02: suggest_cards_endpoint queries wrong database
- Uses
mtg_get_dbdependency (MTG card database) but checksUserDeckmodel which lives in the main application database. - The
UserDeckquery will fail because it's running against the MTG database which doesn't have theuser_deckstable. - Impact: Card suggestion endpoint will always return 404 or crash.
- Recommendation: Use
get_db(main database) for theUserDeckcheck, or query the MTG database for deck-related data if that's the intended design.
Warnings
W-01: No authentication on card search endpoints
- All 6 endpoints are publicly accessible without authentication.
- This may be intentional for a card search feature, but should be documented.
- No rate limiting is applied.
Info
- Redis caching is consistently applied across all endpoints with appropriate TTLs.
- Response format uses
{"cached": bool, "results": ...}pattern — non-standard but consistent within this router.
7. interactions.py — Card Interactions Router
Status: ⚠️ FAIL
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /interactions/synergies/{card_id} |
dict | ❌ |
| GET | /interactions/counters/{card_id} |
dict | ❌ |
| GET | /interactions/evolutions/{card_id} |
dict | ❌ |
| GET | /interactions/recommend/{card_id} |
dict | ❌ |
| GET | /interactions/search/synergies |
dict | ❌ |
| GET | /interactions/search/counters |
dict | ❌ |
| GET | /interactions/search/evolutions |
dict | ❌ |
| GET | /interactions/stats/{card_id} |
dict | ❌ |
Critical Issues
C-01: All endpoints return untyped dict responses
- None of the 8 endpoints use
response_model— they all return raw dictionaries. - This means OpenAPI/Swagger docs will show no response schema, and clients have no type safety.
- Recommendation: Create response schemas (e.g.,
SynergyResponse,CounterResponse, etc.) and apply them.
Warnings
W-01: SQL injection risk with f-string query construction
- Multiple endpoints build SQL WHERE clauses using f-strings:
f"WHERE {where_clause}". - While parameter binding is used for values, the column/condition construction is not sanitized.
- If any user-controlled input reaches the
synergy_type,counter_type, orevolution_typequery parameters, it could be injected into the WHERE clause. - Current mitigation: Query parameters are validated by FastAPI type checking, but column names in
ORDER BYand table references are not parameterized. - Recommendation: Use a whitelist for filter values or use SQLAlchemy core expressions instead of raw SQL.
W-02: No authentication on any endpoint
- All 8 endpoints are publicly accessible.
- No rate limiting is applied.
- Recommendation: Document as intentional public API, or add authentication if these are sensitive interaction data.
Info
- Redis caching is consistently applied with appropriate TTLs (10min–30min).
- Pagination is included in search endpoints.
- The
stats/{card_id}endpoint returns zeros for missing cards rather than 404 — reasonable design choice.
8. games/router.py — Game Management Router
Status: ⚠️ FAIL
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /games/ |
List[GameResponse] |
✅ |
| POST | /games/ |
GameResponse |
✅ |
| GET | /games/{game_id} |
GameResponse |
✅ |
| POST | /games/{game_id}/join |
dict | ✅ |
| POST | /games/{game_id}/leave |
dict | |
| POST | /games/{game_id}/start |
dict | |
| POST | /games/{game_id}/end |
dict |
Critical Issues
C-01: list_games and get_game are stub/mock implementations
list_gamesalways returns[]without querying any database.get_gamereturns a hardcoded mock response regardless ofgame_id.- Impact: These endpoints are non-functional. Any client relying on them will get incorrect data.
- Recommendation: Either implement proper database queries or mark these as TODO with appropriate error responses.
Warnings
W-01: Join/Leave/Start/End endpoints have no response model
- All 4 mutation endpoints return raw dicts instead of typed response models.
- Recommendation: Create a
GameActionResponseschema.
W-02: get_game does not verify game ownership or existence
- Returns a mock response for any
game_idwithout checking if the game actually exists. - No authorization check beyond the general
get_current_userdependency. - Recommendation: Implement proper game lookup and ownership verification.
Info
create_gamecorrectly verifies user existence before creating.GameCreateschema is properly used for the create endpoint.- The router imports
Usermodel but only for verification increate_game.
9. admin.py — Admin Router
Status: ✅ PASS
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /admin/users |
List[dict] |
✅ (admin/judge) |
| GET | /admin/bans |
List[BanResponse] |
✅ (admin/judge) |
| POST | /admin/bans |
BanResponse |
✅ (admin/judge) |
| POST | /admin/bans/{ban_id}/unban |
dict | ✅ (admin/judge) |
| GET | /admin/logs |
List[dict] |
✅ (admin/judge) |
| POST | /admin/audit |
dict | ✅ (admin/judge) |
Info
- All endpoints correctly enforce admin/judge privilege checks.
- Ban creation properly links to user and sets moderator name.
- Unban operation correctly updates both Ban and User records.
- Audit logging captures admin actions with target user and details.
10. rooms.py — Room Management Router
Status: ✅ PASS
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /rooms/ |
List[RoomResponse] |
✅ |
| GET | /rooms/{room_id} |
RoomResponse |
✅ |
| POST | /rooms/ |
dict | ✅ (admin/judge) |
| PATCH | /rooms/{room_id} |
dict | ✅ (admin/judge) |
| DELETE | /rooms/{room_id} |
dict | ✅ (admin/judge) |
Info
- CRUD operations are complete for rooms.
- Admin-only write operations are properly enforced.
- Room name uniqueness is checked before creation.
RoomResponseschema matches model fields.
11. refresh.py — MTGJSON Data Refresh Router
Status: ⚠️ FAIL
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| POST | /mtgjson/refresh |
dict | ✅ (admin) |
| GET | /mtgjson/status |
dict | ✅ (admin) |
| POST | /mtgjson/verify |
dict | ✅ (admin) |
Critical Issues
C-01: /status and /verify endpoints missing db dependency
get_refresh_statusandverify_filesdo not acceptdb: AsyncSession = Depends(get_db).- If
MTGJSONManager.get_health_status()orverify_files()need database access, these endpoints will fail. - Impact: Potential runtime error if the manager methods require a database session.
- Recommendation: Add
dbdependency or verify that the manager methods don't need it.
Warnings
W-01: No response model on any endpoint
- All 3 endpoints return raw dicts without
response_model. - Recommendation: Create response schemas for consistency.
12. user_data.py — User Data Router
Status: ⚠️ FAIL
Endpoints
| Method | Path | Response Model | Auth Required |
|---|---|---|---|
| GET | /api/v1/user-data/sessions/me |
List[SessionCleanupResponse] |
✅ |
| DELETE | /api/v1/user-data/sessions/cleanup |
MessageResponse |
✅ |
| POST | /api/v1/user-data/sessions/logout |
MessageResponse |
✅ |
| POST | /api/v1/user-data/decks/{deck_id}/versions |
DeckVersionResponse |
✅ |
| GET | /api/v1/user-data/decks/{deck_id}/versions |
DeckVersionListResponse |
✅ |
| PATCH | /api/v1/user-data/decks/{deck_id}/versions/{version_id} |
DeckVersionResponse |
✅ |
| DELETE | /api/v1/user-data/decks/{deck_id}/versions/{version_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/replays |
GameReplayResponse |
✅ |
| GET | /api/v1/user-data/replays |
GameReplayListResponse |
✅ |
| GET | /api/v1/user-data/replays/{replay_id} |
GameReplayResponse |
✅ |
| PATCH | /api/v1/user-data/replays/{replay_id} |
GameReplayResponse |
✅ |
| DELETE | /api/v1/user-data/replays/{replay_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/replays/{replay_id}/players |
dict | ✅ |
| GET | /api/v1/user-data/replays/{replay_id}/players |
List[dict] |
✅ |
| POST | /api/v1/user-data/outcomes |
GameOutcomeResponse |
✅ |
| GET | /api/v1/user-data/outcomes |
GameOutcomeListResponse |
✅ |
| GET | /api/v1/user-data/statistics/{user_id} |
UserStatisticsResponse |
✅ |
| POST | /api/v1/user-data/statistics/update |
StatisticsUpdateResponse |
✅ |
| POST | /api/v1/user-data/collection |
CardCollectionResponse |
✅ |
| GET | /api/v1/user-data/collection |
CardCollectionListResponse |
✅ |
| PATCH | /api/v1/user-data/collection/{card_id} |
CardCollectionResponse |
✅ |
| DELETE | /api/v1/user-data/collection/{card_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/wishlist |
WishlistResponse |
✅ |
| GET | /api/v1/user-data/wishlist |
WishlistListResponse |
✅ |
| PATCH | /api/v1/user-data/wishlist/{item_id} |
WishlistResponse |
✅ |
| DELETE | /api/v1/user-data/wishlist/{item_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/groups |
GroupResponse |
✅ |
| GET | /api/v1/user-data/groups |
GroupListResponse |
✅ |
| GET | /api/v1/user-data/groups/{group_id} |
GroupResponse |
✅ |
| PATCH | /api/v1/user-data/groups/{group_id} |
GroupResponse |
✅ |
| DELETE | /api/v1/user-data/groups/{group_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/groups/{group_id}/members |
dict | ✅ |
| PATCH | /api/v1/user-data/groups/{group_id}/members/{member_id} |
GroupMemberUpdate |
✅ |
| DELETE | /api/v1/user-data/groups/{group_id}/members/{member_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/groups/{group_id}/messages |
GroupChatMessageResponse |
✅ |
| GET | /api/v1/user-data/groups/{group_id}/messages |
GroupChatMessageListResponse |
✅ |
| POST | /api/v1/user-data/networks |
NetworkResponse |
✅ |
| GET | /api/v1/user-data/networks |
NetworkListResponse |
✅ |
| GET | /api/v1/user-data/networks/{network_id} |
NetworkResponse |
✅ |
| PATCH | /api/v1/user-data/networks/{network_id} |
NetworkResponse |
✅ |
| DELETE | /api/v1/user-data/networks/{network_id} |
MessageResponse |
✅ |
| POST | /api/v1/user-data/networks/{network_id}/members |
dict | ✅ |
| GET | /api/v1/user-data/preferences |
UserPreferenceResponse |
✅ |
| PATCH | /api/v1/user-data/preferences |
UserPreferenceResponse |
✅ |
| GET | /api/v1/user-data/activity |
ActivityLogListResponse |
✅ |
Critical Issues
C-01: create_deck_version verifies user against User table instead of deck ownership
- The endpoint checks
select(User).where(User.id == user_id)which will always succeed for any authenticated user. - It does NOT verify that the user owns the deck being versioned.
- Impact: Any authenticated user can create versions for any deck.
- Recommendation: Add a deck ownership check (e.g., query the deck's
user_idfield).
C-02: get_game_replays has ambiguous join condition
conditions.append(ReplayPlayer.user_id == user_id)— theuser_idcolumn exists in bothGameReplay(via ReplayPlayer join) andReplayPlayer.- SQLAlchemy may raise
AmbiguousForeignKeysErroror join against the wrong table. - Recommendation: Use explicit table references:
ReplayPlayer.user_id == user_idis correct, but the join should be explicit:stmt = stmt.join(ReplayPlayer).
C-03: update_user_statistics has no user ownership verification
- The endpoint accepts
user_idas a query parameter and updates statistics for any user. - Any authenticated user can modify another user's statistics.
- Recommendation: Either restrict to self-update or add admin check.
Warnings
W-01: get_deck_versions returns wrong response structure
DeckVersionListResponseexpectsversions: List[DeckVersionResponse],total: int,page: int,page_size: int,total_pages: int.- But the endpoint wraps the list in
[SessionCleanupResponse(...)]for sessions — wait, that's the sessions endpoint. - Actually,
get_deck_versionscorrectly returnsDeckVersionListResponsewith proper pagination fields. This is correct.
W-02: get_user_groups and get_user_networks add member_count to response
GroupResponseandNetworkResponseschemas includemember_count: int = 0as a default, so this is actually valid.- No issue here — the schemas already account for this field.
W-03: send_group_message manually constructs response instead of using model_validate
- Inconsistent with other endpoints that use
model_validate. - Recommendation: Use
GroupChatMessageResponse.model_validate(message)for consistency, or keep manual construction if sender_username needs special handling.
W-04: add_replay_player and add_network_member return raw dicts
- These endpoints return
{"message": ..., "player_id": ...}instead of typed response models. - Recommendation: Create response schemas.
W-05: get_replay_players returns List[dict] instead of typed response
- Recommendation: Create a
ReplayPlayerResponseschema.
Info
- Extensive CRUD coverage across sessions, decks, replays, outcomes, statistics, collection, wishlist, groups, networks, preferences, and activity logs.
- Owner verification is consistently applied on collection, wishlist, and preference endpoints.
- Group and network admin/owner checks are properly implemented.
- Pagination is consistently applied across list endpoints.
get_user_groupscorrectly filters to groups where the user is a member using subquery.
Cross-Cutting Issues
Authentication/Authorization
| Issue | Severity | Affected Routers |
|---|---|---|
| No auth on card_router endpoints | Warning | card_router.py |
| No auth on interactions endpoints | Warning | interactions.py |
update_user_statistics allows updating any user |
Critical | user_data.py |
create_deck_version doesn't verify deck ownership |
Critical | user_data.py |
Response Model Consistency
| Issue | Count | Affected Routers |
|---|---|---|
Endpoints returning dict instead of typed model |
12 | card_import.py, card_router.py, interactions.py, games/router.py, refresh.py, user_data.py |
Database Session Consistency
| Issue | Affected Routers |
|---|---|
Missing db dependency |
refresh.py |
| Cross-database query (mtg_get_db for UserDeck) | card_router.py |
Path Prefix Consistency
| Issue | Affected Routers |
|---|---|
Double-prefix conflict (/api/api/cards/...) |
card_router.py + main.py |
| Inconsistent prefix patterns (some routers define internal prefix, some don't) | card_router.py, interactions.py, refresh.py |
Recommendations (Priority Order)
P0 — Fix Immediately (Blocking)
-
Fix
card_router.pydouble-prefix: Removeprefix="/api/cards"from the router definition incard_router.pysincemain.pyalready mounts it atprefix="/api". This breaks all 6 card search endpoints. -
Fix
card_router.pycross-database query: Changesuggest_cards_endpointto useget_dbinstead ofmtg_get_dbfor theUserDeckcheck. -
Fix
user_data.pycreate_deck_versionownership check: Add deck ownership verification before allowing version creation. -
Fix
user_data.pyupdate_user_statisticsauthorization: Add ownership or admin check.
P1 — Fix Soon (Significant Impact)
-
Add response models to all endpoints returning
dict: Create proper Pydantic schemas forcard_import.py,interactions.py,games/router.py,refresh.py, anduser_data.pyendpoints that currently return raw dicts. -
Fix
games/router.pystub implementations: Either implement proper database queries forlist_gamesandget_game, or return appropriate error responses. -
Fix
refresh.pymissingdbdependency: Adddbparameter to/statusand/verifyendpoints. -
Fix
interactions.pySQL injection risk: Use parameterized queries or whitelists for filter values.
P2 — Improve (Nice to Have)
-
Standardize prefix pattern: Decide whether routers should define their own prefixes or rely on
main.pymounting. Apply consistently. -
Add authentication to public endpoints: Document why
card_router.pyandinteractions.pyare public, or add rate limiting. -
Fix
auth.pytoken retrieval: Consider using Bearer token header instead of query parameter for/auth/me. -
Add temp file cleanup in
card_import.py: Use context manager or finally block.
Appendix: Endpoint Count by Router
| Router | Total | GET | POST | PATCH | DELETE |
|---|---|---|---|---|---|
auth.py |
4 | 1 | 3 | 0 | 0 |
users.py |
4 | 1 | 2 | 1 | 0 |
decks.py |
17 | 7 | 6 | 2 | 2 |
card_import.py |
7 | 3 | 2 | 0 | 1 |
card_router.py |
6 | 6 | 0 | 0 | 0 |
interactions.py |
8 | 8 | 0 | 0 | 0 |
games/router.py |
7 | 2 | 5 | 0 | 0 |
admin.py |
6 | 3 | 3 | 0 | 0 |
rooms.py |
5 | 2 | 1 | 1 | 1 |
refresh.py |
3 | 1 | 2 | 0 | 0 |
user_data.py |
45 | 17 | 14 | 8 | 6 |
| Total | 112 | 51 | 38 | 12 | 10 |