# Technical documentation — bigpond_frontend_qa

Evidence date: 2026-10-19.

Source: `git@bitbucket.org:overdrive/bigpond_frontend_qa.git`, `main` at `6b421ff` (2025-07-21, `init`). Parent: `2ec5f32` (`Initial commit`) the same day. No other branches were on the remote.

Secret values are not recorded here. A committed `.env` holds Xero and OpenAI credentials; names only are listed below.

## Stack

| Item | Evidence |
|---|---|
| Language | JavaScript (React JSX and Node Lambda) |
| UI | React 18.2, `react-scripts` 5.0.1, React Router 6.9 |
| UI kits | React Bootstrap 2.7, Bootstrap 5.2, MUI 6 (`@mui/icons-material`, Emotion), AWS Amplify UI React 4.3 |
| App shell | `src/index.js` calls `Amplify.configure(awsExports)` then renders `App` |
| Auth client | `@aws-amplify/ui-react` `Authenticator`. Extra Cognito admin calls via `@aws-sdk/client-cognito-identity-provider` |
| HTTP | `aws-amplify` `API`, plus `axios` in some Lambdas |
| Tables | `datatables.net-bs5`, `datatables.net-buttons-bs5`, `jquery`, `react-data-table-component` |
| Documents | `xlsx`, `xlsx-js-style`, `jspdf`, `jspdf-autotable`, `pdf-lib`, `pdfjs-dist`, `exceljs` (in `generatefile`) |
| AI | `openai` 4.x. Models in code: `gpt-4.1` (`openAIFileProcessing`), `gpt-4o` (`processUnprocessedFiles`) |
| Database driver | `mysql2` in Lambdas |
| AWS SDK | v2 `aws-sdk` and v3 clients (S3, SES, Secrets Manager, SSM, Cognito) |
| Region | `ap-southeast-2` in the Lambdas and in `signUp.js` |
| Package name | `bigpond` `0.1.0`, `"private": true` |

`README.md` also names Material-UI, DataTables, XLSX-JS-Style, and jsPDF. That matches `package.json`.

## Repository layout

```text
src/index.js                 Amplify.configure + React root
src/App.js                   Authenticator.Provider, AuthProvider, BrowserRouter
src/aws-exports.js           generated Amplify config (not quoted)
src/router/index.jsx         role shells
src/router/basic/index.jsx   public routes
src/context/authContext.jsx
src/requireauth.jsx          exported; the main router does not wrap routes with it
src/pages/                   landing, login target, company, client, user, workflow, customMatch, callback, audit, error, loading
src/components/              welcome, contact, navigation, tables, file upload, login
src/util/                    signUp, getAuth, s3, errorLog, xeroURL
src/images/
amplify/backend/             API, auth, function, storage
amplify/#current-cloud-backend/   generated snapshot, long paths
amplify/cli.json
public/
bitbucket-pipelines.yml      SonarQube on branch {master}
sonar-project.properties
package.json
README.md, CHANGELOG.md, NewKnowledgeBase.md, rules.md
.env                         committed; do not copy values
```

`src/pages` directories: `auditPage`, `callback`, `clientPage`, `companyPage`, `customMatchPage`, `errorPage`, `landingPage`, `loadingPage`, `userPage`, `workflowPage`.

There is no `amplify/backend/hosting` directory.

## Auth

Imported Amplify auth `bigpond10dd5625` (`backend-config.json` `serviceType` `imported`).

Parameters file:

- Identity pool and user pool.
- Region `ap-southeast-2`.
- Username attribute and required attribute: email.
- Password minimum 8 with lower, upper, number, symbol.
- MFA off. No MFA types.
- Auto-verified: email.

UI login: `src/components/login/index.jsx`. After `authenticated`, redirect to the previous path or `/companies`.

Admin user creation: `src/util/signUp.js` uses the signed-in user’s Amplify credentials to call `AdminCreateUser` and `AdminAddUserToGroup`. The user pool id is hardcoded in that file. Groups: `Admin` or `User`. Delivery medium: `EMAIL`.

`RequireAuth` (`src/requireauth.jsx`) redirects unauthenticated users to `/`. The live shell in `src/router/index.jsx` does not use that component. It branches on `useAuthenticator().route` itself.

Session id: `identityId.split(":")[1]` with `-` replaced by `_` (`authContext.jsx`). Stored on `users.s3_session` and used as the suffix of `master_table_*`.

## API Gateway

Four Amplify API resources (`backend-config.json`):

| API | Lambdas attached |
|---|---|
| `apibigpond` | `bigpondexpress`, `XeroExpress`, `xerotoken`, `xerotenants`, `xerorefresh`, `updatetableinvoice`, `sendxeroemail`, `frontendLogs`, `generatefile`, `ZipObjects`, `deleteSessionUploads`, `openaistart`, `ZipWorkPapers`, `contactmail` |
| `apibigpondfiles` | `generatefile`, `ZipObjects`, `deleteSessionUploads` |
| `manageFileProcessTable` | `manageFileProcessTable` |
| `tempFileProceesTable` | `tempFileProceesTable` (spelling as in the folder name) |

The React code calls `API.get/post("apibigpond", path)`.

`cli-inputs.json` marks sampled paths `protected` and also grants `guest` create/read/update/delete. Confirm the deployed authorizer before assuming guests are blocked.

### `bigpondexpress` routes

Express app `amplify/backend/function/bigpondexpress/src/app.js`. Listens on port 3000 for local use and exports the app for Lambda.

Users: `/getusers`, `/getusersbycompany/:companyid`, `/getuserbyid/:userid`, `/getuserbyusername/:username`, `/getuserbyemail/:email`, `/initUser/:username`, `/adduser/:user`, `/bulkaddusers`, `/deleteuserbyid/:userid`, `/updateuser/:user`, `/updateusersession/:user`, `/updateuserselectedbank/:user`, `/updateuserworkflowtype/:user`, `/updateuserclient/:user`, `/updateuseruploadprocess/:userid`, `/getuseruploadprocess/:userid`.

Companies: `/getcompany`, `/getactivecompanies`, `/getcompanybyid/:companyid`, `/addcompany/:company`, `/deletecompanybyid/:companyid`, `/updatecompany/:company`, `/updatecompanyxero/:company`.

Clients: `/getcompanyclients`, `/getcompanyclientsid/:clientid`, `/getclientsbycompanyid/:companyid`, `/addcompanyclient/:client`, `/deletecompanyclientbyid/:clientid`, `/updatecompanyclient/:client`, `/setclientactivepending/:clientid`.

Roles: `/getuserrole`, `/getuserrolebyid/:roleid`, `/adduserrole/:role`, `/deleteuserrolebyid/:roleid`, `/updateuserrole/:role`.

Session table: `/getsessionbanknumbers/:sessionid`, `/deletemastersessiontable/:sessionid`, `/clearmastersessiontable/:sessionid`.

Flows: `/addcustommatchflow/:flow`, `/getcustommatchflowbyid/:flowid`, `/getcustommatchflowsbycompanyid/:companyid`, `/updatecustommatchflow/:flow`, `/deletecustommatchflowbyid/:flowid`.

Many write bodies are `JSON.parse` of a path segment rather than a JSON body. `/bulkaddusers` and custom-match `json_value` use `req.body`.

Success shape: `{ success: "call succeed!", rows }`. Error shape: `{ error: "call error!", err }`. HTTP status is not set to 4xx/5xx in `setErrorRes`.

### Other HTTP Lambdas

| Function | Role |
|---|---|
| `XeroExpress` | `/sendurl/:companyid`, `/xerocallback`, `/clientdetails/:companyID`, `/clientaccess/:companyID`, `/updateclientaccess/:details`. Redirect URI `https://www.auditwhizz.net/callback` |
| `xerotoken`, `xerotenants`, `xerorefresh` | OAuth token, tenant list, refresh |
| `sendxeroemail` | SES mail for the Xero link. MySQL via the same secret pattern as XeroExpress |
| `updatetableinvoice` | Invoice table updates (Xero/testing path) |
| `generatefile` | ExcelJS workbook from the session master table. Buckets named in source: `bigpond-uploads` and `big-pond-uploads-bucket123209-dev` |
| `ZipObjects` | Zip of Xero Testing uploads |
| `ZipWorkPapers` | Zip of workpapers plus `Results.xlsx`, signed URL, 404 when empty |
| `deleteSessionUploads` | Removes session uploads |
| `contactmail` | SES to `bhawin@auditwhizz.net` |
| `frontendLogs` | `POST /log/{json}`. Prints the payload. Does not persist a row |
| `manageFileProcessTable` | File-process table CRUD against MySQL and S3 |
| `tempFileProceesTable`, `tempFileProcessTable` | Temporary file-process tables. Two directories |
| `openaistart` | `lambda.invoke` of `openAIFileProcessing-dev` |
| `bigpondCustomMessage` | Cognito custom-message trigger shell. Loads modules from env `MODULES` |
| `bigpondCreateConnection` | Present as a function directory (Amplify build output under `#current-cloud-backend` as well) |

## Scheduled work

| Function | Schedule evidence | Model / action |
|---|---|---|
| `processUnprocessedFiles` | `function-parameters.json` `rate(5 minutes)` | S3 object + `gpt-4o`. Secrets `DatabaseCredentials` and `OpenAIKey` |
| `openAIFileProcessing` | CloudFormation `ScheduleExpression` `rate(1 minute)` | `gpt-4.1` extract and match. Logs toward `workpaper_logs` |

No SQS queue definition was found. Work is Lambda plus the browser’s own poll loops (5 seconds for Excel, 10 seconds for CSV).

## Data

No migration directory. Tables are known only from SQL in the Lambdas and from docs.

| Table | How it is known |
|---|---|
| `users` | Selected and updated in `bigpondexpress`. Columns used: `id`, `company_id`, `fullname`, `username`, `email`, `role_id`, `cognito_uuid`, `s3_session`, `active`, `current_client`, `selected_bank_number`, `xlsx_process`, `workflow_type`, audit columns |
| `company` | `id`, `name`, `active`, audit columns. UI label Audit Firm |
| `company_client` | `company_id`, `name`, `contact_email`, `contact_name`, `active`, plus `xero_token`, `xero_refresh_token`, `xero_tenant`, `connection_id` used by Xero routes |
| `user_role` | CRUD routes. UI does not call them |
| `custom_match_flows` | `company_id`, `type`, `json_value`, `active`, audit columns |
| `master_table_{session}` | Created in `/initUser` if missing. Wide varchar columns for bank, invoice, receipt, textract, running balance, file names |
| `workpaper_logs` | Named in `NewKnowledgeBase.md` and `loggingUtils.js`. `CREATE TABLE` is not in the repo |

`/initUser` joins `users` to `company` for `company_name`.

MySQL credentials:

- Most Lambdas: SSM parameter `rdsDetails` (comma-separated host, port, database) and a Secrets Manager RDS secret (the secret id is hardcoded in the Lambda source).
- `processUnprocessedFiles`: secret `DatabaseCredentials` with `host`, `username`, `password`, `database`.
- Xero hash: SSM `xeroHash`.

Do not copy those secret payloads into docs or tickets.

## Storage

Amplify storage resource name `bigpondpuloads`, service S3 (`backend-config.json`).

Uploads from the workflow screen use Amplify Storage `accessLevel` `private`.

Download of the generated workbook uses bucket `big-pond-uploads-bucket123209-dev` and key `private/{identityId}/{file name}` (`explorerButtons.jsx`).

`generatefile` also references bucket `bigpond-uploads`.

**Unknown / Requires Confirmation** which bucket the deployed Amplify storage uses, and whether the hardcoded `…-dev` name is still correct.

## Integrations

| System | Direction | Trigger | Notes |
|---|---|---|---|
| Cognito | Both | Login; admin create user | Imported pool, groups Admin and User |
| MySQL | App → DB | Almost every API call | See Data |
| S3 | Both | Upload, generate, zip, scheduled read | Private prefix and named buckets |
| OpenAI | App → API | Workpaper processing and the 5-minute job | Keys in Secrets Manager and in `.env` |
| Xero | Both | Client connect, callback, deactivate | `api.xero.com`, redirect on `auditwhizz.net` |
| SES | App → mail | Contact form, Xero email | `ap-southeast-2` |
| SonarQube | CI → scanner | Pipeline on `{master}` | `sonar.projectKey=overdrive_bigpond_frontend_AYqLOFK0uNwRc2P2S9QL`. CPD excludes `**/amplify/**/function/**` |
| Bitbucket Pipelines | CI | Branch filter `{master}` | One step, `sonarsource/sonarqube-scan:3.0.2`, Docker memory 3072. `SONAR_HOST_URL` and `SONAR_TOKEN` are repository variables |

CORS origins repeated in Lambdas: `https://www.auditwhizz.net`, `http://localhost:3000`.

## Environment configuration

`README.md` lists:

- `REACT_APP_OPENAI_API_KEY`
- “AWS Amplify configuration variables” (no names)

The committed `.env` defines:

- `REACT_APP_XERO_CLIENTID`
- `REACT_APP_XERO_CLIENTSECRET`
- `REACT_APP_OPENAI_API_KEY`

Values are in git. They are not repeated in Silicon Ark. Rotate them.

Lambda environment that is named in code:

- `S3_BUCKET` (`processUnprocessedFiles`)
- `MODULES` (`bigpondCustomMessage`)

Amplify function secrets and SSM parameters are listed under Data. They are not in `.env`.

## Frontend structure

`App.js` order: `Authenticator.Provider` → Amplify `ThemeProvider` → `AuthProvider` → `BrowserRouter` → `BigPondRouter`.

Public routes (`router/basic`): index = landing, `login` = login, anything else redirects to `/`.

Authenticated routes depend on `role_id` (see the PRD). `callback` and `error` are also registered on the unauthenticated router.

Workpapers state:

- React state for the step list inside `useQueuedLocalStorage` (`custom_match_page`).
- `localStorage` key `custom_match_custom_flows` for named templates.
- Company rows in `custom_match_flows`.

Xero Testing state:

- React state for file lists.
- `currentUser` in context for client, client name, workflow type, bank.
- S3 as the file store.
- `users.xlsx_process` as the Excel-ready flag.

## Background processing and the browser

There is no in-repo worker process. Schedules are EventBridge rates on two Lambdas (see Scheduled work).

The browser polls:

- Excel: every 5 seconds until `xlsx_process === 1` (`WorkflowUploads.jsx`). No timeout.
- CSV: one 10 second wait.

`openaistart` is a synchronous Lambda invoke of the dev function name, not a queue.

## Security observations

These are implemented facts, not a pentest.

- `.env` is committed with a Xero client secret and an OpenAI key. `git log` shows the file in `6b421ff`.
- User pool id is hardcoded in `src/util/signUp.js`. Admin create uses the current user’s Cognito credentials.
- Guest CRUD is present on API path definitions next to `protected`.
- Express handlers do not authorise by `role_id`.
- SQL identifiers for session tables are string-built. Values in `executeQuery` use placeholders.
- `setErrorRes` returns the raw error object to the client.
- Contact and log Lambdas allow only two origins; many other behaviours rely on API Gateway.
- MFA is off in the imported auth parameters.
- Deactivate-client swallows Xero HTTP errors.

## Build, run, and test

Scripts (`package.json`):

- `npm start` — `react-scripts start` (CRA default port 3000, same origin the Lambdas allow).
- `npm run build` — `react-scripts build`. Output directory `build/` is in the repo snapshot as well as being a CRA output. Whether `build/` should be committed is **Unknown**.
- `npm test` — `react-scripts test`.

`src/App.test.js` renders `<App />` and expects text `/learn react/i`. `App.js` does not render that text. **Inferred:** the default CRA test fails.

`src/setupTests.js` is the CRA jest setup (`@testing-library/jest-dom`).

No Dockerfile, no `phpunit`, no Cypress/Playwright config was found at the top level.

Local API: `bigpondexpress` comments say the Express server is for local runs and Lambda wraps the same app. A README “Getting Started” says clone, `npm install`, configure Amplify, set environment variables, `npm start`. It does not name the Amplify env or the database.

## Quality tooling in the repo

- `bitbucket-pipelines.yml` — SonarQube only, branch `{master}`. Current git branch is `main`, so this pipeline does not attach to the branch that was inspected.
- `sonar-project.properties` — project key above, CPD exclusion for Amplify functions.
- `.cursorrules` and `.cursor/rules/custom-rule.mdc` — editor rules, not product behaviour.
- `rules.md` — tells editors to edit `customFlowPage` and not to preview the site. That page is absent.
- `NewKnowledgeBase.md` — long notes on OpenAI logging, table DOM nesting, localStorage, and field detection. Useful as developer notes. It is not a specification that overrides the code.

## Monitoring

- `frontendLogs` writes to CloudWatch through `console.log` and returns `"Logs created"`.
- Lambda `console.log` / `console.error` elsewhere.
- No application metrics, alarms, or X-Ray config were found in the tree.
- SonarQube is the CI scanner when the pipeline runs.

## Deployment

**Inferred** from Amplify Gen 1 layout: `amplify push` publishes CloudFormation for API, functions, imported auth, and S3. Hosting is not defined in this repo. The production hostname is implied by CORS and the Xero redirect (`https://www.auditwhizz.net`).

`openAIFileProcessing-dev` and the bucket suffix `-dev` suggest an Amplify env named `dev`. Whether that env is what `auditwhizz.net` serves is **Unknown / Requires Confirmation**.

Generated CloudFormation under `amplify/backend/**/build` and `amplify/#current-cloud-backend` is checked in. Paths under `#current-cloud-backend/.../bigpondCreateConnection/` are long enough to fail a Windows checkout unless `core.longpaths` is enabled or the clone path is short.

## Dependency notes

Runtime dependencies are the `package.json` `dependencies` block (Amplify, AWS SDK v2 and v3, OpenAI, React, Bootstrap, MUI, DataTables, jQuery, dayjs, moment, mysql2, axios, jwt-decode, pdf libraries, xlsx). `mysql2` in the frontend package is unused by the browser in the files searched; Lambdas have their own `package.json` where they need the driver.

Dev dependency: `copy-webpack-plugin`.

Lockfile: `package-lock.json`.

## Unknown / Requires Confirmation

- Deployed API Gateway authorizer versus the guest entries in `cli-inputs.json`.
- Which S3 bucket and Amplify env `auditwhizz.net` uses.
- Whether the 1-minute and 5-minute schedules are both enabled.
- Schema drift: columns the app writes that were added outside this repo (`workpaper_logs`, Xero columns, `custom_match_flows`).
- Whether `build/` in git is an artifact that should stay.
- Sonar project still bound to this key, and whether pipelines were moved from `master` to `main` outside this file.
