Files
babymonitor/plan_2_prompt.md
2026-06-24 15:30:47 +02:00

4.7 KiB

Plan 2 — Error Handling & Code Quality

Items covered: #5 (magic return types), #6 (silent error suppression), #15 (hardcoded CORS warning)


Context

You are working on a FastAPI backend for a baby monitor / sleep tracker app. The codebase lives under app/. This plan improves how errors are communicated — both internally between modules and externally to API clients. Make one change at a time, re-read each modified file before moving to the next, and run the tests at the end.


Tasks

1. Replace magic return types with typed exceptions (app/crud.py and app/routers/sessions.py)

Step 1 — Read the files first

Read app/crud.py (specifically the session-end function around lines 57-82) and app/routers/sessions.py (specifically the caller around lines 64-73) before touching anything. Understand the full flow.

Step 2 — Define typed exceptions

Create a new file app/exceptions.py with the following exceptions:

class SessionNotFoundError(Exception):
    pass

class SessionAlreadyEndedError(Exception):
    pass

class InvalidEndTimeError(Exception):
    pass

Step 3 — Update crud.py

In the session-end function in app/crud.py, replace each magic return value with the appropriate raise:

  • Where it currently return None (session not found) → raise SessionNotFoundError
  • Where it currently return False (session already ended) → raise SessionAlreadyEndedError
  • Where it currently return "invalid" → raise InvalidEndTimeError

Change the function's return type annotation to SleepSession (it now only returns on success).

Import the exceptions at the top of crud.py:

from app.exceptions import SessionNotFoundError, SessionAlreadyEndedError, InvalidEndTimeError

Step 4 — Update sessions.py

In app/routers/sessions.py, replace the chain of if result is None / if result is False / if result == "invalid" checks with try/except blocks that catch each exception and map it to the correct HTTPException:

  • SessionNotFoundError → HTTPException(status_code=404, detail="Session not found")
  • SessionAlreadyEndedError → HTTPException(status_code=409, detail="Session already ended")
  • InvalidEndTimeError → HTTPException(status_code=422, detail="End time is invalid")

Import the exceptions at the top of sessions.py.


2. Replace silent error suppression with 422 responses (app/routers/stats.py)

Step 1 — Read the file first

Read app/routers/stats.py and locate both silent-suppression patterns (around lines 24-25 and 114-115). They look like:

try:
    day_start_time = time.fromisoformat(day_start)
except ValueError:
    return {"days": []}  # silent empty response

Step 2 — Replace each one

Replace every such except ValueError: return {...} block with:

except ValueError:
    raise HTTPException(
        status_code=422,
        detail=f"Invalid format: {day_start!r}"
    )

Adjust the detail message to name the specific parameter that was malformed. Make sure HTTPException is imported from fastapi at the top of the file.


3. Add a CORS misconfiguration warning (app/config.py and app/main.py)

Step 1 — Read both files first

Read app/config.py to understand the Settings model and how CORS_ORIGINS is defined. Read app/main.py to see where settings is used.

Step 2 — Add a startup warning

In app/main.py, add a startup event (or inline check at module load time) that logs a warning if CORS_ORIGINS still has the localhost default value. Example:

import logging
logger = logging.getLogger(__name__)

@app.on_event("startup")
async def warn_if_default_cors():
    if "localhost" in settings.CORS_ORIGINS:
        logger.warning(
            "CORS_ORIGINS contains localhost (%s). "
            "Set the CORS_ORIGINS environment variable in production.",
            settings.CORS_ORIGINS,
        )

If a startup event already exists, add the check inside it rather than creating a duplicate.

Also add a comment directly above the CORS_ORIGINS field in app/config.py:

# Override in production via the CORS_ORIGINS environment variable.
# Leaving this as localhost will cause CORS errors in deployed environments.
CORS_ORIGINS: str = "http://localhost:5173"

Verification

Run the full test suite after all changes:

pytest

All existing tests must pass. If any test fails because it was checking for the old magic-return behaviour (e.g. asserting result == "invalid"), update those tests to expect the correct HTTPException status code instead. Do not suppress or skip failing tests. Do not move on to Plan 3 until the test suite is green.