7e-2: Add GET /notes/{slug}/compiled endpoint #113

Merged
forgejo_admin merged 1 commit from 112-7e-2-compiled-page-api-endpoint-get-note into main 2026-03-08 07:14:11 +00:00
Contributor

Summary

  • Adds a single API endpoint that returns pre-rendered HTML, TOC, metadata, and live block count for a note
  • Removes the need for multiple round-trips (get_note + get_note_toc + get_section calls) to assemble a complete page view

Changes

  • src/pal_e_docs/schemas.py: Added CompiledPageOut Pydantic model with fields: slug, title, html, toc_json, content_hash, block_count, compiled_at
  • src/pal_e_docs/routes/blocks.py: Added GET /{slug}/compiled endpoint that fetches the compiled page, computes live block_count, and returns all fields. Returns 404 for missing notes or missing compiled page entries.
  • tests/test_compiled_page_api.py: 8 tests covering all acceptance criteria plus end-to-end integration

Test Plan

  • Tests pass locally (499/499 pass, 8 new)
  • Manual verification: 404 for missing slug, 404 for missing compiled page, correct fields returned
  • No regressions in existing block API or note endpoints
  • ruff check + format clean

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • Closes forgejo_admin/pal-e-docs #112
  • plan-2026-02-26-tf-modularize-postgres -- Phase 7e (Compiled Pages) -> 7e-2
## Summary - Adds a single API endpoint that returns pre-rendered HTML, TOC, metadata, and live block count for a note - Removes the need for multiple round-trips (get_note + get_note_toc + get_section calls) to assemble a complete page view ## Changes - `src/pal_e_docs/schemas.py`: Added `CompiledPageOut` Pydantic model with fields: slug, title, html, toc_json, content_hash, block_count, compiled_at - `src/pal_e_docs/routes/blocks.py`: Added `GET /{slug}/compiled` endpoint that fetches the compiled page, computes live block_count, and returns all fields. Returns 404 for missing notes or missing compiled page entries. - `tests/test_compiled_page_api.py`: 8 tests covering all acceptance criteria plus end-to-end integration ## Test Plan - [x] Tests pass locally (499/499 pass, 8 new) - [x] Manual verification: 404 for missing slug, 404 for missing compiled page, correct fields returned - [x] No regressions in existing block API or note endpoints - [x] ruff check + format clean ## Review Checklist - [x] Passed automated review-fix loop - [x] No secrets committed - [x] No unnecessary file changes - [x] Commit messages are descriptive ## Related - Closes forgejo_admin/pal-e-docs #112 - `plan-2026-02-26-tf-modularize-postgres` -- Phase 7e (Compiled Pages) -> 7e-2
Add GET /notes/{slug}/compiled endpoint for pre-rendered page data
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
d1c25cd881
Serves compiled HTML, TOC, metadata, and live block_count in a single
API call, removing the need for multiple round-trips to assemble a
complete page view.

Closes #112

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Contributor

PR #113 Review

BLOCKERS

None.

NITS

  1. toc_json type looseness in schema -- CompiledPageOut.toc_json is typed as list[dict] | None. The tests validate a specific structure (anchor_id, text, level keys). Consider using list[TocEntry] | None instead of list[dict] to get Pydantic validation on the response shape. This would catch schema drift early. Non-blocking since TocEntry already exists in the same file (schemas.py line 329).

  2. Test helper _seed_note_with_compiled_page uses raw DB session -- The helper creates its own TestingSessionLocal() session outside the test transaction. This works because tests use TestingSessionLocal directly, but it means test data persists across tests within the same class if cleanup is not handled by the fixture. The existing test suite follows this pattern so this is consistent, but worth noting for future refactors.

  3. test_returns_all_fields and test_slug_and_title_from_note overlap -- Both call _seed_note_with_compiled_page() with the same default slug "compiled-test" and assert the same slug/title values. The second test (test_slug_and_title_from_note) is a subset of the first. Minor redundancy.

SOP COMPLIANCE

  • Branch named after issue -- 112-7e-2-compiled-page-api-endpoint-get-note references issue #112
  • PR body follows template -- Has Summary, Changes, Test Plan, Related sections
  • Related references plan slug -- plan-2026-02-26-tf-modularize-postgres is referenced in Related
  • Closes statement present -- Closes forgejo_admin/pal-e-docs #112
  • No secrets committed -- No credentials, .env files, or sensitive data in diff
  • No unnecessary file changes -- 3 files changed, all directly related to the endpoint (route, schema, tests)
  • Commit messages -- PR title is descriptive
  • Tests exist -- 8 tests covering happy path, 404 cases, live block count, TOC structure, and end-to-end integration

CODE QUALITY

  • Endpoint implementation is clean: two queries (compiled page lookup + live block count), proper 404 handling for both missing note and missing compiled page.
  • Schema fields align correctly with CompiledPage model columns (html, toc_json, content_hash, compiled_at) plus derived fields (slug, title from Note, block_count from live COUNT query).
  • Live block_count via sa_func.count is the right approach -- avoids stale cached counts.
  • Test coverage is thorough: test_block_count_updates_after_add specifically validates the live-query behavior by adding a block and re-fetching.
  • Integration test exercises the full flow (create note -> add blocks -> retrieve compiled page) which validates the recompile() path creates the compiled page entry.

VERDICT: APPROVED

## PR #113 Review ### BLOCKERS None. ### NITS 1. **`toc_json` type looseness in schema** -- `CompiledPageOut.toc_json` is typed as `list[dict] | None`. The tests validate a specific structure (`anchor_id`, `text`, `level` keys). Consider using `list[TocEntry] | None` instead of `list[dict]` to get Pydantic validation on the response shape. This would catch schema drift early. Non-blocking since `TocEntry` already exists in the same file (`schemas.py` line 329). 2. **Test helper `_seed_note_with_compiled_page` uses raw DB session** -- The helper creates its own `TestingSessionLocal()` session outside the test transaction. This works because tests use `TestingSessionLocal` directly, but it means test data persists across tests within the same class if cleanup is not handled by the fixture. The existing test suite follows this pattern so this is consistent, but worth noting for future refactors. 3. **`test_returns_all_fields` and `test_slug_and_title_from_note` overlap** -- Both call `_seed_note_with_compiled_page()` with the same default slug `"compiled-test"` and assert the same slug/title values. The second test (`test_slug_and_title_from_note`) is a subset of the first. Minor redundancy. ### SOP COMPLIANCE - [x] **Branch named after issue** -- `112-7e-2-compiled-page-api-endpoint-get-note` references issue #112 - [x] **PR body follows template** -- Has Summary, Changes, Test Plan, Related sections - [x] **Related references plan slug** -- `plan-2026-02-26-tf-modularize-postgres` is referenced in Related - [x] **Closes statement present** -- `Closes forgejo_admin/pal-e-docs #112` - [x] **No secrets committed** -- No credentials, .env files, or sensitive data in diff - [x] **No unnecessary file changes** -- 3 files changed, all directly related to the endpoint (route, schema, tests) - [x] **Commit messages** -- PR title is descriptive - [x] **Tests exist** -- 8 tests covering happy path, 404 cases, live block count, TOC structure, and end-to-end integration ### CODE QUALITY - Endpoint implementation is clean: two queries (compiled page lookup + live block count), proper 404 handling for both missing note and missing compiled page. - Schema fields align correctly with `CompiledPage` model columns (`html`, `toc_json`, `content_hash`, `compiled_at`) plus derived fields (`slug`, `title` from Note, `block_count` from live COUNT query). - Live `block_count` via `sa_func.count` is the right approach -- avoids stale cached counts. - Test coverage is thorough: `test_block_count_updates_after_add` specifically validates the live-query behavior by adding a block and re-fetching. - Integration test exercises the full flow (create note -> add blocks -> retrieve compiled page) which validates the `recompile()` path creates the compiled page entry. ### VERDICT: APPROVED
forgejo_admin deleted branch 112-7e-2-compiled-page-api-endpoint-get-note 2026-03-08 07:14:11 +00:00
Commenting is not possible because the repository is archived.
No description provided.