Summary

Reported in sequence, as three separate complaints:

  1. “If I create a crew linked to an event it doesn’t get created!”
  2. “No wait, it gets created but I can’t see it. And clicking the invite errors.”
  3. “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:

LayereventId
create_crew_screen._submitCrewdid not pass it
CrewNotifier.createCrewparameter absent
CrewRepository.createCrewparameter absent
CrewService.createCrewaccepts 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_id lost, 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 in crew_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 with where 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: _open treated “no route” as “then it must be a place” and opened Google Maps searching the title. A crew is not a place. Only SharedKind.place falls 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.

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