# Project plan — edioverdrive (Transactflow)

Evidence date: 2026-10-16. Source: `https://bitbucket.org/overdrive/edioverdrive.git`, branch `main` at `a33b2b7883666a77dec925f0ba000642b1dd19ee` (2026-10-06, “Merged in feature/1063-boxer-niew-po-store-duplicate”, pull request #194).

This clone was shallow (`--depth 1`). History before that commit was not inspected. The onboarding issue (OVER-101, created 2026-09-28) recorded an older `main` tip, `d03ab9a4` (2026-02-02). Current `main` is later than that snapshot.

There is no prior Silicon Ark folder for this project. The repository already holds product and operations docs under `README.md`, `CHANGELOG.md`, `STORE_API_DOCUMENTATION.md`, `NewKnowledgeBase.md`, and `scope/`. This plan summarises those sources and the code. It does not replace the per-company flow maps.

## Product

Transactflow (repository name **edioverdrive**, README title **Admin Overdrive Starter**, composer package `codeigniter4/adminstarter`, composer description **Transactflow**) is an EDI operations hub. It receives purchase orders, invoices, order responses, and claims from retailers (buyers) and suppliers (sellers), normalises them, and sends them onward on the partner’s channel.

Provenance: **Documented** (`composer.json` description, `README.md`, `scope/company_flow_maps/System_Functionality_Overview_For_Business_Article.md`).

Public hosts named in operations docs:

| Environment | Host | Evidence |
|---|---|---|
| Production admin | `https://admin.transactflow.io/` | `scope/Task_CronJobs_Implementation_Overview.md` |
| QA admin | `https://qa.transactflow.io/` | same, and Store API base URL |
| Local | `http://edioverdrive.local/` | `README.md`, `env` `app.baseURL` |

Whether every customer uses those hosts is **Unknown / Requires Confirmation**.

## Objectives

Documented objectives, from the business overview and the go-live policy:

- Collect orders, invoices, order responses, and claims from mixed channels (API/SOAP/REST, FTP/SFTP, folder drop, email-style handoff, ShopFlow).
- Parse each payload into a shared internal model and route it by buyer–seller link and transport settings.
- Give suppliers one process that can serve several retailers with different technical formats.
- Leave an audit trail (payload archives, cron logs, error logs) so operations can see failures and reprocess where the flow allows it.
- Onboard a new buyer or seller only after company, store, vendor-code, transport, and access records are in place (`scope/Policy_New_Client_Integration_Go_Live.md`).

## Scope

### In scope (implemented on `main`)

- Web admin for companies, stores, vendor numbers, products, orders, invoices, claims, order responses, reports, documents, fault finding, monitoring, users, and system settings.
- Scheduled engine at `GET /cronJobs` that runs jobs defined in `cronjob_actions`.
- Storefront JSON API (`POST /store-api/createOrder`, `POST /store-api/getInvoices`) with organisation JWT login.
- Per-company parsers and exporters selected by `company_transport_methods.docs_type` and `method_identifier`.
- Email and authenticator-app (TOTP) two-factor authentication, password policy, and password-rotation email.
- QA and production deploy by Bitbucket Pipelines `git ftp push`. A third pipeline branch, `storefront`, deploys to a shop QA FTP host.

### Out of scope for this knowledge set

- Live database contents. Company IDs, transport rows, and buyer–seller links in `scope/company_flow_maps/README.md` are a **QA snapshot dated 2026-07-06** (`transactflow_qa_1`). They can differ from production and from later code (see discrepancies).
- Commercial pricing. A billing report and `clients_billing` table exist. The price list and who is billed are **Unknown / Requires Confirmation**.
- Jira board `SI` and Confluence space `AO`, linked from `README.md`. Those sites were not read.

### Not a current integration

`app/Helpers/salesforce_helper.php` (`salesforceConnect`) and `app/Helpers/africastalking_helper.php` (`smsMessage`) are empty or fully commented. No caller was found under `app/`. Salesforce and SMS are **not** active integrations. The SMS file’s comments contain credential-like material. That material is **not** copied here. Human review should confirm it was never a live key and remove it from Git.

## System architecture

```text
Buyers / sellers / storefront
        |  REST, SOAP, FTP, folder, email-style, ShopFlow, Store API JSON
        v
CodeIgniter 4 app (public/ front controller)
        |
        +-- Session UI (filters: maintenance, isLoggedIn, isGranted)
        +-- GET /cronJobs  (own key check in production; not session-authenticated)
        +-- Organisations JWT + Store API
        v
MySQL / MariaDB (MySQLi)  +  writable/ payload folders
        |
        v
Outbound transports back to the partner, plus email / Slack notifications
```

Major components:

| Component | Role | Evidence |
|---|---|---|
| `GetXMLData` | Inbound parse and save for orders, invoices, claims, order responses | `app/Controllers/GetXMLData.php`, go-live policy |
| `Orders`, `Invoices`, `Claims`, `OrderResponses` | Admin lists, export, reprocess | controllers of those names |
| `CronJobs` | Engine, heartbeat, exports, reports, notifications | `app/Controllers/CronJobs.php` |
| `Company`, `Clients`, `Products` | Master data and trading links | controllers and models |
| `StoreApiController`, `Organisations` | JSON storefront API and JWT | `STORE_API_DOCUMENTATION.md` |
| `FaultFinder` | Data-quality checks and notification mail | `app/Controllers/FaultFinder.php` |
| `SystemSettings` | Cron, email, holidays, blocks, fault types, transports | `app/Config/Routes.php` |
| `Documents` / `DocumentBrowserService` | Browse archived payloads | `app/Services/DocumentBrowserService.php` |
| `MakroM2NorthSoapService`, `FtpService` | Partner-specific transports | `app/Services/` |

`companies.type_desc`: `1` buyer, `2` seller. `clients` links `buyer_id` and `seller_id`. Provenance: **Documented** (`scope/company_flow_maps/README.md`).

## Known trading partners (QA snapshot, not a live inventory)

Buyers with flow maps: Pick n Pay (1), Shoprite (8), Makro (9), Dis-Chem (20), Boxer (21), Metro (22).

Sellers with flow maps: Godrej SA (7), Mello Foods NAM (11), DGB SA (12), DGB Bacardi SA (13, stub), Blue Sky Brands (15), Niew Beverages (18), Dala Art (19).

Provenance: **Documented**, QA database on 2026-07-06. Reconcile with the database the environment’s `.env` points at before treating IDs as production fact.

## Milestones and current status

No formal milestone plan is in the repository. Status is inferred from `main`, `CHANGELOG.md` (section **Unreleased**), and temporary comments in code.

| Area | Status | Evidence |
|---|---|---|
| Core order / invoice hub | In production use | Pipelines deploy `main` and `qa`; cron docs name prod and QA hosts |
| Order-response ingest (DGB → Makro CSV, hub `respondOrder`) | Implemented | `CHANGELOG.md`, `GetXMLData` |
| Generic order-response **export** cron | Placeholder | `Orders::exportOrderResponsesViaCron` returns “No order-response export pipeline is configured for this company yet.” |
| Company Admin access to Order Responses | Temporarily blocked | `app/Filters/Authorization.php`, `app/Views/layouts/sidebar.php` |
| Password storage split (`user_passwords`) | Phase 1, dual-write | `CHANGELOG.md`, migrations `2026-05-08-*` |
| PHP floor | Conflicting docs vs `composer.json` | See discrepancies |
| SonarQube pipeline step | Present but commented out | `bitbucket-pipelines.yml` |
| Changelog | Unreleased changes not cut as a version | `CHANGELOG.md` has only `[Unreleased]` |

## Implementation plan (as the repo describes it)

New partner work follows `scope/Policy_New_Client_Integration_Go_Live.md` and `scope/company_flow_maps/Code_Integration_Guide_New_Company_Flows.md`:

1. Create company, stores, GLNs or buyer codes, and `vendor_numbers` where the payload uses a buyer-assigned supplier code.
2. Create an active `clients` row for each buyer–seller pair.
3. Create `company_transport_methods` rows (`orders`, `invoices`, `orders_responses`, `claims`) with the `docs_type` the parser expects.
4. Extend `GetXMLData` / `Invoices` / `Soap` / `Rest` only when an existing parser cannot be reused.
5. Sign off on QA before enabling the transport in production.
6. Deploy with the Bitbucket pipeline for `qa` or `main` (`git ftp push`). Migrations are a manual step in the QA-to-prod checklists under `scope/qa_to_prod_deployments/`.

## Dependencies

- PHP constraint in `composer.json`: `^8.4` (platform pin `8.4.0`). README and the unreleased changelog say 8.3. See discrepancies.
- CodeIgniter 4 `^4.7`.
- MySQL or MariaDB via MySQLi (local onboarding doc names MariaDB).
- Composer packages: `mpdf/mpdf` `^8.1`, `phpoffice/phpspreadsheet` `^5.6`, `league/csv` `^9.16`, `robthree/twofactorauth` `^3.0`, `bacon/bacon-qr-code` `^3.0`, `ext-simplexml`.
- PHPUnit `^10.5.16` (dev). Playwright tests under `e2e/`.
- External poke of `/cronJobs`: Xneelo user crontab every 5 minutes (engine) and every 12 minutes (heartbeat); cron-job.org backup heartbeat only. Documented in `scope/Task_CronJobs_Implementation_Overview.md`.
- SMTP, Slack webhook, and OpenAI key from `.env` (empty placeholders in the committed `env` file).
- FTP credentials for deploy are Bitbucket pipeline variables (`FTP_USERNAME`, `FTP_HOST`, and the QA / shop QA equivalents). Values are not in the repo.

## Discrepancies that need a human

1. **PHP version.** `composer.json` requires `php: ^8.4`. `README.md` and `CHANGELOG.md` (Unreleased) say the floor was lowered to PHP 8.3 so managed QA/PROD can `composer install`. The committed constraint on this `main` commit is 8.4. Which environment is actually installed is **Unknown / Requires Confirmation**.
2. **Buyer–seller matrix vs later work.** The July 2026 QA matrix does not list Boxer ↔ Niew Beverages. `main` on 2026-10-06 merged `feature/1063-boxer-niew-po-store-duplicate`, and the changelog discusses Boxer invoice filters for Godrej and Niew. Live `clients` rows need a fresh export.
3. **Company Admin order responses** are hidden in the sidebar and rejected by the authorisation filter, with a comment that `user_access` for role 3 may still grant the menu. Product intent (“until scoping is ready”) is a code comment, not a signed requirement.
4. **Secrets in the tree.** `CronJobs::SECURITY_KEY` is a hardcoded production cron key (value omitted). `writable/keys/` contains PEM files. `writable/front_end_exports/` contains generated PDFs under per-user folders. The commented SMS helper contains credential-like text. None of those values are copied into Silicon Ark. Confirm rotation and whether they belong in Git.
5. **CSRF** global filter is commented out in `app/Config/Filters.php`.
6. **Auto-routing** is on (`$routes->setAutoRoute(true)`), so controller methods are reachable by convention in addition to the explicit routes.

## Human confirmation still required

- Production vs QA company IDs, active transports, and `clients` pairs.
- Whether `storefront` pipeline is a live shop or a leftover.
- Whether Car / cost-category controllers and Labels / meeting groups are still product features or admin-starter leftovers.
- Password-rotation period (email job exists; the number of days that forces rotation was not confirmed in this pass).
- Ownership of Confluence space AO and Jira project SI as the external spec of record.
