feat(customers): opt-in debug block on the omde lists, printed in the panel console

Sending X-Debug: 1 makes the five wholesale list endpoints return a counts-only
`debug` block next to the rows: the WHERE that actually ran, how many customers
the scope matches before the grid's own filters, how many customers exist per
kind/active/archived/step and how many are an expert's trading account. The
panel sends the header and console-logs the block when localStorage.debug === '1'.

Off by default; DIAG_LOG=false disables it server-side. No names or mobiles.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mahmood
2026-10-26 08:59:33 +03:30
co-authored by Claude Sonnet 5.5
parent ab39f6abed
commit 0156a976e7
4 changed files with 113 additions and 16 deletions
@@ -1,4 +1,4 @@
import { Body, Controller, Get, HttpCode, Param, Post, Put } from '@nestjs/common';
import { Body, Controller, Get, Headers, HttpCode, Param, Post, Put } from '@nestjs/common';
import { AdminCustomersService, type OmdeScope } from './admin-customers.service';
import { TableQueryDto } from '../admin-table/table-query.dto';
import { CurrentAdmin, RequirePermission, SuperAdminOnly } from '../auth/guards';
@@ -18,45 +18,47 @@ import type { AuthenticatedAdmin } from '../auth/jwt.strategy';
export class AdminCustomersController {
constructor(private readonly customers: AdminCustomersService) {}
private list(query: TableQueryDto, scope: OmdeScope) {
return this.customers.list(query, scope);
// `X-Debug: 1` (set by the panel when localStorage.debug === '1') adds a
// counts-only `debug` block to the response — see AdminCustomersService.listDebug.
private list(query: TableQueryDto, scope: OmdeScope, debug?: string) {
return this.customers.list(query, scope, debug === '1');
}
@Post('list')
@HttpCode(200)
@RequirePermission('persons.list.client.omde')
listAll(@Body() query: TableQueryDto) {
return this.list(query, 'all');
listAll(@Body() query: TableQueryDto, @Headers('x-debug') debug?: string) {
return this.list(query, 'all', debug);
}
@Post('banker/list')
@HttpCode(200)
@SuperAdminOnly()
@RequirePermission('persons.list.client.omde')
listBanker(@Body() query: TableQueryDto) {
return this.list(query, 'banker');
listBanker(@Body() query: TableQueryDto, @Headers('x-debug') debug?: string) {
return this.list(query, 'banker', debug);
}
@Post('shopkeeper/list')
@HttpCode(200)
@SuperAdminOnly()
@RequirePermission('persons.list.client.omde')
listShopkeeper(@Body() query: TableQueryDto) {
return this.list(query, 'shopkeeper');
listShopkeeper(@Body() query: TableQueryDto, @Headers('x-debug') debug?: string) {
return this.list(query, 'shopkeeper', debug);
}
@Post('non-verified/list')
@HttpCode(200)
@RequirePermission('persons.list.client.omde')
listNonVerified(@Body() query: TableQueryDto) {
return this.list(query, 'non_verified');
listNonVerified(@Body() query: TableQueryDto, @Headers('x-debug') debug?: string) {
return this.list(query, 'non_verified', debug);
}
@Post('archived/list')
@HttpCode(200)
@RequirePermission('persons.list.client.omde')
listArchived(@Body() query: TableQueryDto) {
return this.list(query, 'archived');
listArchived(@Body() query: TableQueryDto, @Headers('x-debug') debug?: string) {
return this.list(query, 'archived', debug);
}
/** Legacy POST single-customer — the retail customer list. */