# Project plan — sawis_staging

Evidence date: 2026-10-04.

Source repository: `git@bitbucket.org:silicon_bit_bucket/sawis_staging.git`.

The scan-host path `~/projects/sonar_scan/repos/sawis_staging` was not on this machine. The tree was read from a git clone of that origin. Passwords in `system.server.*.php` are not reproduced.

This plan describes what the repository contains. It does not decide what the product should become.

## Product

There is no README and no product requirements document in the repository or in Silicon Ark.

`index.php` tells the visitor there is no content here and to visit `www.sawis.co.za`. The page caption is "Redirect". A comment dated 2015-06-11 says the home page was changed away from `index.php`.

The rest of the tree is a PHP application that copies wine-industry records between MySQL databases and, for one lookup, a CSV file. Scripts and comments call that process "sync". Connection profiles are named STG (the local `sawis_staging` database), S3 (database name `sawis`), API (`sawis_api`), and IPW.

**Unknown / Requires Confirmation:** the official product name, and whether "S3" means anything other than the MySQL profile the code calls S3. Nothing in the repository describes Amazon S3.

## Branch reality

`origin/HEAD` is `master`. That branch is not the line the deploy scripts reset onto.

| Line | Tip | Date | What it is |
|---|---|---|---|
| `master` (default) | `9d06011` | 2025-06-20 | Seven commits. Application snapshot from 2020-10-26 (`a5bcf71`, "ini sawis_staging repo", JacquesOverdrive), then two edits of `system.server.PROD.php` on 2023-05-18, then SonarQube files on 2025-06-20. |
| `qa_staging_2020` | `5040b8b` | 2026-09-21 | Latest integrated tip among the staging lines. Merge of `dev_staging_2020` (pull request #167). `deploy.php` on this branch hard-resets to `origin/qa_staging_2020`. |
| `dev_staging_2020` | `529c77e` | 2026-09-21 | Merge of `default_staging_2020` (pull request #166). Tree matches `default_staging_2020`. `deploy.php` hard-resets to `origin/dev_staging_2020`. |
| `default_staging_2020` | `891921a` | 2026-09-21 | "Prod changes pushed to other branches". Same tree as `dev_staging_2020` at these tips. |
| `prod_staging_2020` | `39368c5` | 2026-09-14 | "test duplicate key issues on sync". `deploy.php` hard-resets to `origin/prod_staging_2020`. Diverged from `qa_staging_2020` (see below). |
| `fix_sync_hotfix20210630` | `63f812f` | 2021-07-29 | "update sync lab analysis records in the API db to a status of ST". Not updated since. |

`qa_staging_2020` is 256 commits ahead of `master`. `prod_staging_2020` is 314 commits ahead of `master`. Those two lines are not the same tree.

Differences that change behaviour, `qa_staging_2020` versus `prod_staging_2020`:

| Area | `qa_staging_2020` | `prod_staging_2020` |
|---|---|---|
| `deploy.php` | Resets to `qa_staging_2020` | Resets to `prod_staging_2020` |
| `system.php` | No timezone call. No CLI defaults | `date_default_timezone_set('Africa/Johannesburg')`. CLI fills missing `$_SERVER` keys. `SERVER_NAME` falls back to `SAWIS_SERVER_NAME` or `10.0.0.62` |
| `NemoDatabase::doQuery` | Two parameters | Third parameter `$blnDieOnError` (default true) and a try/catch around `mysqli_query` |
| IPW profile on the `10.0.0.62` key | Host `10.0.0.105`, database `ipw_live`, user `siliconoverdrive` | Host `10.0.0.155`, database `ipw_staging_20260823`, user `sawis_readon`. A comment names table `sawis_compliance`. The same file comments the previous profile as old |

`project.functions.inc.php` on the QA tip calls `doQuery` with three arguments for BlendMaster. The QA `doQuery` signature has two parameters. On PHP 8, an extra argument to a user-defined function is an `ArgumentCountError`. The production signature accepts the third argument. Provenance: **Implemented** on each branch as described. Whether QA is actually running the production copy of `_nemo.database2.cls.php` is **Unknown / Requires Confirmation**.

`master` `system.php` includes `system.server.QA.php` and `system.server.DEV.php`. Only `system.server.PROD.php` exists on `master`. A request that loads `system.php` from `master` fails on the missing include. Provenance: **Implemented**.

SonarQube config exists only on `master` (`bitbucket-pipelines.yml`, `sonar-project.properties`). The staging-line diff against `master` deletes both files.

## Objectives (inferred from the implementation, not from a written plan)

- Keep a staging database of SAWIS-related records.
- Copy those records between the staging database, the database profile named S3, the API database, and the IPW database.
- Let an operator turn sync on or off, pick entities and stages, and run them from `sync.ui.php`.
- Import at least the grape-variety CSV through `cron.mapper.php`.
- Deploy a chosen branch with `deploy.php` by fetching and hard-resetting that branch under `/var/www/html/sawis_staging/`.
- On `master` only, run a SonarQube scan for `master` and for pull requests.

## Scope

### In scope of the 2026 staging lines

Documented behaviour below is from `qa_staging_2020` at `5040b8b` unless a row says otherwise.

1. Stub public page `index.php`.
2. Sync engine `cron.sync.php` and `cron.sync.new.php`.
3. Operator page `sync.ui.php`. `Execute` includes `cron.sync.new.php`.
4. Blend-master field notes in `cron.blendmaster.php`.
5. Mapper import `cron.mapper.php` (cultivar CSV only in the entity array).
6. Empty daily cron switch in `cron.daily.php`.
7. SQL console `query.php` / `includes/query.cls.php`.
8. Message page `message.php`.
9. Connection profiles in `system.server.PROD.php`, `system.server.QA.php`, and `system.server.DEV.php`.
10. In-repo Nemo framework under `_framework/`.
11. Web git deploy `deploy.php`.

### On `master` and absent from the staging tips

- `cron.sync.20180926.php`, `cron.sync.maanie.php`, `cron.sync.pj.php` — dated copies of the sync script.
- `project.functions.inc.20181101.php` — dated copy of the project functions.
- `bitbucket-pipelines.yml` and `sonar-project.properties`.

### Out of scope of this repository

- The site at `www.sawis.co.za`. This repo only links to it.
- `ajaxfunctions.php`, `registration.member.php`, `resetPassword.php`, `user.php`, and a `modules/` directory. Layout and framework comments name them. They are not in git on `master` or on `qa_staging_2020`.
- A scheduler. No crontab, systemd unit, or pipeline step runs the cron scripts.
- Automated tests. No PHPUnit, Composer, or test directory. `testDeploy.txt`, `testDeploy - Copy.txt`, and `test_deploy.txt` are deploy markers, not tests.

## System architecture

```text
Browser or CLI
  │
  ├─ index.php          stub; destroys the session; points at www.sawis.co.za
  ├─ sync.ui.php        operator actions (does not itself include system.php)
  ├─ cron.sync.php      sync engine; includes system.php
  ├─ cron.sync.new.php  sync engine used by sync.ui.php Execute
  ├─ cron.mapper.php    CSV → staging tables (cultivar file only)
  ├─ query.php          SQL against selected connection profiles
  └─ deploy.php         git fetch + git reset --hard of one branch

system.php
  ├─ system.server.PROD.php / QA.php / DEV.php   profiles keyed by HTTP host
  ├─ session (gc_maxlifetime 7200)
  ├─ switchBD(S3) then read sysSettings into $SystemSettings
  └─ switchBD(staging)

MySQL profiles (names used in code)
  STG   database sawis_staging     local staging tables, stg*, log*, sysSync*
  S3    database sawis             settings and the S3 copy of entities
  API   database sawis_api
  IPW   database ipw_live on QA; ipw_staging_20260823 on prod_staging_2020
```

`system.php` selects a profile by `$_SERVER['SERVER_NAME']` (on the QA tip) or by the CLI default described above (production tip). Profiles for other hosts are ignored for that request.

## Major components

| Component | Role |
|---|---|
| `system.php` | Bootstrap: errors on, load every server file, session, connect, load `sysSettings` from the S3 profile, switch back to the staging profile |
| `project.functions.inc.php` | `switchBD`, staging update/insert, push to an environment, sync-log email, BlendMaster duplicate-key handling |
| `cron.sync.php` / `cron.sync.new.php` | Entity SQL and stage execution |
| `sync.ui.php` | Checkboxes for entity groups and stages; maintenance actions |
| `_framework/` | Nemo page, list, menu, database, and email classes |
| `deploy.php` | Unauthenticated `shell_exec` of git commands |

## Milestones visible in git

These are commit facts, not an approved roadmap.

| When | Evidence |
|---|---|
| 2020-10-26 | Initial commit (Gareth Bowers) and `a5bcf71` "ini sawis_staging repo" |
| 2021-07-29 | Hotfix branch: lab analysis API rows set to status `ST` |
| 2023-05-18 | `system.server.PROD.php` edited on `master` |
| 2024-05 | Member sync and BlendMaster "litres out" commits on the staging history |
| 2025-03 | Sync error handling so a failure does not take the system offline; email strict-mode commits; MySQL `sql_mode` cleared when the cron runs |
| 2025-06 | Certification field changes; a commit message says certification was removed from sync entities. The QA tip still lists `Certification` in `sync.ui.php` |
| 2025-06-20 | Sonar pipeline added on `master` only |
| 2025-08 to 2025-12 | BlendMaster wine-type and product-type fixes; commit messages "php 8.2 upgrade" and "upgrade 8.4" |
| 2026-04-14 | "testing if deploy works" |
| 2026-08-12 | `strMapperWO` added on location data |
| 2026-09-14 | Production tip: duplicate-key work and the IPW profile change |
| 2026-09-21 | QA / dev / default tips |

## Implementation plan

No written implementation plan is in the repository. Current delivery is branch-specific `deploy.php` plus manual or scheduled execution of the PHP scripts. How often sync runs is **Unknown / Requires Confirmation**.

## Known dependencies

- PHP with `mysqli`. Commit messages name PHP 8.2 and 8.4. The runtime actually installed on each server is **Unknown / Requires Confirmation**.
- MySQL or MariaDB. The cron sets `sql_mode` to an empty string globally when `cron.sync.php` runs.
- PHP `mail()` for sync-log email (`NemoEmail::Send`).
- jQuery 1.12.4 from `ajax.googleapis.com` in `layouts/header.incl.php`.
- Optional SMS via `http://www.mymobileapi.com/api5/http5.aspx` inside `SendSMS`. Nothing in the sync scripts calls `SendSMS`. Credentials would come from `sysSettings` keys `smsUsername`, `smsPassword`, and `smsLive`.
- Bitbucket, for git remotes and for the Sonar pipe on `master`.

## Current project status

The default branch does not contain a runnable copy of the 2026 application. The sync application is implemented on the `*_staging_2020` branches and was still being committed in September 2026.

`prod_staging_2020` and `qa_staging_2020` have diverged. Which host runs which branch is determined only by whichever `deploy.php` last reset that host. **Unknown / Requires Confirmation:** which branch each server is on today.

## Human confirmation

- Which branch is production, QA, and development on the servers.
- Whether `master` should stay the default branch.
- The product name, and the relationship to `www.sawis.co.za` and to "SAWIS Online" (the sync email subject).
- What S3, IPW, WIETA, WSB, BG2, WOL, and MAPPER stand for. The code uses the abbreviations and does not expand them.
- Who operates sync, and whether `sync.ui.php` is exposed only on a private network.
- The scheduler for the cron scripts.
- Whether plaintext database passwords in `system.server.*.php` are still valid. They are not copied here. The production IPW block also repeats a password in a comment.
