# Business rules — quantiviaLive

Evidence date: 2026-10-05. Source: `git@bitbucket.org:overdrive/quantivialive.git`, `master` at `0af11d2`.

Rules below are taken from code that was read. They are **Implemented** unless marked otherwise. They are not an approved business-rules catalogue. Where the code is the only source, the rule is also **Inferred** as a business intention: the code does this; nobody has confirmed that the organisation still wants it.

Credential values are omitted.

## Licensing

**Implemented** in `quantivia/inc/common_functions.inc.php`.

1. License constants come from `sg_get_const`: `N_PROJECTS`, `L_COMPANY`, `L_MAC`, `L_DOMAIN`, `L_TYPE`, `L_SERIAL`.
2. If `N_PROJECTS` is missing, the session value is 0. If `L_COMPANY` is missing, the company label is `Unregistered - Demonstration Only !`.
3. The installation is licensed only when the machine MAC matches `L_MAC` and `L_DOMAIN` equals `$_SERVER['SERVER_NAME']`.
4. When that match succeeds, `L_TYPE` containing `Q` sets quantity tracking (`Qlicensed`). `L_TYPE` containing `E` sets extended features (`Elicensed`).
5. **Hostname exception (implemented).** If the server name is one of `demo.quantivia.com`, `colab.procon8.com`, `sdev.quantivia.com`, `sdev.procon8.co.za`, `sdev.procon8.com`, `quantivia.local.com`, `qademo.quantivia.com`, `qaonline.quantivia.com`, `online.quantivia.com`, or `127.0.0.1`, the session is licensed, extended and quantity flags are true, `N_PROJECTS` is 25, and the company label is `Procon8`, without a MAC check.

**Inferred.** Putting the production hostname on that list means a request whose `SERVER_NAME` is `online.quantivia.com` does not need the license file's MAC match. Whether that was deliberate for this snapshot is **Unknown / Requires Confirmation**.

6. `requireFullLicence()` (`common_pageSetup.php`) stops the request with HTTP 401 and `This system is in Demo mode, and can not use this function` when `licensed` is false.
7. `display_all_projects()` lists only the first project when unlicensed (comment in code: the demo). When licensed, it stops after `N_PROJECTS` projects.
8. Project-row edit styling is added only for a project admin or site admin while the session is licensed.

## Identity and access

**Implemented** in `class.quantivia_so.inc.php` and `common_pageSetup.php`.

| Rule | Behaviour |
|---|---|
| Site admin | User is in eGroupware group `Admins`, or the user id is `-1` |
| Worker identity | If `$_SESSION['worker']` is set, `get_uid` returns `-1`, which `is_user_admin` treats as site admin |
| Project admin | User is in group `P_{id}_admin`, or `projects.administrator` equals the user id |
| Progress admin | User is in `P_{id}_p_admin` or in `P_{id}_admin` |
| Project member | User is in `P_{id}` or in `P_{id}_admin` |
| Programme member | User is in the eGroupware group whose name equals the programme name |
| Missing id | The `is_user_*` functions return false when user id or project id is missing (programme check also requires a programme name) |
| Group creation | Reading a project group id creates the eGroupware group if it does not exist |

Denial copy and HTTP 401 behaviour are in the PRD (FR-002).

**Inferred.** Progress administrators are not a superset of project administrators for the project-admin check: `is_user_project_admin` does not look at `P_{id}_p_admin`. The progress-admin check does look at the admin group. A progress-admin-only user is therefore not a project admin.

**Unknown / Requires Confirmation.** The full list of screens that allow progress admins, and whether "site admin" is intended to bypass project membership on every screen. `checkCurrentUserAutherization` allows a site admin only when the page passes `$allowSiteAdmin`.

### Session gate

- `quantivia/main.php` redirects to the eGroupware index when `sessionid` or `last_loginid` is absent.
- `common_functions.inc.php` sets HTTP 403 when `sessionid` is absent and does not exit on that statement. Later code may still run. **Implemented.** Whether that is a defect is **Unknown / Requires Confirmation**.

### qvaapi

**Implemented** in `quantivia/api/qvaapi.php`.

- Token is `HTTP_REFERER`, passed to `validate_token`. Failure: `Invalid Token`, HTTP 403.
- Token is split on `_`. The first piece is an eGroupware account id. If the account cannot be read: HTTP 403.
- `pid` is required. It must equal the project id stored in that user's Quantivia session. Mismatch: HTTP 403 and a sentence that includes both ids and the username.
- Default table name when `table` is omitted: `all`.

The token construction rules inside `validate_token` were not read. **Unknown** beyond the call.

## Project data rules read from the business object

**Implemented** in `class.quantivia_bo.inc.php` unless noted.

| Topic | Rule |
|---|---|
| Timekeeping method | `0` Structured, `1` Detailed, `2` None |
| Budget overflow | `1` Remaining Budget, `2` Current Budget |
| Reporting method | `RAMP` Ramp Method, `STEP` Step Method |
| Default reporting | If tabular or graphical method is empty on the project list, use `RAMP` |
| Reporting retention | Last 1, 3, 10, 25, 50, 100, or All (`999`) |
| Forecasting method | `1` Original Duration, `2` Current Trend, `3` Remaining Duration |
| Ticket status | `-100` Open, `-101` Closed, `-102` Deleted, `-103` Pending, `-104` Verify |
| Risk status | `-100` Raised, `-101` Closed, `-102` Canceled, `-103` Acknowledged |
| Risk severity | `100` High, `50` Moderate, `10` Low, `-1` Unknown |
| Deprecated project field | `update_project` unsets `s_calib` with the comment "deprecated in the new UI" |
| Standard report edit | Comment in `services/Table.php`: the user who created the report, or the project administrator, can edit the standard report, including deletion |

These coded lists are the allowed values the PHP arrays name. Whether the database rejects other values is **Unknown / Requires Confirmation**.

## Quantivia categories in eGroupware

**Implemented.**

- Actions category looked up by name `Project Actions` on app `actions` (`what_type_is_project_tickets`).
- Risk category looked up by name `Project Risks` on app `risk` (`what_type_is_project_risks`).
- Settings file also stores numeric ids 36, 35, 94, and 95 under keys `egw_bug_cat`, `egw_fea_cat`, `egw_gen_cat`, and `egw_pmt_cat`.

**Unknown / Requires Confirmation.** Whether those numbers still match live category rows, and how they relate to the name lookups.

## Time and reporting windows

**Implemented** in settings and `common_functions.inc.php`.

- Timezone is UTC.
- Timestamp ceiling in session: `2147472000`. Comment says this is 19 Jan 2038 00:00:00 UTC and must fall on midnight because some tables do not store hours, minutes, and seconds.
- `report_period` is `4`. Comment: weeks for reporting actuals.
- `time_report_period` is `4`. Comment: weeks for the window when auto-allocating to open control points.
- Project list column `Progress Review Window (weeks)` comes from `get_project_time_radar_window`. The function body was not read.

## Offload and workers

**Implemented** in `worker.php` and `create_ofload_token`.

| type_id | Comment in code | Action called |
|---|---|---|
| 0 | Maintenance | `archive_logs`, `service_user_views` |
| 1 | Deliverables | `import_upload_2_db` |
| 2 | Assignments | `import_cp_assign_upload_2_db` |
| 3 | Schedules | `import_schedule_upload_2_db` |
| 4 | Deliverable progress | `import_deliverable_actuals_upload_2_db` |
| 5 | Time | `import_batch_actual_times_to_db` |
| 6 | Publishings | `publish_report` |
| 7 | Deliverables download | `create_deliverables_download` |
| 8 | Assignments download | `create_cp_assign_download` |
| 9 | Schedules download | `create_schedule_download` |
| 10 | Progress download | Turnaround array for activities or deliverables |
| 11 | Time download | No call |
| 12 | Complete download | `create_complete_deliverables_download` |
| 13 | Resources download | `create_resources_download` |
| 14 | Resource upload | `import_resource_upload_2_db` |
| 15 | Resource actuals | `import_resource_actuals_upload_2_db` |

Offload tokens live 12 hours.

`QFD/union.bat` starts ten copies of `worker.vbs`. Each copy requests `http://quantivia.local.com/quantivia/inc/worker.php`. The settings file's worker host is `online.quantivia.com` on port 80. **Discrepancy:** two different worker hosts are configured. Which one a given environment uses is **Unknown / Requires Confirmation**.

When `worker.php` runs, it sets the current user to `worker`, the template to `templates_procon8_01`, and `$_SESSION['worker']` true.

## P6 import

**Implemented** in `forms/p6import.php`.

- The screen states that only P6 XER, ZIP, and XML files are supported.
- XML is converted toward XER before import.
- Imported activity comments default to `Imported with P6 Import Wizard` where that assignment was read.
- Resource notes fall back to `Added by P6 Import Wizard` when notes are empty.

Field-level mapping rules beyond that were not extracted. **Unknown** as a complete mapping catalogue.

## File retention and storage

**Implemented** configuration.

- `file_retention` is true.
- `file_storage` is `/var/www/html/online.quantivia.com/files`. If that setting were empty, `common_functions.inc.php` would use `sys_get_temp_dir()`.
- `excel_password` is set in the settings file. The value is omitted. What it locks was not traced in this pass.

## Version identity

**Implemented**, and internally inconsistent.

| Source | Value |
|---|---|
| `quantivia_setings.php` key `version` | `1.2.000` (overwritten after `common_functions.inc.php` loads) |
| Active changelog last key | `2.0.013` |
| `so_version` | 216 |
| `bo_version` | 276 |
| Assembled `version` string | `{changelog key} - (SO:{so} - BO:{bo})` |

`version.php` prints that assembled string unless the posted `ser` value is `DJ00x`, in which case it prints `AD`. It also logs the posted `lic`, `mac`, `dom`, and `ser` fields. It forces the worker session and the Procon8 template before doing so.

## eGroupware setup access

**Implemented** in `header.inc.php`.

- `header_admin_user` is `admin`.
- `setup_acl` is an empty string, so the file does not record an IP allow-list for setup.
- Domain select box is off (`show_domain_selectbox` false). Comment in the file: users on the default domain log in with the login id alone.
- A commented-out domain block names database `quantiviagroupware` on `localhost` with a different user than the active block. The active block uses the RDS host. Passwords omitted.

## Rules that must not be invented from this file

The following were not established and stay **Unknown / Requires Confirmation**:

- Approval chains for progress review beyond the changelog sentence for `2.0.004` ("Progress review validation prior to approval").
- Monetary or contractual rules for SPI, CPI, EAC, or RPI. The metrics exist in changelog text and chart services. The formulas were not re-derived for this document.
- Data retention periods beyond the boolean `file_retention` and the report-retention enum.
- Who may call `version.php` or `phpinfo.php`. Both are reachable as files in the web root; no auth wrapper was seen at the top of `version.php`.
