Files
2026-08-17 22:23:10 +02:00

2.7 KiB

ADM-018 Design — Customer List

Problem

GET /users only returns users_profiles fields (userId, displayName, phone). The admin frontend needs email, role, createdAt from identity_users, plus search by email, pagination, and total count.

Design

Backend changes (users module)

Domain layer — extend Profile with optional email and role:

// profile.ts — add:
export interface CustomerSummary {
  userId: string;
  email: string;
  role: string;
  displayName: string | null;
  phone: string | null;
  createdAt: Date;
}

export interface CustomerListResult {
  items: CustomerSummary[];
  total: number;
}

Port — add new method to ProfileRepository:

listCustomers(opts: { q?: string; offset: number; limit: number }): Promise<CustomerListResult>;

InfrastructurePgProfileRepository.listCustomers():

SELECT iu.id, iu.email, iu.role, up.display_name, up.phone, iu.created_at
FROM identity_users iu
LEFT JOIN users_profiles up ON up.user_id = iu.id
WHERE ($1::text IS NULL OR iu.email ILIKE '%' || $1 || '%')
ORDER BY iu.created_at DESC
LIMIT $2 OFFSET $3

Plus a COUNT(*) query for total.

Application — new use case ListCustomers:

export class ListCustomers {
  constructor(private readonly profiles: ProfileRepository) {}
  async execute(opts): Promise<CustomerListResult> { ... }
}

API — enhance GET /users:

  • Query params: q (optional string), offset (default 0), limit (default 20)
  • Response: { items: CustomerSummary[], total: number }
  • Serialize userId as id to match frontend Customer type

Frontend changes

api-client.tscustomersApi.list() already passes offset, limit, q. Update return type to include total.

customers/page.tsx — set total from API response: setTotal(data.total).

Boundaries

  • No new module — stays in users module
  • No migration needed — identity_users already has email, role (migration 003)
  • Domain layer stays DB-free (ports pattern)
  • Admin-only endpoint (already gated by requireRole('admin'))

Files to change

  1. project/src/modules/users/domain/profile.ts — add CustomerSummary, CustomerListResult
  2. project/src/modules/users/domain/ports.ts — add listCustomers() to ProfileRepository
  3. project/src/modules/users/application/profile-use-cases.ts — add ListCustomers
  4. project/src/modules/users/infrastructure/pg-profile-repository.ts — implement listCustomers()
  5. project/src/modules/users/api/users.routes.ts — enhance GET /users
  6. project/apps/admin/src/lib/api-client.ts — update return type
  7. project/apps/admin/src/app/(dashboard)/customers/page.tsx — wire total