Files
kooltab-backoffice/docs/flutter-integration-prompt.md
T
2026-09-20 02:35:57 +02:00

6.3 KiB

KoolTab Flutter App — Remote Backoffice Integration (Improved Pairing Flow)

You are implementing the device-side integration for the KoolTab remote tab control system. The Flutter app (bar POS terminal) needs to register with a remote backend, sync open tabs, and process remote close-tab commands.

Project Location

C:\Users\bram\StudioProjects\kooltab2

Architecture Overview

  • State management: provider (ChangeNotifier pattern)
  • Routing: go_router
  • Local DB: drift (SQLite ORM)
  • HTTP: http package
  • Auth tokens stored in flutter_secure_storage
  • MVVM pattern: views → viewmodels → services
  • Models in lib/models/
  • Services in lib/services/
  • ViewModels in lib/viewmodels/
  • Views in lib/views/
  • Config constants in lib/utils/app_config.dart
  • Main app bootstrap in lib/app/app_bootstrap.dart

Pairing Flow (improved)

Instead of typing a UUID venueId, the flow is:

  1. Tablet calls GET https://api.kooltab.com/api/v1/venues/ (public, no auth)
  2. Gets list of [{id, name}] — admin picks venue from a dropdown
  3. Admin enters device name (e.g. "Bar terminal 1")
  4. Admin enters the 6-character registration code (generated from dashboard)
  5. Tablet calls POST /devices/register with venueId + name + code
  6. Stores deviceId + token + venueId + serverUrl in secure storage
  7. Sync starts automatically

Existing Sync Infrastructure (already built)

Do NOT rewrite these files, just modify as needed:

  • lib/services/remote_sync_service.dart (410 lines) — setCredentials(), startSync(), stopSync(), sync loop, command processing, ACKs
  • lib/viewmodels/remote_sync_view_model.dart (90 lines) — ChangeNotifier wrapper
  • lib/models/remote_command.dart (135 lines) — DTOs: RemoteCommand, SyncRequest, SyncResponse, SnapshotTab, CommandAck
  • lib/utils/app_config.dart — URL constants
  • lib/models/payment_method.dart — payment enums

What to Build

1. Update Server URL

In lib/utils/app_config.dart:

const kRemoteServerUrl = 'https://api.kooltab.com/api/v1/';

2. Add Venue Model

Create lib/models/venue.dart:

class Venue {
  final String id;
  final String name;
  Venue({required this.id, required this.name});
  factory Venue.fromJson(Map<String, dynamic> json) => Venue(id: json['id'], name: json['name']);
}

3. Update RemoteSyncService — Add venueId Storage

In lib/services/remote_sync_service.dart:

  • Add venueId parameter to setCredentials() signature
  • Store venueId in FlutterSecureStorage alongside deviceId/token/serverUrl
  • Add String? get venueId getter
  • Update isConfigured to also check venueId exists
  • Add clearCredentials() method (clears all stored credentials)

4. Registration ViewModel

Create lib/viewmodels/registration_view_model.dart:

  • Future<List<Venue>> fetchVenues() — calls GET /api/v1/venues/
  • Future<void> registerDevice(String venueId, String name, String code) — calls POST /devices/register, then stores credentials via RemoteSyncService.setCredentials()
  • States: initial, loading, venuesLoaded, error, registered
  • Expose as ChangeNotifier

5. Registration UI

Create lib/views/registration_view.dart — a full-screen registration flow with steps:

Step 1 — Select venue:

  • Dropdown list of venues fetched from API
  • Show loading spinner while fetching
  • Show error + retry if fetch fails
  • "Next" button when venue selected

Step 2 — Device details:

  • Device name text field (with default "Bar terminal 1")
  • Registration code text field (6 characters)
  • "Register" button
  • Loading state while registering
  • Error display if registration fails

Step 3 — Success screen:

  • Success animation/message
  • "Start using KoolTab" button → navigates to main bar screen and triggers sync

6. Wire Registration into Navigation

In lib/app/app_bootstrap.dart:

  • On app startup, check remoteSyncService.isConfigured
  • If NOT configured: show registration screen instead of main bar screen
  • If configured: proceed to main bar screen as normal

In lib/app/router.dart:

  • Add route for registration screen as initial route when not configured

7. Disconnect Option

In the Settings screen (lib/views/settings_view.dart) or Admin screen:

  • If configured, show "Connected to [venue name]" with device name
  • "Disconnect" button → calls clearCredentials(), navigates back to registration screen

API Endpoints Summary

Method Endpoint Auth Purpose
GET /api/v1/venues/ None List venues (returns [{id, name}])
POST /api/v1/devices/register None Register device (body: venueId, name, registrationCode)
POST /api/v1/devices/:id/sync Bearer token Sync tabs, receive commands
POST /api/v1/devices/:id/commands/:cmdId/ack Bearer token Acknowledge command

Registration API Details

Venues list:

GET https://api.kooltab.com/api/v1/venues/
Response: [{"id": "uuid", "name": "KoolTab Demo Bar"}, ...]

Device registration:

POST https://api.kooltab.com/api/v1/devices/register
{
  "venueId": "uuid-from-venue-list",
  "name": "Bar terminal 1",
  "registrationCode": "A8F3C2"
}
Response 201:
{
  "deviceId": "uuid",
  "token": "dev_abc123...",
  "tokenExpiresAt": "2026-..."
}

The registration code is generated from the dashboard (Devices → Add Device → generates 6-char code valid for 10 minutes).

Files to Create

  • lib/models/venue.dart
  • lib/viewmodels/registration_view_model.dart
  • lib/views/registration_view.dart

Files to Modify

  • lib/utils/app_config.dart — update URL
  • lib/services/remote_sync_service.dart — add venueId + clearCredentials
  • lib/app/app_bootstrap.dart — check isConfigured, route to registration if not
  • lib/app/router.dart — add registration route
  • lib/views/admin_screen_view.dart or lib/views/settings_view.dart — add disconnect option

Important Notes

  • Do NOT break the existing sync loop — registration only configures credentials
  • The existing sync sends SnapshotTab and processes close_tab commands stays unchanged
  • Use flutter_secure_storage for persisting credentials
  • Handle loading/error states in the UI
  • After registration, call remoteSyncViewModel.start() to begin syncing
  • Tabs appear on the dashboard within ~90 seconds of first sync