Replaces every em-dash and en-dash with regular ASCII hyphens
across comments, JSX strings, and dev-facing logs. Mostly cosmetic
but stops the inconsistent mix that crept in over the last few
months (some files used em-dashes in comments, others didn't,
some used both).
Bundles two small dashboard-layout tweaks that touch a couple of
already-modified files:
- (dashboard)/layout.tsx main padding goes from p-6 to pt-3 px-6
pb-6 so page content sits closer to the topbar.
- Sidebar now receives the ports list it needs for the footer
port switcher.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add server-side `<admin>/layout.tsx` that redirects non-super-admins to
`/[portSlug]/dashboard`. Closes the gap where any authed user could
guess the URL and reach Users / Roles / Audit Log / Backup.
- `withAuth` super-admin branch now 404s when the requested portId does
not match a real port row, preventing a compromised super-admin
session from operating against a fabricated portId.
- Portal JWTs now carry `aud: 'portal'` + `iss: 'pn-crm'` claims and
`verifyPortalToken` requires both, so a portal token can no longer be
replayed against the CRM session path or vice versa. In-flight tokens
(≤24h) will be invalidated once on deploy.
- `saved-views/[id]` PATCH and DELETE now do an explicit ownership
check before the service call, returning 403 instead of relying on
the service's internal userId filter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds three named rate limiters to the existing Redis sliding-window
catalog and a withRateLimit wrapper that composes inside withAuth.
Wires the OCR limiter into the receipt-scan endpoint so a runaway
client can't burn through the AI budget in a tight loop.
- ocr: 10/min/user
- ai: 60/min/user (reserved for future server-side AI surfaces)
- exports: 30/hour/user (reserved for GDPR bundle, PDF, CSV exports)
429 responses include X-RateLimit-* headers and a Retry-After hint.
Tests: 771/771 vitest (was 766) — +5 rate-limit tests covering catalog
shape, sliding window, cross-prefix isolation, cross-user isolation,
and resetAt timestamp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add yacht list + create routes, export RouteHandler type and inner
handlers so tests can invoke them directly with a mock AuthContext.
New tests/helpers/route-tester.ts provides makeMockCtx/makeMockRequest
reusable by subsequent Task 3.x routes.