# Project plan — flutter_app (Datafy Ai)

Evidence date: 2026-10-15.

Source: `https://bitbucket.org/overdrive/flutter_app.git`, branch `develop`, commit `7d303449744ed14e8e5777c840c695bc37427c5f` (`7d30344`, 2026-04-13, `chore: bump version to 1.0.79+100103 [skip ci]`).

OVER-119 recorded an older tip, `75ce743` (2026-02-06, `IOS deploy remove retro`). That commit is still in history. It is not `HEAD`. The scan-host path `~/projects/sonar_scan/repos/flutter_app` was not on the machine used for this inspection. Evidence is a single-branch clone of `develop`.

There is no prior `silicon_ark/flutter_app/` directory.

## Product

The user-facing name is **Datafy Ai**. Android launcher label and iOS display name are **Datafy**. The Dart package is `datafy_ai`. Android application id and iOS bundle id are `coza.datafy.web`. `pubspec.yaml` version on this commit is `1.0.79+100103`.

`pubspec.yaml` description is the Flutter default: "A new Flutter project." `README.md` title is "Datafy Ai" and does not state a customer problem in one sentence. The implemented product is a retail field-execution client: representatives work a selected brand's stores (tasks, promotions, KaChing challenges, surveys), including offline, and admins use online screens for the same work.

Provenance of the names and version: **Implemented**. Provenance of the field-execution purpose: **Inferred** from screens, schema, and the README changelog. A signed product statement is **Unknown / Requires Confirmation**.

## Objectives

No project-plan file in the repository states objectives. The following are inferred from what the app does:

1. Let a signed-in Rep select a brand (customer) and work that brand's stores.
2. Let a Rep complete store tasks, specials (promos), KaChing challenges, and surveys, including while offline.
3. Let an Admin do the same work online against Supabase, without PowerSync.
4. Keep a store's tasks, promos, and KaChing rows from appearing under another store.
5. Ship Android from `develop` to the Play production track, and ship iOS to TestFlight from a custom pipeline.

Provenance: **Inferred**, except item 5, which is **Implemented** in `bitbucket-pipelines.yml` and the Fastfiles. Whether production (rather than an internal track) is the approved release target conflicts with `README.md`. See Discrepancies.

## Scope

In this repository:

- Flutter client for Android, iOS, and a `web/` tree.
- Local PowerSync schema, sync-rule source file, and upload/query services.
- Three Supabase SQL migrations.
- Bitbucket Pipelines, Fastlane, SonarQube project key, and store-deploy notes.

Not in this repository:

- The Supabase project schema as a whole. The client has generated table classes and three migrations. Most tables are assumed to already exist in Supabase.
- PowerSync Dashboard state. `sync_rules.yaml` is the copy that the README says must be pasted into the dashboard. Whether the live dashboard matches the file is **Unknown / Requires Confirmation**.
- `../COMPREHENSIVE_SCOPE.md` and `../documentation/`, which `README.md` cites. Those paths are outside the git tree.
- A backend that creates tasks, promos, or KaChing rows. This repo consumes and updates them.

## System shape

```text
Rep or Admin
    |
    | Supabase Auth (email/password; phone is stored as {digits}@datafy.co.za)
    v
Flutter client (package datafy_ai)
    |
    |-- Admin path: Supabase PostgREST + Storage (online)
    |
    |-- Rep path, after brand tap:
            PowerSync (local SQLite) <--> Supabase
            Attachment queue for photos (local_only attachments_queue)
    |
    v
Play production track (develop pipeline)
TestFlight (custom iOS pipeline, self-hosted macOS)
```

Default Supabase URL in code: `https://datafy.appmonitor.co.za`. PowerSync URL in code: `https://67c1c2c9586c8d282a0669f2.powersync.journeyapps.com`.

## Major components

| Component | Role | Evidence | Status |
|---|---|---|---|
| Auth and login | Phone-as-email or email, plus password. Location permission required before profile load | `lib/pages/includes/auth/login/` | Implemented |
| Brands | Customer list. Rep starts PowerSync only after a brand is chosen | `lib/pages/rep/dashboard/brands/` | Implemented |
| Rep store work | Stores, categories, tasks, promos, KaChing, surveys, galleries | `lib/pages/rep/` | Implemented |
| Admin store work | Parallel screens, Supabase, route guard `requireAdmin` | `lib/pages/admin/`, `lib/flutter_flow/nav/nav.dart` | Implemented |
| PowerSync | Offline DB, sync, attachment upload | `lib/services/powersync/`, `sync_rules.yaml`, `lib/app_constants.dart` | Implemented in the client. Dashboard deploy is a manual step |
| Force update | Service and overlay exist. Startup does not call them | `lib/services/force_update_service.dart`, `lib/main.dart` | Present, not active |
| CI | `develop` builds an Android App Bundle and uploads to Play production. `main` runs SonarQube only | `bitbucket-pipelines.yml` | Implemented |

SPAR, SUPERSPAR, and KWIKSPAR have extra list and category screens. Other channels use the general screens. DISCHEM is inserted by a migration into `channel_data`. The full channel list lives in Supabase and was not exported here.

## Milestones

No milestone plan is in the repository. History that can be dated:

| When | What | Evidence |
|---|---|---|
| 2025-09-09 | Root commit `b0f0d78`, message `Initial commit` | Git |
| 2026-01-27 | Second root `92a719f`, message `Initial commit: Datafy AI Flutter app` | Git. Two roots means the history was joined from more than one start |
| 2026-02-06 | `75ce743` `IOS deploy remove retro` | Commit cited by OVER-119. Ancestor of current `HEAD` |
| 2026-02 (migration timestamps) | Survey region/channel columns, photo id on promo/KaChing, DISCHEM channel row | `supabase/migrations/` |
| 2026-04-13 | `develop` tip `7d30344`, version `1.0.79+100103` | Git, `pubspec.yaml` |

`develop` has 120 commits on this clone. The only remote branch this clone fetched is `origin/develop`. Other remote branches were not listed. **Unknown / Requires Confirmation.**

## Implementation plan

There is no forward plan in the repo. Current delivery behaviour:

1. A push to `develop` runs the Android release build, bumps the patch version in three pubspecs, commits that bump with `[skip ci]`, and pushes it back when the pipeline is allowed to push.
2. Fastlane lane `production` uploads the AAB to the Play **production** track.
3. After a successful upload, the pipeline PATCHes Supabase `version` where `id=1`, column `app_version`, when `SUPABASE_SERVICE_ROLE_KEY` is set.
4. iOS is not on the `develop` pipeline. Custom pipelines `build-ios` and `deploy-ios-testflight` need a self-hosted macOS runner labelled `self.hosted` and `macos`. TestFlight lane is `beta`.

Provenance: **Implemented**.

## Dependencies

- Flutter stable image `ghcr.io/cirruslabs/flutter:stable`. SDK constraint `>=3.0.0 <4.0.0`.
- Supabase (`supabase_flutter` 2.9.0) for auth, data, and storage bucket `media`.
- PowerSync 1.14.1 and `powersync_attachments_helper`.
- Path packages `dependencies/ff_commons` and `dependencies/ff_theme` (comment in `pubspec.yaml` says 1.0.54+84; CI rewrites their `version:` line with the app version).
- Play Console service account and an Android upload keystore, supplied as Bitbucket secured variables.
- App Store Connect API key for TestFlight, also Bitbucket variables.
- SonarQube on `main` only (`sonar-project.properties` key `overdrive_flutter_app_70dee6c4-fe61-42b4-b37c-c566c62a3aec`).

A default Supabase anon key is compiled into `lib/backend/supabase/supabase.dart`. The key is not copied into Silicon Ark. Human review should confirm whether that default is still valid and whether it should remain in git.

## Current status

Active client on `develop` at version `1.0.79+100103` (2026-04-13). No commit after that date is on this branch.

`assets/environment_values/environment.json` still says `appVersion` `1.0.38`. That value is loaded by `FFDevEnvironmentValues` and no other Dart file reads `.appVersion`. The Play/pipeline version is `pubspec.yaml`.

Force update is not called from `main.dart`. The pipeline still writes `version.app_version`.

Automated tests: `test/widget_test.dart` pumps `MyApp` and does not assert product behaviour. The file comment still describes a counter.

## Discrepancies

| Topic | README | Code / pipeline |
|---|---|---|
| Android release track | "deploy to Play Store internal testing" | Fastlane `track: "production"` and step name "Deploy to Play Store (Production Track)" |
| iOS on `develop` | "`develop` branch runs Android and iOS" | `develop` runs Android build and production deploy only. iOS is a custom pipeline |
| Force update | Removed from startup; files kept | Matches `main.dart`. Pipeline still updates `app_version` |
| Scope docs | `../COMPREHENSIVE_SCOPE.md` and `../documentation/` | Not in this git repository |

Which Play track customers actually receive, and whether the README or the Fastfile is the approved rule, is **Unknown / Requires Confirmation**.

## Human confirmation

- Product owner, customer, and the one-sentence purpose.
- Whether Play production is intentional.
- Whether the PowerSync dashboard matches `sync_rules.yaml`.
- Whether the committed Supabase anon-key default should stay in source.
- Whether `main` is a release branch. This clone only has `develop`. Sonar is configured for `main`.
- Contents of the external scope and documentation folders named by the README.
