# Business rules — greenfields

Evidence date: 2026-10-13. Source: `main` at `3918f17`.

Rules below are taken from application and Edge Function behaviour. Rules that are only implied are marked **Inferred**. Rules that cannot be established are marked **Unknown / Requires Confirmation**. Do not treat this file as a legal or compliance source of truth.

## Access and identity

### BR-001 — Anonymous lead intake is allowed

**Rule:** A visitor can complete the business application wizard without creating a Supabase account.

**Evidence:** Public routes for StepStart and Step1–Step6; insert uses table client without requiring `loggedIn`.

**Provenance:** **Implemented**.

### BR-002 — Startup track requires matching lead contact details

**Rule:** Startup wizard continues only when the submitted email and contact number match an existing `lead` row.

**Evidence:** `lib/pages/wizzard/login/login_widget.dart` queries `LeadTable` and navigates to `StartupStep1` or shows login error.

**Provenance:** **Implemented**. Strength of this check (no password/OTP) is a product decision — **Requires Confirmation** if stronger verification is expected.

### BR-003 — Portal uses Supabase email/password accounts

**Rule:** Portal users authenticate with email and password via Supabase Auth. Social providers are not active.

**Evidence:** `SupabaseAuthManager` / `email_auth.dart`. Social mixins not applied.

**Provenance:** **Implemented**.

### BR-004 — Router auth flag is unused

**Rule (observed):** No go_router route sets `requireAuth: true`, so the redirect-to-`/stepStart` path for protected routes never runs.

**Evidence:** `lib/flutter_flow/nav/nav.dart` route list vs `FFRoute.requireAuth` default.

**Provenance:** **Implemented** behaviour (gap relative to typical portal expectations). Intended policy **Unknown / Requires Confirmation**.

## Data capture and consent

### BR-005 — Lead is written only at the end of the business wizard

**Rule:** Intermediate steps store values in in-memory `FFAppState`; persistence to `lead` occurs on Step6 submit.

**Evidence:** `lib/app_state.dart`, step6 insert.

**Provenance:** **Implemented**. Refresh/close before Step6 loses data — **Inferred**.

### BR-006 — Opt-in flag is stored on lead

**Rule:** Step6 presents an opt-in control (default observed as opted in in UI state) and stores it on `lead.otp`.

**Evidence:** step6 widget; `LeadRow.otp` maps column `otp`.

**Provenance:** **Implemented**. Whether backend rejects `otp = false` is **Unknown**. Column name `otp` vs "opt" is a naming inconsistency — **Implemented**.

### BR-007 — Sharing with AWS is disclosed in UI

**Rule:** Consent copy states Silicon Overdrive will share information with AWS and that Silicon Overdrive or AWS may contact the user; unsubscribe is mentioned in the text.

**Evidence:** Strings on step5/step6 widgets (including typo "Silicon Overdriv").

**Provenance:** **Implemented** as disclosure text. Operational unsubscribe process **Unknown**.

### BR-008 — Startup record includes contact identity from soft login

**Rule:** Startup rows carry `contact_email` and `contact_number` (and AWS/project fields) for the applicant who passed the lead match.

**Evidence:** `startup.dart` fields; startup step inserts.

**Provenance:** **Implemented**.

## Notification and operations

### BR-009 — Unsent rows are batched to a fixed mailbox

**Rule:** When `auto_email` runs, every `lead` and `startup` with `sent = 0` is included in one HTML email, then all such rows are updated to `sent = 1`.

**Evidence:** `supabase/supabase/functions/auto_email/index.ts`.

**Provenance:** **Implemented**.

### BR-010 — Notification recipients and sender in code

**Rule (as coded):** Email goes to `cei.silicon@gmail.com` from `onboarding@resend.dev` with subject `New Lead`.

**Evidence:** same Edge Function.

**Provenance:** **Implemented**. Whether this matches the user-facing promise of mail from `greenfields@overdrive.co.za` is a **discrepancy** — **Requires Confirmation**.

### BR-011 — Edge Function may be invoked without JWT verification

**Rule (deploy guidance):** Function is served/deployed with `--no-verify-jwt`.

**Evidence:** `supabase/readme.txt`.

**Provenance:** **Documented** in repo. Anyone who can hit the URL can trigger the batch — **Inferred** risk if the function is publicly reachable.

## Portal domain rules

### BR-012 — New account creates user and company rows

**Rule:** On successful create-account path, a `user` row (id = auth uid) and a `company` row (`user_id` = auth uid) are inserted.

**Evidence:** app login create-account handlers.

**Provenance:** **Implemented**. Atomicity across the two inserts is not guaranteed — **Inferred**.

### BR-013 — Posts belong to the authenticated user id

**Rule:** Post list/create uses `currentUserUid` as `user_id`.

**Evidence:** posts list/post widgets; `post.dart`.

**Provenance:** **Implemented**. Server-side ownership enforcement depends on RLS — **Unknown**.

### BR-014 — Company profile fields support AWS startup narrative

**Rule:** More-details UI asks for registration year, technical contacts, website, and a description framed for AWS Startup credit eligibility / accelerator motivation.

**Evidence:** `more_details_widget.dart` labels.

**Provenance:** **Implemented** as form copy. Eligibility decisions are not automated in this repo — **Unknown**.

## Validation

### BR-015 — Client-side required fields

**Rule:** Wizard and form widgets use FlutterFlow form validation patterns (required labels, controllers). Exact mandatory set per field is defined in each `*_widget.dart` / model, not in a central rules engine.

**Provenance:** **Implemented** per page. Exhaustive field matrix not duplicated here.

### BR-016 — No application-level role permissions

**Rule:** There is no coded role (admin vs member) gating routes or menus.

**Evidence:** absence of role fields on `user` table model; nav tabs shared.

**Provenance:** **Implemented** (lack of RBAC). Desired roles **Unknown / Requires Confirmation**.

## Naming / data quirks affecting rules

| Quirk | Impact | Provenance |
|---|---|---|
| `lead.otp` for opt-in | Misleading column name | **Implemented** |
| `startup.montly_budget` | Typo in schema/field | **Implemented** |
| `xtwiter` on lead | Typo for X/Twitter | **Implemented** |
| Dashboard `$4,204` | Not a business calculation | **Implemented** placeholder |

## Conflicts with Silicon Ark `greenfields_web`

Silicon Ark documents `greenfields_web` as a Transactflow / Admin Overdrive EDI system with company buyer/seller roles. Those business rules do **not** apply to this Flutter repository unless a human confirms a shared product. Hostname overlap alone is insufficient.
