fix(audit-wave-9): standardize on Sheet for previews; doctrine in CLAUDE.md

Swap the one outlier (client-interests-tab.tsx) from Vaul Drawer to
Sheet side=right so every detail-preview surface uses the same
primitive. Document the doctrine: Sheet for side panels on both desktop
and mobile; Vaul Drawer reserved for mobile-only bottom-sheet UX
(currently just MoreSheet).

Closes ui/ux M11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 11:50:07 +02:00
parent b2588ecdd8
commit 4233aa3ac3
94 changed files with 1674 additions and 895 deletions

View File

@@ -25,43 +25,52 @@ const BODY_MAX_BYTES = 1 * 1024;
// A 5xx in /api/v1/clients (create / update) was landing full client
// PII (full name, DOB, address, phone, nationality, email) in
// error_events.request_body_excerpt for the super-admin inspector.
// Extend to cover GDPR-relevant fields too.
const SENSITIVE_KEYS = new Set([
// Match fragments case-insensitively + snake/kebab-normalized so the
// redactor catches `recipientEmail`, `client_email`, `phone_number`,
// `tax_id`, `passwordHash`, etc. without an exhaustive enumeration.
const SENSITIVE_KEY_FRAGMENTS = [
// Credentials
'password',
'newPassword',
'oldPassword',
'token',
'secret',
'apiKey',
'accessKey',
'secretKey',
'creditCard',
'cardNumber',
'api_key',
'apikey',
'access_key',
'secret_key',
'credit_card',
'card_number',
'cvv',
'ssn',
'authorization',
'cookie',
// PII
'email',
'emails',
'phone',
'phoneNumber',
'mobile',
'whatsapp',
'dob',
'dateOfBirth',
'date_of_birth',
'birthdate',
'address',
'street',
'postcode',
'zip',
'nationalId',
'national_id',
'passport',
'taxId',
'fullName',
'firstName',
'lastName',
]);
'iban',
'tax_id',
'taxid',
'full_name',
'fullname',
'first_name',
'last_name',
'recipient',
];
function isSensitiveKey(key: string): boolean {
const k = key.toLowerCase().replace(/[-]/g, '_');
return SENSITIVE_KEY_FRAGMENTS.some((frag) => k.includes(frag));
}
/** Drop sensitive keys + cap the JSON length. */
function sanitizeBody(body: unknown): string | null {
@@ -77,7 +86,7 @@ function sanitizeBody(body: unknown): string | null {
if (value && typeof value === 'object') {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(value)) {
if (SENSITIVE_KEYS.has(k)) {
if (isSensitiveKey(k)) {
out[k] = '[REDACTED]';
} else {
out[k] = walk(v);