# PRD — greenfields

Evidence date: 2026-10-13.

Source: `git@bitbucket.org:overdrive/greenfields.git`, `main` at `3918f17f956e7adb3655d65662eba8ef517ead93` (2024-05-13, `deploy`).

There is no prior PRD in the source repository or in Silicon Ark under `greenfields/`. Requirements below are recovered from the implementation and the short README. Provenance is labelled. Secrets (Supabase anon key value, Resend API key) are not reproduced.

Provenance labels: **Documented**, **Implemented**, **Inferred**, **Planned**, **Unknown / Requires Confirmation**.

## Product purpose

**Documented.** README: `CEI Application V2`, FlutterFlow / Flutter web build.

**Implemented.** The web surface brands as **Greenfields** (`web/index.html` title and meta). The MaterialApp title is `Silicon Overdrive `. Copy across wizards describes collecting company and AWS-related information for Silicon Overdrive sharing with AWS, and a follow-up email from `greenfields@overdrive.co.za` for a "Scale-readiness roadmap report" and network join.

**Inferred.** Primary product job: AWS partner lead intake (business + startup tracks) plus a light authenticated community/portal shell.

Customer owner, programme name, and whether the portal is in production use are **Unknown / Requires Confirmation**.

## Users and roles

No role table or role enum exists in the Flutter table models. Actors are separated by workflow, not by an application RBAC model.

| Actor | Behaviour | Provenance |
|---|---|---|
| Anonymous visitor | Lands on `StepStart` when not logged in (`/` initial route). Can open public wizard routes. | **Implemented** (`nav.dart`, `main.dart`) |
| Business lead applicant | Completes Step1→Step3→Step4→Step5→Step6 without Supabase Auth; data held in `FFAppState` then inserted into `lead`. | **Implemented** |
| Startup applicant | Enters email + contact number; must match a `lead` row; then StartupStep1–4 insert into `startup`. | **Implemented** (`wizzard/login`) |
| Authenticated portal user | Supabase email/password account; app inserts `user` and `company` on create-account path. | **Implemented** (`app_login`, auth managers) |
| Operator / internal mailbox | Receives HTML email of unsent `lead` and `startup` rows via Edge Function. | **Implemented** (`auto_email`) |
| Deploy operator | Bitbucket Pipelines uses FTP credentials from pipeline variables. | **Implemented** |

**Important gap — Implemented:** `FFRoute.requireAuth` defaults to `false`, and no route in `nav.dart` sets `requireAuth: true`. Router-level auth redirect to `/stepStart` is therefore unused. Portal pages that query `currentUserUid` may run without a session; expected UX when unauthenticated is **Unknown / Requires Confirmation**.

Social sign-in mixins (Apple, Google, Facebook, Microsoft, GitHub, phone) exist in `auth_manager.dart` but are not mixed into `SupabaseAuthManager`. Provenance: **Planned** / unused scaffolding, not active product behaviour.

## Systems the product talks to

1. **Supabase** — Auth, PostgREST tables, Edge Functions. Project URL hardcoded in `lib/backend/supabase/supabase.dart` (ref `zbocxsdglolhcijqyyuy`).
2. **Resend** — Edge Function posts mail; API key from `RESEND_API_KEY`. From address in code: `onboarding@resend.dev`. To: `cei.silicon@gmail.com`.
3. **jsonkeeper.com** — `AWSServicesListCall` GET `https://www.jsonkeeper.com/b/GO8J` for AWS service options.
4. **Static image hosts** — `https://greenfields.overdrive.co.za/images/…` and legacy `https://greenfields.medmin.co.za/images/…`.
5. **FTP host** — pipeline deploy target (credentials not in repo).

No first-party REST API of this app's own is defined beyond calling Supabase and the two HTTP helpers above.

## Main workflows

### W1 — Choose journey

Trigger: open app while logged out (`/` → `StepStartWidget`).

Behaviour:

1. UI shows journey choice imagery from `greenfields.overdrive.co.za`.
2. "BUSINESS APPLICATION" navigates to the business wizard (`Step1`).
3. "START-UP BUSINESS APPLICATION" navigates to `StartupLogin`.

Provenance: **Implemented** (`step_start_widget.dart`).

### W2 — Business lead wizard

Trigger: navigation to `Step1` from journey chooser (or other links).

Steps (go_router names):

| Step | Route | Collects (via `FFAppState`) | Next |
|---|---|---|---|
| 1 | `/step1` | Company name, website, tagline, sector choice | `Step3` (skips `Step2`) |
| 2 | `/step2` | Sector UI (legacy medmin images) | Reachable if opened; not on primary forward path from Step1 |
| 3 | `/step3` | Country, city, zipcode (geo tables available) | Step4 |
| 4 | `/step4` | Name, WhatsApp/cell, email, job title, LinkedIn, X | Step5 |
| 5 | `/step5` | Introduction / AWS-related questions and consent-style text | Step6 |
| 6 | `/step6` | Source chips, opt-in switch → `LeadTable().insert` | Success |

On Success page load, `AutoSentEmailCall` GETs the Edge Function. Copy tells the user to expect mail from `greenfields@overdrive.co.za` and offers navigation to `StartupLogin`.

Provenance: **Implemented**. Step numbering in UI ("step 1 of 4") does not match six routes — **Inferred** copy lag / FlutterFlow artefact.

Field `lead.otp` stores the opt-in bool (**Implemented** naming). Server-side enforcement of consent is **Unknown**.

### W3 — Startup wizard (soft identity)

Trigger: `StartupLogin` / embedded wizard `LoginWidget`.

1. Query `lead` by email and cell/contact number.
2. On match: proceed to `StartupStep1`…`StartupStep4`.
3. On failure: `LoginError` UI.
4. Final step inserts `startup` with AWS account, root email, credits, hosting, spend, services list, budgets, tech stack, compliance, accelerator, maintenance, workload, contact fields, `sent`.
5. Success page again triggers `AutoSentEmailCall`.

Provenance: **Implemented**. This is not Supabase Auth.

### W4 — Create portal account / sign in

Trigger: `/appLogin` (and related login widgets under `lib/pages/login/`).

1. Sign in: Supabase `signInWithPassword`.
2. Create account: Supabase sign-up; on success path inserts `user` (id = auth uid) and `company` (linked by `user_id`). Navigation uses `pushNamedAuth` toward the posts list.
3. Password forget: Supabase `resetPasswordForEmail` (`PasswordForget` route).
4. Profile: sign out, email/password change helpers, link to `MoreDetails` for company fields.

Provenance: **Implemented**. Email confirmation behaviour depends on Supabase project settings (**Unknown** from client alone). Create-account path is not a DB transaction — partial insert failure mode is **Inferred** risk.

### W5 — Portal usage

Bottom navigation (`NavBarPage` in `main.dart`) includes Applications (default), List/posts, Profile, Support, notifications, FAQ (exact tab set as coded).

| Area | Behaviour | Provenance |
|---|---|---|
| Applications | "AWS Programs" / "Grow your startup with AWS"; loads company for current user; navigates to `StartupApplication` | **Implemented** |
| Posts | List posts for `currentUserUid`; create via `Post` | **Implemented** |
| Dashboard | Route exists; shows static/hardcoded content (e.g. `$4,204`) | **Implemented** placeholder |
| Notifications | Route exists; no live data source observed | **Implemented** shell |
| Support / FAQ | Support form UI; FAQ copy about AWS Activate | **Implemented** |
| MoreDetails | Update `company` fields | **Implemented** |

### W6 — Operator notification batch

Trigger: GET Edge Function `auto_email` (from Success pages; also invokable without JWT per deploy notes).

1. Select all `lead` where `sent = 0` and all `startup` where `sent = 0`.
2. Build HTML tables.
3. Send one email via Resend (`subject: New Lead`).
4. Update all matching rows to `sent = 1`.

Provenance: **Implemented**. Any completion can flush **all** pending rows — batch semantics are **Implemented**, not per-record.

## Functional requirements

### FR-001 — Public journey entry

Requirement: An unauthenticated user opening `/` sees the journey chooser, not the portal shell.

Evidence: `createRouter` initial `/` builder chooses `StepStartWidget` when not logged in.

Implementation: **Implemented**. Confidence: High.

### FR-002 — Persist business lead

Requirement: Completing the business wizard writes a `lead` row with company, location, contact, source, opt-in, and `sent` defaulting as coded.

Evidence: `LeadTable` / `step6_widget.dart` insert.

Implementation: **Implemented**. Confidence: High.

### FR-003 — Persist startup application

Requirement: After lead match, completing the startup wizard writes a `startup` row with AWS and project fields.

Evidence: `StartupTable` / startup step4 insert.

Implementation: **Implemented**. Confidence: High.

### FR-004 — Soft gate startup wizard

Requirement: Startup wizard proceeds only when email + contact match an existing lead.

Evidence: `wizzard/login/login_widget.dart`.

Implementation: **Implemented**. Confidence: High. Strength of identity (no OTP) is a product risk — **Requires Confirmation** if stronger auth is expected.

### FR-005 — Notify operators of new submissions

Requirement: Unsent leads/startups are emailed to the configured operator address and marked sent.

Evidence: `auto_email/index.ts`, `AutoSentEmailCall`.

Implementation: **Implemented**. Confidence: High for code path; live mailbox correctness **Unknown**.

### FR-006 — Portal account

Requirement: Users can register and sign in with email/password; profile and company records are created/updated.

Evidence: auth managers, `user` / `company` tables, profile widgets.

Implementation: **Implemented**. Confidence: High for happy path.

### FR-007 — Share data with AWS (consent)

Requirement: UI states Silicon Overdrive will share information with AWS and may contact the user; opt-in control on step 6.

Evidence: consent strings on step5/step6; `otp` field.

Implementation: **Implemented** as UI + stored flag. Legal/process fulfilment outside the app is **Unknown**.

### FR-008 — Web deploy on main

Requirement: Pushing `main` builds Flutter web and uploads to FTP.

Evidence: `bitbucket-pipelines.yml`.

Implementation: **Implemented** in CI definition. Live host URL **Unknown**.

## Constraints and non-functional observations

| Topic | Observation | Provenance |
|---|---|---|
| Search indexing | `robots: noindex` on web | **Implemented** |
| Auth guard | No `requireAuth: true` routes | **Implemented** gap |
| Edge Function JWT | Deployed with `--no-verify-jwt` per `supabase/readme.txt` | **Documented** |
| Secrets in repo | `supabase/.env` committed; anon key in Dart source | **Implemented** risk |
| Tests | Boilerplate counter-style widget test only | **Implemented** |
| Naming drift | CEI package vs Greenfields web title vs Silicon Overdrive app title | **Implemented** |

## Discrepancies

| Topic | Evidence A | Evidence B |
|---|---|---|
| Product name | README / pubspec `CEI Application V2` | Web title `Greenfields` |
| Success email brand | UI: `greenfields@overdrive.co.za` | Edge Function From: `onboarding@resend.dev`, To: `cei.silicon@gmail.com` |
| Related repo | Hostname `greenfields.*` | Silicon Ark `greenfields_web` is Transactflow EDI — not proven same product |
| Wizard step count | UI "step 1 of 4" | Six business wizard routes; Step1 skips Step2 |

## Unknown / Requires Confirmation

1. Production URLs and whether FTP deploy is still active.
2. Supabase RLS and whether anon key can read/write all rows.
3. Whether portal features (posts, dashboard metrics, notifications) are meant to be production-ready or demos.
4. Meaning of package name CEI and programme ownership.
5. Whether Android/iOS builds are released.
6. Relationship of `lib/pages/step1/` (non-wizard duplicate) to the live flow — not exported from `lib/index.dart`.
