trails/apps/journal/app/routes.ts
Ullrich Schäfer e61179ab27 Implement notifications + supporting fixes
Adds the notifications system end-to-end (4 types, payload-versioned
JSONB, SSE-based live unread badge, /notifications page, mark-read API,
fan-out job for activity_published, daily 90-day retention purge).
Bell icon in the navbar with unread badge.

Side-findings from exercising the change:
- Add 6-digit magic code to registration (mirrors login UX, mobile
  paste-friendly), with `[Register Magic Link]` console line in dev so
  the code is reachable without a real email transport.
- Manual passkey/magic-link toggle on the register form (login already
  had it).
- Restrict ALPN to http/1.1 in HTTPS dev so React Router's
  singleFetchAction CSRF check (Origin vs. Host) passes — Node doesn't
  synthesize Host from h2's :authority. Plain HTTP dev unaffected.
- Followers/Following routes now use the locked-account rule from the
  profile route (owner + accepted followers see the list; others 404).
  Profile page renders the count chips as plain spans for viewers who
  can't see the lists, so private profiles don't surface dead links.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 01:28:55 +02:00

61 lines
3.6 KiB
TypeScript

import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/home.tsx"),
route(".well-known/trails-cool", "routes/api.well-known.trails-cool.ts"),
route("oauth/authorize", "routes/oauth.authorize.tsx"),
route("oauth/token", "routes/oauth.token.ts"),
route("auth/register", "routes/auth.register.tsx"),
route("auth/login", "routes/auth.login.tsx"),
route("auth/verify", "routes/auth.verify.tsx"),
route("auth/logout", "routes/auth.logout.tsx"),
route("auth/accept-terms", "routes/auth.accept-terms.tsx"),
route("api/auth/register", "routes/api.auth.register.ts"),
route("api/auth/login", "routes/api.auth.login.ts"),
route("routes", "routes/routes._index.tsx"),
route("routes/new", "routes/routes.new.tsx"),
route("routes/:id", "routes/routes.$id.tsx"),
route("routes/:id/edit", "routes/routes.$id.edit.tsx"),
route("api/routes/:id/callback", "routes/api.routes.$id.callback.ts"),
route("api/routes/:id/edit-in-planner", "routes/api.routes.$id.edit-in-planner.ts"),
route("api/routes/:id/gpx", "routes/api.routes.$id.gpx.ts"),
route("activities", "routes/activities._index.tsx"),
route("activities/new", "routes/activities.new.tsx"),
route("activities/:id", "routes/activities.$id.tsx"),
route("users/:username", "routes/users.$username.tsx"),
route("users/:username/followers", "routes/users.$username.followers.tsx"),
route("users/:username/following", "routes/users.$username.following.tsx"),
route("api/users/:username/follow", "routes/api.users.$username.follow.ts"),
route("api/users/:username/unfollow", "routes/api.users.$username.unfollow.ts"),
route("follows/requests", "routes/follows.requests.tsx"),
route("api/follows/:id/approve", "routes/api.follows.$id.approve.ts"),
route("api/follows/:id/reject", "routes/api.follows.$id.reject.ts"),
route("feed", "routes/feed.tsx"),
route("api/events", "routes/api.events.ts"),
route("notifications", "routes/notifications.tsx"),
route("api/notifications/:id/read", "routes/api.notifications.$id.read.ts"),
route("api/notifications/read-all", "routes/api.notifications.read-all.ts"),
route("settings", "routes/settings.tsx"),
route("api/settings/profile", "routes/api.settings.profile.ts"),
route("api/settings/email", "routes/api.settings.email.ts"),
route("api/settings/passkey/delete", "routes/api.settings.passkey.delete.ts"),
route("api/settings/delete-account", "routes/api.settings.delete-account.ts"),
route("sync/import/:provider", "routes/sync.import.$provider.tsx"),
route("api/sync/connect/:provider", "routes/api.sync.connect.$provider.ts"),
route("api/sync/callback/:provider", "routes/api.sync.callback.$provider.ts"),
route("api/sync/disconnect/:provider", "routes/api.sync.disconnect.$provider.ts"),
route("api/sync/webhook/:provider", "routes/api.sync.webhook.$provider.ts"),
route("privacy", "routes/privacy.tsx"),
route("legal/imprint", "routes/legal.imprint.tsx"),
route("legal/terms", "routes/legal.terms.tsx"),
route("legal/privacy", "routes/legal.privacy.tsx"),
// REST API v1
route("api/v1/routes", "routes/api.v1.routes._index.ts"),
route("api/v1/routes/compute", "routes/api.v1.routes.compute.ts"),
route("api/v1/routes/:id", "routes/api.v1.routes.$id.ts"),
route("api/v1/activities", "routes/api.v1.activities._index.ts"),
route("api/v1/activities/:id", "routes/api.v1.activities.$id.ts"),
route("api/v1/auth/devices", "routes/api.v1.auth.devices.ts"),
route("api/v1/auth/devices/:id", "routes/api.v1.auth.devices.$id.ts"),
route("api/v1/uploads", "routes/api.v1.uploads.ts"),
] satisfies RouteConfig;