2.1 KiB
2.1 KiB
ADM-018 Implementer Evidence
Summary
Enhanced GET /users backend to support admin customer listing with search, pagination, and total count. Updated frontend to consume the new response shape.
Changes
Backend (users module)
Domain layer (profile.ts):
- Added
CustomerSummaryinterface (userId, email, role, displayName, phone, createdAt) - Added
CustomerListResultinterface (items, total) - Added
CustomerListOptionsinterface (q, offset, limit)
Ports (ports.ts):
- Added
listCustomers(opts)andfindCustomerById(userId)toProfileRepository
Application (profile-use-cases.ts):
- Added
ListCustomersuse case - Added
GetCustomeruse case
Infrastructure (pg-profile-repository.ts):
- Implemented
listCustomers(): JOIN identity_users + users_profiles, ILIKE search on email, LIMIT/OFFSET pagination, COUNT for total - Implemented
findCustomerById(): single customer lookup with JOIN
API (users.routes.ts):
GET /usersnow acceptsq,offset,limitquery params; returns{ items, total }GET /users/:idnow returns CustomerSummary (includes email, role) instead of bare Profile- Added
serializeCustomer()function mappinguserId→idfor frontend compatibility
Frontend (admin app)
api-client.ts: Updated customersApi.list() return type to { items, total }
customers/page.tsx: Wired setTotal(data.total) from API response
Verification
| Check | Result |
|---|---|
| Backend typecheck | ✅ clean |
| Backend build | ✅ clean |
| Backend tests | ✅ 123 passed |
| Admin typecheck | ✅ clean |
| Domain purity | ✅ no DB/HTTP imports in domain |
| Parameterized queries | ✅ all SQL uses $1, $2, etc. |
Acceptance traceability
| Criterion | Evidence |
|---|---|
| Customer list with search | GET /users?q=foo → ILIKE on email |
| Pagination | offset/limit params, default 20 per page |
| Total count | COUNT(*) query, returned as total |
| Email and role in response | JOIN identity_users + users_profiles |
| Admin-only | Existing requireRole(user, 'admin') gate |