## Implementation Plan: Fix Null Badge Names in Profile JSON Response ### 1. Code Change – Add Pydantic Alias to `BadgeOut.name` **File:** `devplacepy/schemas/content.py` - **Line 65** – Change the field definition from: ```python name: Optional[str] = None ``` to: ```python name: Optional[str] = Field(None, alias="badge_name") ``` - **Imports** – Ensure `from pydantic import Field` is present at the top of the file (it is already imported elsewhere in the module, but confirm the import is available. If not, add it.) This alias tells Pydantic to accept the key `badge_name` from the input dict (the raw database row) and serialize it as `name` in the JSON output. HTML rendering is unaffected because it reads `badge['badge_name']` directly from the raw dict before Pydantic processing. ### 2. Verify No Existing `BadgeOut` Constructions Use `name=` Keyword Argument Search the entire codebase for all occurrences of `BadgeOut(`. If any call site passes `name=` as a keyword argument (e.g., `BadgeOut(name="something")`), the alias will reject that input unless the model config includes `populate_by_name=True`. - **If none exist** → no further config change is needed. - **If some exist** → either: - Change those call sites to use `badge_name=` instead, or - Add `model_config = ConfigDict(populate_by_name=True)` to the `BadgeOut` class (or its parent `_Out`). Given the investigation flow (data comes from database dicts, not programmatic construction), it is expected no such keyword constructions exist. However, this must be confirmed. ### 3. Add a JSON‑Serialization Test for Badge Names **New test location:** `tests/api/profile.py` (or a dedicated schema test, e.g. `tests/unit/schemas/test_badge_out.py`). The test must: - Use the project’s `TestClient` to send a GET request to the profile endpoint with `Accept: application/json`. - Verify HTTP 200. - Parse the JSON response and confirm that each entry in `badges[]` has a non‑null `name` that matches the expected badge text for the test user’s badges. If the test database does not guarantee a badge for the test user, either: - Insert a temporary badge via fixture/database setup, or - Assert that if `badges` is non‑empty, all `name` fields are non‑null. **Existing test pattern:** Look at `tests/api/streaks.py:130` for how API tests are structured. ### 4. Run Verification Commands Execute the project’s test command as specified: ``` pip install -e '.[dev]' -q && python -m pytest {test_files} ``` Initially, run only the modified/new tests to confirm they pass, then run the full suite to ensure no regressions. If any unrelated failures appear (e.g. those seen in earlier attempts), verify they predate this change (should match baseline). No lint command is explicitly required, but if a lint step is part of CI, ensure the change introduces no lint violations (e.g. unused imports, formatting). Run `make lint` or equivalent if available. --- ## Definition of Done - [ ] The `BadgeOut.name` field in `devplacepy/schemas/content.py` has an alias `"badge_name"`. - [ ] The codebase has been scanned for `BadgeOut(name=...)` constructions; if found, either those sites have been updated or `populate_by_name=True` has been added to the model config. - [ ] A test exists that calls the profile endpoint with `Accept: application/json` and asserts that every badge in the response has a non‑null `name`. - [ ] The new test passes when run in isolation. - [ ] The project’s full test suite (`python -m pytest` as specified) passes with no new failures. - [ ] No lint violations are introduced by the change.