Routes
Status: Scaffolded 2026-09-24
Every path the site answers, in three groups: public pages anyone can load, the /app area that needs a session, and the three text routes for crawlers and agents.
Public
| Route | Renders | Data |
|---|---|---|
/ | landing: what Vegan Grove is, this week's public events, the map teaser | GET /api/stats, GET /api/events |
/places | the map, filters by type and vegan level, a list for the current viewport | GET /api/places?bbox= from the browser as the map moves |
/places/[slug] | one place: name, type, vegan level, address, hours, photos, reviews | GET /api/places/:slug |
/events | upcoming public events by area and date | GET /api/events |
/events/[slug] | one event: when, where as far as the organizer allows, who is hosting, RSVP count | GET /api/events/:slug |
/groves and /groves/[slug] | groves by area, and a grove's description with its public events | GET /api/groves |
/media and /media/[slug] | the documentary and film library, click-to-load trailers | GET /api/media |
/guides and /guides/[slug] | outreach, rights, vegan 101, sanctuary, nutrition | GET /api/guides |
/login, /signup | forms posting to the session route handler | |
/privacy, /terms | static |
Public pages are server-rendered, never carry a session, and are cacheable. Nothing on them is personalized.
Authenticated: /app
src/app/app/layout.tsx renders the member shell and is behind middleware.ts, which redirects a request without the vg_session cookie to /login?next=<path>. Inside:
| Route | Purpose |
|---|---|
/app/feed | friends, grove, or public scope |
/app/messages | conversations, Socket.IO for live updates |
/app/friends | friends, requests, invite codes |
/app/companion | Ivy, streaming over SSE |
/app/settings | handle, avatar, home area, the privacy switches, sessions, delete account |
All five are stubs in the scaffold: the layout, the gate, and the navigation exist; the screens render placeholders.
There is no profile route
There is no /u/[handle], no /members, no /app/profile/[id]. Profiles are never public (ADR 0004), and a member's own profile is /app/settings. If a public-posts view ships later it will read GET /api/handles/:handle/posts, show the handle, the avatar, and those posts, and nothing else: no bio, no area, no friends, no counts, and it will not be called a profile.
Machine-readable routes
/robots.txt (src/app/robots.ts): allow everything public, disallow /app and /api, point at the sitemap. Generated so the sitemap URL follows NEXT_PUBLIC_SITE_URL.
/sitemap.xml (src/app/sitemap.ts): the static public routes plus every approved place, published event, grove, media item, and guide, fetched from the API at request time and revalidated hourly. Nothing under /app, and no handle pages, because there are none.
/llms.txt (src/app/llms.txt/route.ts): a plain-text description of the site for language-model agents, with the public routes and a link to these docs. It says what the site is and where the public data lives; it does not enumerate members or anything behind a session.
Not found and errors
not-found.tsx and error.tsx at the app root render on the site's own shell. A place or event the API answers 404 for, whether missing or not visible to the caller, renders the same not-found page; the web app does not try to tell the difference, matching the error-handling rule.