Summary
Reported in sequence, as three separate complaints:
- “If I create a crew linked to an event it doesn’t get created!”
- “No wait, it gets created but I can’t see it. And clicking the invite errors.”
- “And I can’t search for it, but if I search for anything else it shows up.”
They looked like three bugs. They were one cause plus two independent ones.
Root Cause
CrewService.createCrew has always accepted eventId and inserted it into
crews.event_id. Nothing upstream could pass it:
| Layer | eventId |
|---|---|
create_crew_screen._submitCrew | did not pass it |
CrewNotifier.createCrew | parameter absent |
CrewRepository.createCrew | parameter absent |
CrewService.createCrew | accepts and writes it — never received it |
Everything else in the chain worked: the route reads ?eventId=, the wizard
loads the event and pre-fills from it, the state preserves it through
copyWith, and the UI even renders a different step sequence when it is set
(_stepsLinked vs _stepsStandalone). The submit call dropped it.
Verified in production: 0 of the 8 most recent crews carried an event_id.
The vibe "Market" on four of them proves the pre-fill really ran — the
event’s category was inherited — so the link was lost downstream, not upstream.
Why the symptom appeared to change
The crew_must_have_anchor CHECK requires a crew to be anchored to an event, a
venue or an area.
- With
event_idlost, a crew created from an event had no anchor → the insert was rejected → “it doesn’t get created”. - Someone fixed that by adding the current city as a fallback (
areaFallback, see the comment increw_notifier.dart). The insert then succeeded — with the event link still missing → “it gets created but I can’t see it”, because the event page lists crews withwhere event_id = ….
Warning
The symptom moved, the cause did not. The database constraint was reporting the real bug and the fix silenced it.
Fix
eventId (and venueId, equally unreachable until now) added to
CrewRepository.createCrew and CrewNotifier.createCrew;
create_crew_screen._submitCrew passes wizardState.linkedEventId.
Bug 2 — Routes That Do Not Exist
Introduced 31 July with feature-chat-sharing.
SharedContent.route pointed crews at /crew/:id, which does not exist in
app_router.dart, and profiles at /profile/:id when the real route is
/user/:userId — /profile is a shell branch with fixed children
(settings, my-crews…), so /profile/<uuid> matches nothing.
GoRouter throws on an unknown route, so the card errored under the user’s finger. Not a dead link: a crash.
Crews now return no route, because there genuinely is nowhere to send them:
they open through showCrewDetailSheet, which needs a Crew object rather
than an id. The invite’s join button still works, which is the action that
matters.
Note
That change exposed another:
_opentreated “no route” as “then it must be a place” and opened Google Maps searching the title. A crew is not a place. OnlySharedKind.placefalls through to maps now.
Bug 3 — Crew Search Matched the Wrong Column
search_screen.dart searched crews with ilike on vibe_tag, while
events search title and venues search name. Typing a crew’s name found
nothing; typing its genre would have found it.
Now or(title.ilike, vibe_tag.ilike), with the term stripped of , ( ) —
the characters PostgREST uses to delimit an or filter. Leaving them in turns
a search like “rock, techno” into a malformed filter that fails the whole
query.
Verified in production: the old filter returns 0 rows for the crew created that evening, the new one returns 1.
Bug 4 — The Crew Chat Was Never Created
Full account in feature-crew-chat-lifecycle. In short:
_openCrewChat wrote to crews.chat_id, a column that did not exist, so
opening a crew chat always errored and every tap created another orphan chat.
One crew collected seven.
Cleanup performed with the user’s authorisation: 12 empty chats removed, 7 crews left with exactly one linked chat each, 47 messages still present, 0 chats without participants, 0 orphaned participant rows. No chat containing a message was touched.
Open Items
No regression test. CrewRepository constructs CrewService() directly
and CrewService reads Supabase.instance.client in a field initialiser, so
there is no seam to inject a fake through. Adding one is worth doing — this bug
class (a parameter that exists at the bottom of a stack and nothing passes
it) is invisible to flutter analyze and has now happened twice.
Existing crews stay orphaned. There is no way to guess which event they were meant to link to. They must be relinked by hand or recreated.
Related
fix-crew-creation-v2 — describes linked-event selection as working: it was, in the UI, not in the save feature-chat-sharing — origin of the wrong routes feature-crew-chat-lifecycle — the chat side of the same story