Summary
Squad and Crew were two model stacks over the same crews table, with
two sets of names for the same columns and two services writing to it. Squad
has been deleted; Crew absorbed what it carried.
| DB column | Name in Squad | Name in Crew |
|---|---|---|
title | name | title |
valid_until | expiresAt | validUntil |
| member count | currentSize | memberCount |
Every new column had to be added twice. visibility was added twice on the
same afternoon it was created.
Key Decisions
It was not just duplication — the halves had drifted
SquadService.createSquad was a worse, divergent version of createCrew:
- it never set a title, so those crews were named after their own vibe tag — which is why the crew list had rows called after their genre;
- it wrote
area_name = vibe_tagas the anchor, producing crews anchored to Techno; - it hardcoded a 24h expiry instead of deriving it from the event end;
- it created its own chat with
metadata: {'squad_id': …}— a different key fromcrew_id, sosweep_crew_chats()would never have found those chats: they would never close and never be purged; - and since
trg_crews_create_chatnow creates the chat with the crew, that path would have produced two chats per crew, overwritingchat_idwith the second and orphaning the first.
Warning
The last point was a bug introduced the same morning by the trigger. It would have stayed invisible until someone created a crew from the feed.
One vocabulary, no aliases
Crew absorbed the derived state Squad carried: displayName (falls back to
the vibe for the nameless crews the old path created), isFull, spotsLeft,
isExpired, timeLeft, timeLeftLabel.
No name/title aliases were added. Two words for one field is the disease,
not the cure — it would have been enough to restart the drift.
The rename reached the l10n layer too
15 keys renamed off “squad”, and the English, Italian and Spanish copy with them. The UI still said “JOIN SQUAD” and “Leave the Squad?” while the code said crew.
Note
A rename that stops at the code layer does not resolve the confusion. It moves it onto the user.
Files Changed
Deleted:
| File | Why |
|---|---|
lib/shared/models/squad_model.dart | second model over the same table |
lib/features/social/services/squad_service.dart | second, divergent write path |
lib/features/social/repositories/squad_repository.dart | — |
lib/features/social/notifiers/squad_notifier.dart | duplicated CrewNotifier |
lib/features/social/screens/create_squad_sheet.dart | created nameless crews anchored to the vibe |
lib/features/social/providers/crew_provider.dart | a third stack (ChangeNotifier beside the StateNotifier), zero references anywhere |
app_config_service.squadExpiryHours | defined once, called never |
Renamed: squad_bento_section.dart → crew_bento_section.dart,
squad_detail_sheet.dart → crew_detail_sheet.dart.
−1171 lines, +319.
Architecture Notes
Fixed in passing: event_discovery_screen renders a crew section but never
asked for the crews. It drew whatever the feed had loaded on its own, so
opening discovery first showed an empty row. It now loads its own.
Open Items
chatsstill holds rows withmetadata.squad_idwritten by the old path. They are attached to no crew and the sweep does not see them. Worth checking and removing if empty.crews.titleis nullable and some historical rows are empty.displayNamecovers that on screen, but the column should become NOT NULL now that the only creation path always asks for it.
Related
feature-crew-chat-lifecycle — the trigger that made the double path actively harmful fix-crew-event-link — the preceding chain of bugs localization — renamed keys