# Business rules — edi_shopfront (EDI ShopFlow / Transactflow Shopfront)

Evidence date: 2026-10-16.

Source: `git@bitbucket.org:overdrive/edi_shopfront.git`, `main` at `9d1d726`.

Rules below are taken from code, views, migrations, seeds, and README/overview. Each rule is marked **Documented** or **Inferred** (from implementation). Where two parts disagree, the conflict is stated. No rule was added because it "should" be true.

## Identity

**Inferred — BR-I1.** Operators using the shop and seller UI are working in an EDI / ShopFlow / Transactflow shopfront product. The README calls the same tree Admin Overdrive Starter.

**Documented — BR-I2.** `composer.json` describes the project as Transactflow with homepage Overdrive.

**Unknown / Requires Confirmation.** Canonical customer-facing product name.

## Access and authentication

**Inferred — BR-A1.** A request needs a session (`isLoggedIn`) unless the path is in the Authentication filter exception list (login/register, password reset, 2FA, unlock, `cronJobs`, `store-api` and children, `organisations` and children, `tracking-pixel`, `slack`, 404 helpers, etc.). Evidence: `app/Config/Filters.php`.

**Inferred — BR-A2.** A session is not enough for most pages. `isGranted` requires a matching menu grant for the role, with its own exception list (includes `home`, `Welcome/*`, `chatGPT/*`, `portal-selection`, `seller/logout`, and the auth exceptions). Evidence: `Filters.php`, `Authorization.php`.

**Inferred — BR-A3.** CSRF and honeypot filters are not applied globally. A logged-in browser session can post without a CSRF token.

**Inferred — BR-A4.** Seeded roles are Developer, Admin, Company Admin, Company User. Evidence: `UserRole` seeder.

**Inferred — BR-A5.** Developer and Admin can see all companies; Company Admin is scoped to linked companies. Evidence: `Welcome::setCompanyUsersAndAdminSessionVars` (and related session setup).

**Inferred — BR-A6.** Users have `user_type` ∈ {Buyer, Seller, Buyer and Seller} and `default_portal` ∈ {Buyer, Seller}. Dual-type users must select a portal before continuing. Evidence: migration + Welcome + layout header.

**Inferred — BR-A7.** Seller portal menus are filtered using a `seller_portal` flag on menu rows. Evidence: migration + Authorization behaviour.

**Inferred — BR-A8.** Email 2FA and blocked-user flows can prevent or gate login completion. Evidence: 2FA routes, `email_authentication_codes`, blocked users list.

**Documented — BR-A9.** README setup expects `php spark db:seed Users` before use. Password values are omitted from this document.

**Inferred — BR-A10.** Organisations API and JWT login bypass the normal session menu model (filter-excepted). Evidence: Filters + Routes + JwtLibrary.

## Store and company context

**Inferred — BR-C1.** Buyer shopping operates in a current store context (`currentStoreID` session / store_users membership).

**Inferred — BR-C2.** Companies can be configured with transport method options (Folder / API / Email and related options in UI). Evidence: company transport method UI/controllers, `TransportMethodOptions` seeder.

**Unknown / Requires Confirmation — BR-C3.** Which transport method a given retailer/company must use in production, and who may change it.

## Ordering

**Inferred — BR-O1.** Creating an order requires an authenticated user and cart items. Evidence: `Orders::createOrder`.

**Inferred — BR-O2.** When an order is created from a cart, line items are grouped by the product's company (seller). Evidence: `Orders::createOrder`.

**Inferred — BR-O3.** Order types include Standard Order and JAB Order. Evidence: migrations on `orders` / `carts`.

**Inferred — BR-O4.** JAB orders distribute quantities across multiple stores. Evidence: `JabOrders.php`.

**Inferred — BR-O5.** Order header status must be one of: Pending, Scheduled, Partially Supplied, Successfull, Regret, Cancelled. Evidence: `OrdersModel` validation. The spelling **Successfull** is enforced by the application.

**Inferred — BR-O6.** Order item status must be one of: Pending, Successfull, Regret, Cancelled. Evidence: `OrderItemsModel` validation.

**Inferred — BR-O7.** Orders submitted to the external Store API are subject to config limits: max 100 items; currencies ZAR/USD/EUR/GBP; VAT rates 0, 0.15, 0.20, 0.25; max order value 1 000 000; rate limit 60 requests/minute. Evidence: `Config/StoreApi.php`.

**Inferred — BR-O8.** External submission uses retries (max 3, delay 5s) and a circuit breaker (opens after 5 failures for 5 minutes). Evidence: `ExternalOrderService.php`, `StoreApi` config.

**Inferred — BR-O9.** SSL verification for the Store API defaults to false in config. Whether production overrides this is **Unknown**.

## Pricing

**Inferred — BR-P1.** Price file applications move through approve/reject/apply/restore/revert style statuses before affecting live pricing. Evidence: price file application controllers/migrations.

**Inferred — BR-P2.** Mapping rules transform uploaded price file columns into product/price fields. Evidence: `PriceFileMappingRules`, `PriceFileTransformationService`.

**Unknown / Requires Confirmation — BR-P3.** Who may approve price file applications in each company (beyond menu RBAC).

## EDI and cron

**Inferred — BR-E1.** Cron is invoked via unauthenticated HTTP `GET cronJobs`, with a production security key check. Evidence: `CronJobs.php`, filter exceptions.

**Inferred — BR-E2.** Cron execution is limited to Monday–Friday between approximately 08:00 and 23:00. Evidence: `CronJobs::index`.

**Inferred — BR-E3.** Which jobs run is driven by active rows in `cronjob_actions` (function, recurrence, order). Evidence: cron tables + CronJobs.

**Inferred — BR-E4.** EDI document exchange supports Folder, SOAP (PnP, M2North), and REST (Shoprite) transports. Evidence: `GetXMLData`, `Soap`, `Rest`.

**Inferred — BR-E5.** Email transport for EDI orders/invoices is not fully implemented. Evidence: comments in `GetXMLData`.

**Unknown / Requires Confirmation — BR-E6.** Partner-specific business SLAs, acknowledgement rules, and who owns retailer credentials.

## Adverts and notifications

**Inferred — BR-N1.** Adverts can expire; a Spark command deactivates expired adverts. Evidence: `DeactivateExpiredAdverts`.

**Inferred — BR-N2.** System notifications can be read and dismissed per user. Evidence: notifications migrations/controller.

**Inferred — BR-N3.** Queued emails are stored in `sent_queue`; open tracking via public pixel can update processing state. Evidence: Email + EmailPixelTracking.

## Permissions model detail

**Inferred — BR-R1.** Authorization matches menu URL segments (up to three segments). Evidence: `Authorization.php`.

**Inferred — BR-R2.** Page actions include view/create/edit/delete/export style permissions via `PermissionConfig` / `PermissionService`. Evidence: those classes.

**Inferred — BR-R3.** AJAX requests may skip the menu grant check when the user is logged in. Evidence: Authorization filter behaviour noted in exploration; confirm against current `Authorization.php` when changing security policy.

## Documented starter rules that under-specify the product

**Documented — BR-D1.** README features list only authentication, authorization, registration, and menu management. The running system enforces many additional domain rules above. Treat README as starter documentation, not the business rule catalogue.

## Conflicts and confirmation list

| Topic | Conflict / gap |
|---|---|
| Product name | README vs composer vs ShopFlow branding |
| PHP version | README 8.3 vs composer ^8.0 |
| Order status labels | Model `in_list` vs any UI-only labels |
| CSRF | Disabled vs typical Overdrive security expectations |
| Payments | Table without gateway rules |
| Cron key | Hardcoded/production key handling — confirm rotation process |
| Email EDI | Documented incomplete in code comments |
