Places
Status: Proposed 2026-09-24, scaffolded in the API (list, get, submit, approve); ingest rules added 2026-09-29; lists, reviews, and check-ins match the API as of 2026-10-24
Places are The Trick Book's Spots with the sport swapped for the cause. A Place is a sanctuary, restaurant, cafe, grocery, shop, community garden, organization, or venue with a pin on the map, a vegan level, and community verification. Places are public and carry no member data, which makes them the safest feature to ship first.
Why
An activist new to an area asks three questions: where can I eat, where can I volunteer, where do people meet. A map that answers all three with data the community keeps honest is the reason to open the app on a Tuesday, which is what makes the Saturday action discoverable.
What ships in v1
- A map (MapLibre, OpenFreeMap tiles) with clustered pins, driven by the viewport's bounding box. The default view leans fully vegan:
veganLevel: fullonly, chains hidden. "Include vegan options" and "show chains" are opt-in toggles, and fully vegan places sort first everywhere. - A Place page: name, type, vegan level (
fulloroptions), address, postcode, hours, phone, website, tags (cuisine, wheelchair, outdoor seating, takeaway, delivery), photos, reviews, upcoming events at this place, and the source attribution. - Community gardens (
type: garden, alwaysfull) from OpenStreetMap, so a Grove can find a place to grow food together. - Submit a place (signed in): pin drop or address search, type, vegan level, a photo. Enters
pending; an admin approves. The submitter is never shown. - Reviews: rating, text, the month visited, and an opt-in to show the author's handle. One active review per member per place.
- Check-ins: a separate, anonymous confirmation of the vegan level, one per member per place per UTC month. The page shows the count and the latest month.
- Place lists: private collections ("want to try", "volunteer here").
isPublicis stored for future friend sharing and is not published yet. Another member's list, including one with the flag set, is not readable. - Farmers and produce markets from OpenStreetMap, stored as
grocerywith the tagmarket:farmers. See data sources. - Seed data: OpenStreetMap
diet:vegantags for the SoCal bounding box (531 tagged places at the time of writing) plus a curated sanctuary list, all imported aspendingand approved by hand. See data sources and the ingest rules for places.
Data and visibility
places (public once approved, including the check-in aggregates), place_reviews (public text, handle only if showHandle), place_checkins (one row per member per place per UTC month; only the aggregates are public), place_lists (the owner only; isPublic is stored and not a visibility grant yet). The data model has the schema. Geo queries are bounding-box only; no point ever leaves the device (ADR-0005).
API
GET /api/places?bbox=&type=&veganLevel=&includeChains=&q=, GET /api/places/map-pins (pins only, no cursor), GET /api/places/:slug, POST /api/places (member, pending), POST /api/ingest/places (ingest key, see ingest), GET/POST /api/places/:id/reviews, GET/POST /api/places/:id/check-ins, place-list routes under /api/place-lists (owner only), admin GET /api/admin/places/pending, PUT /api/admin/places/:id/approve|reject, and admin review hide and restore. The shapes, status codes, and the isPublic rule are on the API endpoints page. Public reads return approved places only; a non-approved place is visible to its submitter and admins, and a list can still embed a pending place its owner saved.
Screens
Web: /places (map plus list), /places/[slug]. Mobile: the Places tab (map with a list toggle), a place sheet, submit-a-place, my lists.
Verification
Community verification is what keeps the vegan level honest. See verification.
Open questions
- Hours: import from OSM when present, let members correct; do we show "hours unverified" until a member confirms?
- Claiming: a business can claim its Place to fix details. Claimed status is public; the claimant is not. Scope for M2 or later.