feat: add pagination, cross-board activity endpoint, and Project updated_at #181
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/pal-e-api!181
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "180-add-pagination-cross-board-activity-endp"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Add three features to support the pal-e-app frontend activity feed: pagination on the notes list endpoint, a cross-board activity endpoint for recent board item changes, and an
updated_attimestamp on the Project model.Changes
src/pal_e_docs/routes/notes.py: Addlimit(int|None, ge=1) andoffset(int|None, ge=0) query params toGET /notes. Defaults to None for full backwards compatibility.src/pal_e_docs/routes/boards.py: AddGET /boards/activityendpoint returning board items across all boards sorted byupdated_at DESC. Supportslimit(default 20, max 100) andcolumnfilter. Registered before/{slug}to avoid FastAPI route conflicts.src/pal_e_docs/models.py: Addupdated_atcolumn toProjectmodel withserver_default=func.now()andonupdate=func.now().src/pal_e_docs/schemas.py: Addupdated_at: datetimefield toProjectOutschema.alembic/versions/p6k7l8m9n0o1_add_project_updated_at.py: Alembic migration addingupdated_atcolumn toprojectstable.tests/test_pagination_activity.py: 23 new tests covering all three features.Test Plan
ruff formatandruff checkcleanReview Checklist
Related
plan-pal-e-docs-- Phase F11Self-Review
Verdict: PASS -- no blockers.
Reviewed
Pagination (
GET /notes) --limit(ge=1) andoffset(ge=0) default toNonefor full backwards compatibility. Applied after ordering, works with all existing filters. Validation rejects limit=0 and negative offset via FastAPI Query constraints.Activity endpoint (
GET /boards/activity) -- Registered before/{slug}to avoid route conflicts (matches existing pattern for/backlog/items). Column filter reuses the sameBoardColumnenum validation pattern fromlist_board_items. Default limit of 20, max 100.Project
updated_at-- Follows the identical pattern used byNote.updated_at,Board.updated_at, andBoardItem.updated_at(server_default + onupdate). Schema updated. Migration is clean and minimal.Tests -- 23 new tests covering edge cases: validation boundaries, empty results, cross-board queries, filter combinations, order preservation, route conflict avoidance.
Lint --
ruff formatandruff checkclean. All 577 tests pass.PR #181 Review
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / Alembic / Pydantic (pal-e-docs API)
Backwards compatibility (GET /notes): PASS.
limitandoffsetdefault toNone. When both areNone, no.offset()or.limit()is applied, and the query returns all results exactly as before. The refactor from two separatereturnstatements (lines 400-401 in old code) to a singlereturn q.all()is clean.Route ordering (GET /boards/activity): PASS.
/activityis registered at line 100, before/{slug}at line 162. Comment documents the ordering requirement. Follows the exact same pattern as/backlog/itemsat line 70.Schema consistency (ProjectOut): PASS.
updated_at: datetimeadded toProjectOutschema (line 60 in schemas.py). Matches the ORM model.from_attributes = Truehandles the serialization.Code patterns: The activity endpoint follows the exact same enum validation pattern used in
list_board_itemsandlist_backlog_itemsfor column/item_type filtering. Clean and consistent.onupdate behavior:
onupdate=func.now()is ORM-level (not a DB trigger), consistent with 5 other columns in the codebase that use the same pattern. Works correctly with SQLite test fixtures.Ruff compliance: Code formatting matches existing patterns. No unused imports.
BLOCKERS
1. BLOCKER: Alembic migration creates multiple heads (will break CI and deployments)
Migration
p6k7l8m9n0o1hasdown_revision = "o5j6k7l8m9n0", but migrationb9817e1e5862(already on main) also hasdown_revision = "o5j6k7l8m9n0". This creates two Alembic heads branching from the same parent. Runningalembic upgrade headwill fail with:Fix: Change the new migration's
down_revisionfrom"o5j6k7l8m9n0"to"b9817e1e5862"so the chain is linear:This is the only change needed. The migration logic itself (additive
add_columnwithserver_default) is correct and safe.NITS
Global mutable state in test helper (
_item_counter): The_item_counterglobal at line 31 oftest_pagination_activity.pypersists across tests and across test classes within the same process. It works because it only needs uniqueness (not specific values), but auuid4().hex[:8]suffix would be more idiomatic and immune to test ordering issues. Non-blocking.Missing negative limit test for
/notes: The tests coverlimit=0(422) andoffset=-1(422), but do not testlimit=-1. FastAPI'sge=1constraint handles this, but an explicit test would be more thorough. Non-blocking.No
offsetparam on/boards/activity: The notes endpoint supports bothlimitandoffset, but the activity endpoint only supportslimit. For a frontend activity feed, offset-based pagination (or cursor-based) may be needed later. Not a blocker for this PR since it was not in the issue requirements.No max limit on
/notespagination: The activity endpoint capslimitatle=100, but the notes endpoint allows anylimit >= 1(e.g.,limit=999999). Consider addingle=1000or similar for consistency and to prevent accidental full-table scans. Non-blocking.SOP COMPLIANCE
180-add-pagination-cross-board-activity-endpreferences issue #180)plan-pal-e-docs-- Phase F11)PROCESS OBSERVATIONS
server_default, no data migration needed). The only issue is the revision chain, not the migration logic.alembic upgrade head(which CI does per PR #169). This is exactly the kind of issue CI should catch.VERDICT: NOT APPROVED
One blocker: the Alembic migration's
down_revisionmust be updated from"o5j6k7l8m9n0"to"b9817e1e5862"to fix the multiple-heads conflict. All other aspects of this PR are solid -- the code is clean, well-tested, and follows existing patterns. Once the migration chain is fixed, this is ready to merge.PR #181 Review (Re-review)
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / Alembic / Pydantic
Pagination (
GET /notes): Clean implementation.limitandoffsetare optionalQueryparams with properge=1/ge=0constraints. Defaults toNonefor full backwards compatibility. Ordering is applied before pagination (correct SQL semantics). The refactor from inline.all()to building the query then applying offset/limit is well-structured.Activity endpoint (
GET /boards/activity): Properly registered before/{slug}to avoid FastAPI route conflicts (same pattern as existing/backlog/items).BoardColumnenum validation with descriptive 422 error. Default limit 20, max 100 viale=100. Sorted byupdated_at DESC-- correct for an activity feed.Project
updated_at: Model usesserver_default=func.now()andonupdate=func.now()-- consistent with the pattern used onNote,Block,Board, andBoardItem. Schema addsupdated_at: datetimetoProjectOut. Migration is minimal and correct (add_column/drop_column).Alembic migration:
down_revision = "b9817e1e5862"is correct. Verified the full migration chain is linear (18 migrations, single head). The previous review's blocker (wrongdown_revision) is fixed.BLOCKERS
None. The previous blocker (Alembic
down_revisionpointing to non-existent revision) has been fixed.down_revisionnow correctly points tob9817e1e5862(thefix_schema_drift_nullable_timestampsmigration, which is the actual head on main).NITS
Module-level mutable state in tests (
_item_counterglobal intest_pagination_activity.py, line 31): Works correctly but is a minor code smell. A pytest fixture or class-level counter would be more idiomatic. Non-blocking.test_activity_default_limitcreates notes that do not exist (lines 180-186): The test creates 25 board items withnote_slug=f"note-{i}"but these notes are never created. This works because the API does not validate note existence on board item creation -- but it relies on that implementation detail. Non-blocking since the feature being tested is the limit, not note resolution.SOP COMPLIANCE
180-add-pagination-cross-board-activity-endp)plan-pal-e-docs -- Phase F11)Closes #180)ruff formatandruff checkreported cleanPROCESS OBSERVATIONS
None(no limit/offset), so existing API consumers are unaffected.ProjectOutschema now expectsupdated_atfrom the database.VERDICT: APPROVED