refactor: restructure API pagination metadata for better frontend usability

- Create PaginationMetadata model with computed derived fields (total_pages, has_next_page, has_prev_page)
- Update PaginatedListResponse to embed pagination metadata in a separate 'pagination' object
- Add create_pagination_metadata() factory function in utils/pagination.py for consistent computation
- Update all paginated service functions to use new structure:
  - history_service.list_history()
  - blocklist_service.get_import_logs()
  - jail_service.get_jail_banned_ips()
  - ban_mappers.map_domain_dashboard_ban_list_to_response()
- Update response model docstrings with new structure examples
- Update Backend-Development.md documentation with new pagination patterns
- Update test fixtures to work with new response structure

Response shape changes from:
  {"items": [...], "total": 100, "page": 1, "page_size": 50}
To:
  {"items": [...], "pagination": {"page": 1, "page_size": 50, "total": 100, "total_pages": 2, "has_next_page": true, "has_prev_page": false}}

Benefits:
- Frontend receives all pagination state needed for UI controls
- No need for frontend to calculate total_pages or page navigation logic
- Consolidated pagination metadata reduces field sprawl
- OpenAPI schema automatically reflects changes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-30 22:24:42 +02:00
parent 05c3b564ae
commit 73021429f7
9 changed files with 156 additions and 96 deletions

View File

@@ -1,51 +1,3 @@
## [IMPORTANT] Scheduler lock race condition
**Where found**
- `backend/app/utils/scheduler_lock.py:56-58` — heartbeat interval 10 seconds
**Why this is needed**
Current design: Process A acquires lock, heartbeat misses, lock expires, Process B acquires lock, both running simultaneously → duplicate work, data corruption.
**Goal**
Implement robust distributed locking that prevents concurrent execution.
**What to do**
**Option A (Strengthen heartbeat):**
- Reduce interval to 5s (half of timeout)
- Use database advisory locks
- Monitor heartbeat failures
**Option B (Migrate to Redis):**
- Use `redlock-py` or `aioredis`
- Simpler, more reliable than database-backed
**Current code improvements:**
- Log when heartbeat fails
- Add metric for lock contention
- Test multi-process scenario
**Possible traps and issues**
- Database locks don't scale under high contention
- Redis adds new dependency
- Clock skew breaks timestamp-based expiry
**Docs changes needed**
- Update `Docs/Deployment.md` § Scheduler Lock
- Add troubleshooting: "Blocklist import runs twice"
**Doc references**
- `Docs/Deployment.md` (scheduler)
- `backend/app/utils/scheduler_lock.py` (lock implementation)
---
## [IMPORTANT] API pagination doesn't return metadata
**Where found**