perf(settlement,rating): paginate 3 unbounded list endpoints (M10-M12)

- M10 GET /settlement: was unbounded; add page/limit + countByUser + data.meta.
- M11 GET /admin/comments/pending: paginate findPending + countPending.
- M12 GET /comments/{doctor}: paginate the fetch-joined roots query via
  Paginator(fetchJoinCollection) + countApprovedRootsByDoctor.

All keep the existing { data: { data: [...] } } envelope and add data.meta
(backward compatible). Default limit 50 / max 100.

Regressions: SettlementListPaginationTest, CommentPaginationTest (both fail
without the limits). Also de-flaked SendCodeMobileRateLimitTest (randomised the
IP block so the persistent per-IP limiter buckets don't accumulate across runs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-06-28 20:36:41 +03:30
co-authored by Claude Opus 4.8
parent 447482c2ea
commit 61ac775175
10 changed files with 175 additions and 24 deletions
+2
View File
@@ -184,6 +184,8 @@ Get approved **root** comments for a doctor (replies are nested under each root
**Permission:** `PUBLIC`
> **صفحه‌بندی:** `?page` و `?limit` (پیش‌فرض ۵۰، حداکثر ۱۰۰)؛ پاسخ شامل `data.meta` (`totalRecords`/`totalPages`/`currentPage`) است. آرایه‌ی نظرات همچنان در `data.data` است. همین صفحه‌بندی روی `GET /api/v1/admin/comments/pending` هم اعمال می‌شود.
### Path Parameters
| Param | Type | Description |
|-------|------|-------------|
+3 -1
View File
@@ -141,10 +141,12 @@ Request a settlement (withdrawal from wallet to bank account).
## GET `/api/v1/settlement`
Get authenticated user's settlement requests.
Get authenticated user's settlement requests (paginated, newest first).
**Permission:** `AUTH`
> **صفحه‌بندی:** `?page` و `?limit` (پیش‌فرض ۵۰، حداکثر ۱۰۰). پاسخ علاوه بر `data.data` یک `data.meta` (`totalRecords`/`totalPages`/`currentPage`) دارد؛ پاکت قبلی دست‌نخورده است.
### Response `200`
```json
{
+3 -3
View File
@@ -63,9 +63,9 @@ _None outstanding._
| ✅M7 | Refresh token not rotated on use (same raw token 30d), never re-checks user status | src/Auth/Controller/AuthController.php:477-480 · TokenService.php:33-45 | security-auth | **DONE** — single-use rotation (revoke old + issue new) + suspended-user (status!=1) rejected. `tests/Auth/RefreshTokenRotationTest`. |
| M8 | N+1: secretary list lazy-loads secretary/doctor ManyToOne per row | src/Secretary/Controller/SecretaryController.php:192,213 | perf-nplus1 | Profiler secretary list → ~2 queries/row |
| M9 | N+1: billing claims lazy `items` + `insuranceRepo->find()` per claim in enrichClaims | src/Billing/Controller/BillingController.php:~49,68 | perf-nplus1 | GET claims → items+insurance query/claim |
| M10 | Unbounded list: `listMine` settlements `findByUser` no limit | src/Settlement/Controller/SettlementController.php:193 | perf-pagination | GET settlement list → paginate |
| M11 | Unbounded list: admin `pendingComments` `findPending` no limit | src/Rating/Controller/RatingController.php:350 | perf-pagination | admin moderation large backlog → paginate |
| M12 | Unbounded list: public `listComments` per-doctor no limit | src/Rating/Controller/RatingController.php:270 | perf-pagination | popular doctor comments → paginate |
| M10 | Unbounded list: `listMine` settlements `findByUser` no limit | src/Settlement/Controller/SettlementController.php:193 | perf-pagination | **DONE** — page/limit + countByUser + data.meta. `tests/Settlement/SettlementListPaginationTest` |
| M11 | Unbounded list: admin `pendingComments` `findPending` no limit | src/Rating/Controller/RatingController.php:350 | perf-pagination | **DONE** — findPending(limit,offset)+countPending+meta. `tests/Rating/CommentPaginationTest::testAdminPendingListPaginates` |
| M12 | Unbounded list: public `listComments` per-doctor no limit | src/Rating/Controller/RatingController.php:270 | perf-pagination | **DONE** — Paginator(fetchJoinCollection) page/limit + countApprovedRootsByDoctor + meta. `tests/Rating/CommentPaginationTest::testPublicListPaginates` |
| ⚠️M13 | Missing index: `ServiceItem.section_id` FK fully unindexed (entity has zero indexes) | src/ClinicService/Entity/ServiceItem.php:23-24 | perf-index | EXPLAIN findBySection → no full scan |
| ✅M14 | Missing index: `WalletTransaction(user_id, type)` composite for per-type SUM | src/Settlement/Entity/WalletTransaction.php:38-39 | perf-index | **DONE** — added composite `idx_wallet_user_type` + migration. `InfraSmokeTest::testWalletUserTypeIndexExists`. |
| ⚠️M15 | Missing index: `ClinicDoctorInvitation.doctor_id` FK unindexed | src/ClinicInvitation/Entity/ClinicDoctorInvitation.php:41-42 | perf-index | **FALSE POSITIVE**`doctor_id` has a FK → auto-indexed (IDX_26DCCFEB87F4FB17 exists). No change. |