Skip to content

Fix public route and entity resolution invariants - #587

Merged
kelvinkipruto merged 1 commit into
mainfrom
claude/issue-574-948130
Jul 20, 2026
Merged

Fix public route and entity resolution invariants#587
kelvinkipruto merged 1 commit into
mainfrom
claude/issue-574-948130

Conversation

@kelvinkipruto

Copy link
Copy Markdown
Contributor

Closes #574

What changed

Route grammar & 404s

  • Added src/lib/routes/publicRoutes.ts — a pure, documented resolver for the [...slugs] catch-all grammar (tenant: /, /:entitySlug, /:entitySlug/:pageSlug, /:pageSlug; global: / and /:pageSlug only).
  • The catch-all page now calls notFound() for every non-matching path. /unknown (no matching entity or page), /unknown/about, and 3+ segment paths return real 404s instead of silently rendering the entity selector.

Entity resolution

  • Fixed slugField overwriting slugOverrides.hooks, which silently disabled the ensureUniqueSlug beforeValidate hook on political entities — per-tenant slug uniqueness is now actually enforced.
  • Added a verification migration that fails loudly if pre-existing duplicate (tenant, slug) pairs exist.
  • BlockRenderer now passes the route-resolved entity object to blocks; promise-list and latest-promises blocks use it directly instead of re-resolving by slug without tenant scoping (previously a cross-tenant slug collision could resolve the wrong entity). Their fallback slug lookup is now tenant-scoped.

Promise lists

  • The main promise list previously fetched with no limit, so Payload silently capped it at 10 records. It now deliberately requests all published promises (pagination: false) via a shared, tested query builder; the teaser list keeps its explicit limit: 3.

Branded error handling

  • Added (frontend)/not-found.tsx and (frontend)/error.tsx (Sentry-instrumented) so 404s/500s get branded pages while preserving HTTP semantics via notFound().

Migrations

  • migrations/20260720_000000_check_political_entity_slug_uniqueness.ts — verification only; throws with a list of duplicates if any exist, no data changes.

Tests

  • tests/int/publicRoutes.int.spec.ts — route matrix: tenant, global, entity, duplicate-slug, and invalid paths.
  • tests/int/politicalEntitySlugs.int.spec.ts — slug field keeps the uniqueness hook; hook rejects duplicates per tenant.
  • tests/int/promiseListQuery.int.spec.ts — pagination behavior of the promise list query.
  • Full int suite: 122/122 passing; tsc --noEmit clean.

🤖 Generated with Claude Code

- Add documented catch-all route grammar with pure resolvers; all
  non-matching paths (e.g. /unknown/about, 3+ segments) now 404
- Preserve slugOverrides hooks in slugField so ensureUniqueSlug runs
- Pass the resolved entity object to blocks; promise-list blocks no
  longer re-resolve entities by slug without tenant scoping
- Deliberately disable pagination on the main promise list instead of
  silently truncating at Payload's default page size
- Add branded (frontend) not-found and error pages
- Add migration verifying no duplicate per-tenant entity slugs
- Add route-matrix, slug-uniqueness, and pagination tests

Closes #574

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
PromiseTracker Ready Ready Preview, Comment Jul 20, 2026 6:35am

Request Review

@kelvinkipruto
kelvinkipruto merged commit 33b0347 into main Jul 20, 2026
5 checks passed
@kelvinkipruto
kelvinkipruto deleted the claude/issue-574-948130 branch July 20, 2026 06:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix public route and entity resolution invariants

1 participant