chore(autonomous-session): consolidate uncommitted work from prior session

Bundles the prior autonomous-session output that was sitting unstaged:

- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
  never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
  after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
  redirects (ocr to ai, reports to dashboard, invitations to users),
  docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
  flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
  let-reassign), set-state-in-effect disables in CountryFlag and
  UploadForSigning preview-bytes effect, unused 'confirm' destructures in
  interest contract + reservation tabs, unescaped apostrophe in test-template
  card copy
This commit is contained in:
2026-05-23 00:52:59 +02:00
parent 43719b49e9
commit 221ae5784e
749 changed files with 7440 additions and 3118 deletions

View File

@@ -1,5 +1,5 @@
/**
* Port-scoped global reservations list locks in feat(marina): the new
* Port-scoped global reservations list - locks in feat(marina): the new
* `GET /api/v1/berth-reservations` endpoint that powers the
* `[portSlug]/berth-reservations` page. The route is thin (parseQuery →
* listReservations); the test guarantees port scoping at the handler

View File

@@ -36,7 +36,7 @@ describe('POST /api/v1/companies', () => {
const res1 = await createHandler(req1, ctx, {});
expect(res1.status).toBe(201);
// Same name with different case should still conflict.
// Same name with different case - should still conflict.
const req2 = makeMockRequest('POST', 'http://localhost/api/v1/companies', {
body: { name: name.toUpperCase() },
});

View File

@@ -94,7 +94,7 @@ describe('GET /api/v1/companies/[id]/members', () => {
);
expect(delRes.status).toBe(204);
// Default active only.
// Default - active only.
const activeOnlyRes = await listHandler(
makeMockRequest('GET', `http://localhost/api/v1/companies/${company.id}/members`),
ctx,
@@ -375,7 +375,7 @@ describe('POST /api/v1/companies/[id]/members/[mid]/set-primary', () => {
);
const m1 = ((await m1Res.json()) as any).data;
// M2, M3 not primary.
// M2, M3 - not primary.
const m2Res = await createHandler(
makeMockRequest('POST', `http://localhost/api/v1/companies/${company.id}/members`, {
body: {

View File

@@ -416,7 +416,7 @@ describe('PATCH /api/v1/berth-reservations/[id]', () => {
it('returns 403 when caller lacks reservations.cancel for cancel action', async () => {
const { port, reservation } = await seedReservation();
// Sales agent has activate but NOT cancel.
// Sales agent - has activate but NOT cancel.
const ctx = makeMockCtx({
portId: port.id,
permissions: makeSalesAgentPermissions(),

View File

@@ -1,5 +1,5 @@
/**
* Saved-views ownership enforcement locks in the 403/404 split shipped
* Saved-views ownership enforcement - locks in the 403/404 split shipped
* in fix(auth). The route handlers preflight `assertViewOwner` BEFORE the
* service call, so even if the service's internal userId filter is later
* refactored, the route still rejects cross-user mutations.
@@ -96,7 +96,7 @@ describe('saved-views ownership enforcement', () => {
it('PATCH on a view in a different port: 404 (cross-port enumeration is blocked)', async () => {
// The view exists in `portId` but the auth context says we're operating
// in a different port. The lookup is scoped to `(id, portId)` so the row
// is invisible should 404, not 403.
// is invisible - should 404, not 403.
const otherPort = await makePort();
const ctx = makeMockCtx({ portId: otherPort.id, userId: ownerUserId });
const res = await patchHandler(

View File

@@ -94,7 +94,7 @@ describe('PATCH /api/v1/yachts/[id]', () => {
// Validator strips owner fields, so we need to bypass it to reach the service's defensive guard.
// Test the service layer defense by calling the handler with a payload that the validator
// would accept but which also contains an unknown field that matches the forbidden keys.
// Actually the validator just omits `owner` additional keys `currentOwnerId` etc. pass
// Actually the validator just omits `owner` - additional keys `currentOwnerId` etc. pass
// through Zod's .partial() (which still omits unknown keys by default).
// Zod .strip() is default, so unknown keys are dropped: we assert on the service directly.
const { updateYacht } = await import('@/lib/services/yachts.service');
@@ -264,7 +264,7 @@ describe('GET /api/v1/yachts/[id]/ownership-history', () => {
expect(res.status).toBe(200);
const body = (await res.json()) as any;
expect(body.data).toHaveLength(2);
// Sorted DESC by startDate newest first
// Sorted DESC by startDate - newest first
const firstStart = new Date(body.data[0].startDate).getTime();
const secondStart = new Date(body.data[1].startDate).getTime();
expect(firstStart).toBeGreaterThanOrEqual(secondStart);

View File

@@ -82,7 +82,7 @@ describe('GET /api/v1/yachts (listHandler)', () => {
});
});
describe('POST /api/v1/yachts permission gate', () => {
describe('POST /api/v1/yachts - permission gate', () => {
it('viewer (no yachts.create) receives 403 through full pipeline', async () => {
const port = await makePort();
const client = await makeClient({ portId: port.id });