## KoolTap Flutter App — Planned Tab Sync Add support for **planned tab names** that are synced from the server. The server now returns a `plannedTabNames` list in the sync response. The app should create open tabs for any planned names that don't already have an open tab. ### Background The dashboard admin can manage a list of "planned customers" (e.g. "Jan", "Marie", "Thomas"). These names are sent to the device in every sync response. The device should ensure those tabs exist — creating new ones if a planned name doesn't already have an open tab. ### Existing Files (read these first) - `lib/models/remote_command.dart` — contains `SyncResponse`, `RemoteCommand`, `SnapshotTab`, etc. - `lib/services/remote_sync_service.dart` — the sync loop that processes the sync response - `lib/services/bar_tab_service.dart` — creates and manages tabs (has `createTab(String customerName)`) - `lib/models/bar_tab.dart` — the `BarTab` model - `lib/database/app_database.dart` — the Drift database schema - `lib/viewmodels/remote_sync_view_model.dart` — wraps the sync service as `ChangeNotifier` - `lib/utils/app_config.dart` — server URL constant ### What to Change #### 1. Update `SyncResponse` model In `lib/models/remote_command.dart`, add `plannedTabNames` to the existing `SyncResponse` class (it already exists — add the field): ```dart class SyncResponse { final String cursor; final List commands; final List plannedTabNames; // ← add this SyncResponse({ required this.cursor, required this.commands, required this.plannedTabNames, // ← add this }); factory SyncResponse.fromJson(Map json) => SyncResponse( cursor: json['cursor'] as String, commands: (json['commands'] as List) .map((e) => RemoteCommand.fromJson(e as Map)) .toList(), plannedTabNames: (json['plannedTabNames'] as List?) // ← add this ?.map((e) => e as String) .toList() ?? [], ); } ``` #### 2. Process planned names in the sync service In `lib/services/remote_sync_service.dart`, inside the `_performSync()` method (or wherever the sync response is handled), add logic to process `plannedTabNames` **after** commands are processed but **before** updating the cursor. The logic: ```dart // After processing commands and before updating cursor: // Ensure planned tabs exist for (final name in response.plannedTabNames) { final hasOpenTab = openTabs.any((t) => t.customerName == name); if (!hasOpenTab) { await barTabService.createTab(name); } } // Also: if a tab is open for a customer NOT in plannedTabNames, // should we close it? Probably not — just leave it. ``` Where `openTabs` is the list of currently open tabs (already available from `barTabService.getOpenTabs()` or similar). Look for `getOpenTabs()` in `BarTabService` or access the local database. #### 3. Handle the first sync (no existing tabs) On first sync, the device might have zero open tabs and receive a list of planned names. The code should create tabs for all planned names. ### Important Notes - `BarTabService.createTab(String customerName)` already exists — it opens a new tab with version 1. Call it directly. - Do NOT close existing tabs that aren't in the planned list — planned tabs are additive only - If a planned name already has an open tab (same `customerName`), skip creating it - The sync service already tracks `openTabs` — it sends them in the `SyncRequest` via `SnapshotTab`. You can get the current open tabs from the local database using `BarTabService.getOpenTabs()` or `BarTabService.openTabs` stream - This logic should run inside the existing sync loop, after processing commands but before saving the cursor ### Testing - Add "Jan" and "Marie" as planned names in the dashboard - Run a sync on the Flutter app — tabs for "Jan" and "Marie" should appear - Remove "Jan" from planned names and re-sync — the "Jan" tab should NOT be closed (planned tabs are additive only) - Add a new name "Thomas" — a new tab should appear on next sync ### Files to Modify - `lib/models/remote_command.dart` — add `plannedTabNames` field to `SyncResponse` - `lib/services/remote_sync_service.dart` — add planned tab creation logic in sync loop