# Features — flutterflow_sync

Evidence date: 2026-10-15. Source: `git@bitbucket.org:overdrive/flutterflow_sync.git`, `main` at `8525b9f` (2025-09-04, "first commit").

Status words used here:

- **Current** — source is on `main` at `8525b9f` and the behaviour is in that source.
- **Stub** — a type, route, or method exists and does not perform the behaviour its name or the README describes.
- **Documented only** — stated in README, changelog, or NewKnowledgeBase, and not present in code.
- **Planned** — an unchecked changelog roadmap item.
- **Not in git** — named by a link or by the onboarding scan, and no file exists at that path.

There is one commit and one branch. Nothing in git history is a removed feature. Deployment of `main` is **Unknown / Requires Confirmation**. The processes were not started in this investigation. Startup wiring defects are in `technical-documentation.md`; features below describe the source as written.

## Current

### Sync engine

| Feature | Location | Notes |
|---|---|---|
| Four sync buckets | `server/src/config/syncConfig.js` | `global`, `user_data`, `user_stores`, `user_store_data`. SQL matches `sync_rules.yaml` with `{{placeholders}}` instead of `bucket.*` |
| Pull via Supabase RPC | `syncManager.executeQuery` | `execute_sync_query` |
| Local JSON tables | `createTableIfNotExists`, `storeQueryResults` | One MySQL table per remote name. Row body is JSON |
| Pending write queue | `routes/data.js`, `processPendingChanges` | INSERT, UPDATE, DELETE |
| Per-user socket room | `server.js` | `user_<supabase user id>`. Events `sync_started`, `sync_completed`, `sync_error` |
| Socket-triggered sync | `server.js` `request_sync` | Calls `handleClientSyncRequest` |
| In-memory and Redis stats | `syncManager` | `sync_stats` cached 3600 seconds |
| Sync metadata and logs | `initializeSyncTables` | Status enum `pending`, `syncing`, `completed`, `error` on metadata. Log levels `info`, `warn`, `error`, `debug` |
| Active-user periodic sync | cron `*/5 * * * *` | Users with `sync_metadata.updated_at` in the last 24 hours |
| Retention cleanup | cron `0 2 * * *` | 7-day pending changes and resolved conflicts; 30-day metadata and logs |
| Batch size | `config.BATCH_SIZE` | Default 100. Loop still executes one INSERT per row |

### HTTP API

| Feature | Location | Notes |
|---|---|---|
| `GET /health` | `server.js` | Process uptime and npm version. No dependency check |
| `GET /api/auth/health` | `routes/auth.js` | Supabase `getSession`. README lists this as POST |
| `POST /api/sync/trigger` | `routes/sync.js` | Manual sync for the token user |
| `GET /api/sync/status` | same | Metadata rows for the token user |
| `GET /api/sync/history` | same | Same table, with limit and offset |
| `GET` and `POST /api/data/:tableName` | `routes/data.js` | Read local JSON; enqueue a write |
| Upload, list, delete files | `routes/upload.js` | See file features |
| Helmet, compression, CORS | `server.js` | CORS origins from `CORS_ORIGINS` |
| Rate limit on `/api/` | `server.js` | 100 requests / 15 minutes / IP. Env keys unused |
| 10MB JSON body | `server.js` | |

### Files

| Feature | Location | Notes |
|---|---|---|
| Single and multiple upload | `routes/upload.js` | Max 10 files, 10MB each |
| Type allow-list | `fileUploadService.js` | jpeg, png, gif, webp, pdf, text, doc, docx |
| Resize and thumbnail | `processImage` | Route asks for 1200×800 quality 85 and a thumbnail. Sharp output is JPEG. Service default of 800×600 is overridden by the route |
| Metadata row and pending insert | `routes/upload.js` | Table `file_uploads` |
| Delete file and queue Supabase delete | same | Also tries to unlink a thumbnail |

### Dashboard

| Feature | Location | Notes |
|---|---|---|
| Login / logout / session check | `Login.tsx`, `dashboardAuth.js`, `routes/dashboard.js` | Shared env credentials |
| Overview cards and bar chart | `Overview.tsx` | Polls every 30 seconds. Chart.js bar of the current counters, not a time series |
| Sync status table and per-user trigger | `SyncStatus.tsx` | |
| Log filter, search, CSV download | `Logs.tsx` | Search filters the fetched array in the browser. CSV is built in the browser |
| User aggregate and trigger | `UsersList.tsx` | Not an account editor |
| Health page | `Health.tsx` | MySQL, Redis, Supabase flags, uptime, memory. Redis lookup calls a property `SyncManager` does not have |
| Responsive shell | `Dashboard.tsx` | Tailwind sidebar, mobile drawer |

### Flutter client

| Feature | Location | Notes |
|---|---|---|
| Init, socket, Supabase | `flutterflow_sync_client.dart` | Socket auth token is the current session access token at connect time |
| trigger, read, write, status | same | |
| upload, list, delete files | same | `dart:io` `File` |
| Action wrappers and batch helpers | `flutterflow_sync_actions.dart` | Batch helpers loop `writeData` |
| Search, count, exists, latest, date range | same | Built as `where` strings passed to read |
| Widgets | `flutterflow_sync_widgets.dart` | Status, button, connection, progress, list, file, image, gallery |
| Package manifest | `client/pubspec.yaml` | `flutterflow_sync_client` 1.0.0. Depends on `supabase_flutter`, `http`, `socket_io_client`, `image_picker`, `file_picker` |

### Operator docs in the source repo

| Feature | Location | Notes |
|---|---|---|
| README setup, API list, Flutter samples | `README.md` | |
| Changelog 1.0.0 narrative and roadmap | `CHANGELOG.md` | |
| Knowledge-base narrative | `NewKnowledgeBase.md` | Claims several controls the code does not contain. Treated as notes, not as implementation |
| FlutterFlow setup, existing-app, actions, widgets guides | `docs/*.md` | Paste-in instructions. Sample widget code in the guides is not the library source |

### Deployment files

| Feature | Location | Notes |
|---|---|---|
| Compose: MySQL 8, Redis 7, server, nginx dashboard | `docker-compose.yml` | MySQL mount `./server/sql/init.sql` is **not in git** |
| Server image | `server/Dockerfile` | Node 18 Alpine, non-root user, `HEALTHCHECK` via `healthcheck.js`. `npm ci` with no lockfile in git |
| Dashboard image | `dashboard/Dockerfile`, `dashboard/nginx.conf` | Multi-stage Vite build, nginx, `/api/` proxy, its own `/health` string |
| Env template | `env.example` | Placeholders for Supabase, MySQL, Redis, JWT, session, dashboard, CORS, sync, rate limit, log level |
| PM2 one-liner | README | Not a committed process file |

## Stub

| Feature | Location | Notes |
|---|---|---|
| Conflict storage | `sync_conflicts` table, `GET /dashboard/api/conflicts` | Nothing inserts a row or sets `resolution` / `resolved_at`. No screen |
| Supabase Storage upload | `uploadToSupabase` | Returns a URL string. No storage API call. No caller |
| Midnight "log rotation" | `server.js` cron | Writes a Winston info line |
| `data_updated` socket event | Client listens. Server never emits it | |
| Pending-changes API | `GET /dashboard/api/pending-changes` | No screen calls it |
| Settings icon | `Dashboard.tsx` imports `Settings` | No settings route |
| Line chart | `Overview.tsx` imports `Line` | Only `Bar` is rendered |
| JWT issue/verify | `auth.js` imports `jsonwebtoken` | Not called |
| Bucket parameter queries | `syncConfig.js` `parameters[].query` | Not executed. `request.user_id()` never runs |
| Dashboard session gate on the HTML app | `server.js` `dashboardAuth` | JSON routes under `/dashboard/api` are registered without that middleware |

## Documented only

| Claim | Where |
|---|---|
| Device offline cache and automatic sync when the phone reconnects | README, changelog, NewKnowledgeBase |
| Conflict strategies, last-write-wins, manual resolution UI | Changelog, NewKnowledgeBase |
| Exponential backoff | Changelog, NewKnowledgeBase |
| Incremental sync | Changelog |
| Joi validation and parameterised SQL as a general rule | NewKnowledgeBase. Some statements use placeholders; table names, `where`, `orderBy`, and sync substitutions do not |
| Dashboard WebSocket live logs | README, changelog |
| Tests of every layer | Changelog. No test files |
| CI/CD pipeline | NewKnowledgeBase. No pipeline file |
| Microservices, service discovery, alerting, event sourcing | NewKnowledgeBase and changelog architecture section |
| Password hashing of the configured dashboard password | Changelog. Code compares with bcrypt and does not hash the env value on startup |
| `POST /api/auth/health` | README. Route is GET |
| Working default login `admin` / `admin123` | README, Compose default |

## Planned

From `CHANGELOG.md` checkboxes. None are referenced by a TODO in code. None are scheduled outside that file.

### 1.1.0

- Advanced conflict resolution
- Real-time data subscriptions
- Enhanced dashboard analytics
- Mobile monitoring app
- API versioning

### 1.2.0

- Multi-region deployment
- Advanced caching
- Data compression
- Enhanced security
- Performance monitoring improvements

### 2.0.0

- Rewrite
- GraphQL
- Analytics and reporting
- Machine learning
- Enterprise features

## Not in git

| Path | Why it is named |
|---|---|
| `docs/api.md` | README documentation list |
| `docs/deployment.md` | README documentation list |
| `docs/troubleshooting.md` | README documentation list |
| `LICENSE` | README "MIT License" |
| `server/sql/init.sql` | `docker-compose.yml` volume |
| `package-lock.json` (server and dashboard) | Dockerfiles run `npm ci` |
| `sonar-project.properties`, `sonarqube_scan.bat` | Onboarding issue file list from the scan host. Not in `8525b9f` |
| Test files, Bitbucket pipeline, ESLint config, PM2 file | Scripts or prose name them |

## Recently changed

The only commit is the initial add of the whole tree on 2025-09-04. There is no earlier revision and no later one.

## Deprecated / removed

Changelog: "None (initial release)" for breaking changes, deprecations, and bug fixes. Git has no deleted paths.
