# PRD — quantivia

Evidence date: 2026-10-05. Source: `git@bitbucket.org:overdrive/quantivia.git`, `master` at `c567977` (2019-05-21, "#87 Lines to all dashboard tables").

There was no prior PRD in Silicon Ark for this directory. Related sets exist for `quantivia-clean`, `quantiviaLive`, and `quantivia-svn`. Requirements below come from this repository's code and the embedded user guide. Provenance is marked on each item.

`development` (`ba5f6c5`, 2019-08-07, "Update from latest for version 2") was not checked out. This PRD does not treat that branch as the product baseline. Which branch customers see is **Unknown / Requires Confirmation**.

## Product purpose

Quantivia is a **Deliverable Progress and Performance Reporting** tool that runs inside an eGroupWare tree. It uses eGroupWare sessions and accounts. It is not registered as a standard eGroupWare app (`quantivia/setup/setup.inc.php` is absent). `quantivia/index.php` says it is intended to execute from within the eGroupWare folders but not as part of eGroupWare.

It supports programme and project teams tracking deliverables, budgets, earned-value style performance, control points, progress updates, and reporting, with per-client UI branding.

Provenance: **Documented** (`class.quantivia_bo.inc.php` header; `quantivia/templates_procon8_01/user_guide.php`) and **Implemented**.

This repository's committed settings name a localhost demo: eGroupWare database `demo`, Quantivia database `demoppr`, Windows file storage `C:\wamp64\www\html`. Provenance: **Implemented** (`header.inc.php`, `quantivia/setup/quantivia_setings.php`).

## Users and roles

| Role | What they do | Evidence | Provenance |
|---|---|---|---|
| Anonymous visitor | Can reach login; Quantivia redirects away when the `sessionid` cookie is missing | `quantivia/index.php`, `quantivia/main.php` | Implemented |
| eGroupWare authenticated user | Holds `sessionid` and `last_loginid` cookies used by Quantivia | `login.php`, `main.php` | Implemented |
| Site Admin | Member of eGroupWare group `Admins`. Site-wide menus (project list, users, programmes). User id `-1` is also treated as admin so workers can run | `is_user_admin()` | Implemented |
| Project Admin | Member of `P_{p_id}_admin`, or listed as the project's `administrator`. Configures the project and publishes when status allows | `is_user_project_admin()`, `Menu.php` | Implemented; user-guide term **Documented** |
| Progress Admin | Member of `P_{p_id}_p_admin`, or already a project admin | `is_user_project_progress_admin()` | Implemented |
| Project User (view) | Member of `P_{p_id}`. Dashboard and view-oriented menus | `is_user_project_user()`, `Menu.php` | Implemented |
| Programme user | Member of an eGroupWare group whose name matches the programme name | `is_user_programme_user()` | Implemented |
| Worker process | `$_SESSION['worker']` forces `get_uid()` to return `-1` | `get_uid()`, `version.php` | Implemented |

People authenticate through eGroupWare. `login.php` and `loginextra.php` contain branches for CAS, HTTP, and SQL-SSL auth. This tree's `header.inc.php` does not set `auth_type`. The active auth type is stored outside this file (typically eGroupWare configuration) and is **Unknown / Requires Confirmation**.

`loginextra.php` is a second login screen (eGroupWare `$Id` updated 2016-11-22 by JeanThirion). It is not a Quantivia-specific identity provider. Provenance: **Implemented** as an eGroupWare login variant.

There is no `auto_login.php` in this tree.

## Main workflows

### W1 — Sign in

Trigger: user opens `login.php` or `loginextra.php`.

Expected behaviour:

- If `header.inc.php` is missing or the API cannot be created, the browser is sent to `setup/index.php`.
- Credentials are validated by the configured eGroupWare auth type.
- Session cookies are established.
- The user may then open Quantivia via `quantivia/main.php`. `quantivia/index.php` requires `sessionid` and redirects to `main.php`.

Provenance: **Implemented**.

Missing cookie: redirect to `../index.php` (eGroupWare front). `common_functions.inc.php` responds with HTTP 403 when `sessionid` is absent.

### W2 — Select project or portfolio

Trigger: authenticated user selects a project, or a portfolio view.

Expected behaviour:

- Current project id is stored in the Quantivia session (`p_id`).
- Portfolio view uses `p_id == '-1'` and multi-project session key `mp_id`. Menu label becomes "Portfolio".
- In portfolio view, project-admin and view flags are the OR of the selected projects. Project status starts as `control` and becomes `define` if a status check fails. The status call inside that loop passes `$p_id` (the sentinel `-1`) rather than each selected project id. Provenance: **Implemented** (`Menu.php`). Whether that is intentional is **Unknown / Requires Confirmation**.

### W3 — Configure a project

Trigger: Site Admin manages projects and users; Project Admin configures categories, budget structure, tracking, and theme.

Expected behaviour (menu comments and links in `Menu.php`):

- Site Admin: Project List, Users Admin, Programme Admin.
- Project Admin and view users: Project List, project categories, Budget Structure.
- Actual Hours Structure is enabled only when the project's timekeeping method is `Structured`. Otherwise the menu item is disabled with the tooltip "This menu option can only be used on projects with Structured time keeping."
- Project Admin: Tracking Admin, Theme Admin.

Provenance: **Implemented** (`Menu.php`). Field-level create steps are also in the user guide (**Documented**).

### W4 — Load deliverables, schedule, and progress

Trigger: Project Admin uses upload wizards.

Expected behaviour (`Menu.php` disable rules):

- Deliverable upload, chain-assignment upload, schedule upload, and resource update are blocked while project status is `control`.
- Progress upload is allowed only while status is `control`.
- Actual hours update is allowed only while status is `control`.
- Heavy work can be handed to `worker.php` task types (deliverables, assignments, schedules, progress, time, resources).

Provenance: **Implemented**. The user guide documents the wizard sequence (**Documented**). Whether uploads are offloaded on the host named in settings is **Unknown / Requires Confirmation** (the offload URL points at `online.quantivia.com`, while databases point at localhost).

Primavera P6 import accepts `.xer`, zip, and XML (`forms/p6import.php`). Provenance: **Implemented**.

### W5 — Online progress update

Trigger: a progress package is issued, the user submits, an admin reviews.

Lifecycle statuses in `quantivia_bo::$view_statuses`:

`Invalid` (0 and 9), `Issued`, `Submitted`, `Reviewed`, `Archived`, `Rejected`, `Void`, `Proposed To Delete`, `Expired`.

Email subjects are built as "Quantivia Progress Status Request…". Sending uses `class.quantivia_notifier.inc.php` (PHPMailer SMTP, default host `localhost`, port `25`). Mail suffix and SMTP credentials are read from Quantivia config when present. They are not set in `quantivia_setings.php`. Provenance: **Implemented**. Which SMTP server a deployment uses is **Unknown / Requires Confirmation**.

### W6 — Publish a report and view graphs

Trigger: Project Admin publishes.

Expected behaviour:

- Publish is disabled unless project status is `control`, with the message "A report cannot be published when the project is not in the 'Control' status."
- S-curve, bulls-eye, trend, resource (FTE), Pareto, and latency charts, plus several tabular reports, are disabled until a published report exists ("No published reports exist.").
- Resource S-curves and resource tabular reports are not gated on that condition in this file (`false` is passed to the disable check).
- Chart JSON is served from `quantivia/services/*.json.php`.
- Publish itself is worker task type 6 (`publish_report`).

Provenance: **Implemented** (`Menu.php`, `worker.php`, `services/`).

### W7 — Change control

Trigger: budget is locked, then a change instance is opened or closed.

Project status (`what_is_project_status`):

- `define` when `P{id}_budget_locked` is not set.
- `control` when locked and no open change instance exists.
- `change` when locked and an open change instance exists.

While status is `control`, schedule changes return false or the message "Project locked, use change control". While `define`, planned dates are written as the initial setup. While `change`, from/to values are stored on the change session.

Provenance: **Implemented**. The user guide has a Change Control topic (**Documented**).

### W8 — Dashboard

Trigger: Project Admin or view user opens Dashboard.

Expected behaviour: `dashboard/Dashboard.php` (and `Dashboard2.php` through `Dashboard4.php`) plus widgets for overall progress, overall performance, deliverables, control points, budget, S-curve, week, category tables, and a legend. The tip commit message is "#87 Lines to all dashboard tables". Provenance: **Implemented**. The exact visual change in that commit versus `99550c77` was not diffed widget by widget.

Calendar is shown only when the project config attribute `P{id}_extended_features` is set (`what_is_project_ft_count`). Provenance: **Implemented**.

## Functional requirements

### FR-001 — Session gate

The system redirects unauthenticated requests away from Quantivia.

- Actor: any visitor.
- Trigger: open `quantivia/index.php` or `quantivia/main.php` without `sessionid`.
- Expected: redirect to the eGroupWare index. `common_functions.inc.php` returns HTTP 403 if included without `sessionid`.
- Evidence: `quantivia/index.php`, `quantivia/main.php`, `common_functions.inc.php`.
- Implementation: Implemented. Confidence: High.

### FR-002 — Role groups

Access is derived from eGroupWare groups `Admins`, `P_{id}`, `P_{id}_admin`, and `P_{id}_p_admin`, plus the project `administrator` column.

- Actor: authenticated user.
- Expected: Site Admin, Project Admin, Progress Admin, and Project User flags as coded in `class.quantivia_so.inc.php`.
- Page checks call `checkCurrentUserAutherization()` and return HTTP 401 with a translated denial message.
- Evidence: `class.quantivia_so.inc.php`, `common_pageSetup.php`.
- Implementation: Implemented. Confidence: High.

### FR-003 — Project lifecycle

A project is in exactly one of `define`, `control`, or `change`, derived from the budget-locked flag and an open change instance.

- Evidence: `what_is_project_status()`.
- Implementation: Implemented. Confidence: High.

### FR-004 — Wizard gates follow lifecycle

Uploads that change structure are refused in `control`. Progress and actual-hours uploads are refused unless status is `control`. Publish is refused unless status is `control`.

- Evidence: `Menu.php` disable messages.
- Implementation: Implemented (menu layer). Whether every form repeats the same check server-side was not verified for every endpoint. Confidence: Medium for server-side enforcement beyond the menu.

### FR-005 — Performance reporting

The product calculates and displays earned-value style results using configurable methods:

- Reporting method: RAMP or STEP.
- Forecasting: Original Duration, Current Trend, Remaining Duration.
- EAC: Budget Rate, CPI, CPI and SPI compounded, CPI and SPI (80:20).
- Budget overflow: Remaining Budget or Current Budget.
- Timekeeping: Structured, Detailed, or None.

Evidence: static arrays on `quantivia_bo`. Implementation: Implemented as coded options. Confidence: High that the options exist. Confidence: Medium on every formula; formulas live in the large BO class and were not re-derived here.

### FR-006 — License gate

Full-license features call `requireFullLicence()`. If `$_SESSION['licensed']` is false, the response is HTTP 401 and the text "This system is in Demo mode, and can not use this function".

License state is set in `common_functions.inc.php`:

- MAC from the license constants must match a local MAC, and `L_DOMAIN` must equal `SERVER_NAME`, before `licensed` is set. `L_TYPE` containing `Q` sets quantity licensing; containing `E` sets extended features.
- Named hostnames skip that check and force licensed, extended, and quantity flags, with `N_PROJECTS` 25 and company name `Procon8`. The names include `demo.quantivia.com`, `online.quantivia.com`, `quantivia.local.com`, `localhost`, `127.0.0.1`, and several Procon8 dev hosts.

Evidence: `common_functions.inc.php`, `common_pageSetup.php`, `who_is_who_in_the_zoo.php`. Implementation: Implemented. Confidence: High.

### FR-007 — Per-client branding

The active template folder is `$_SESSION['template']`. Seventeen `templates_*` packs ship a `user_guide.php`. `version.php` forces `templates_procon8_01` for the worker/license endpoint.

Implementation: Implemented. Which pack a given customer must use is **Unknown / Requires Confirmation**.

### FR-008 — Offloaded work

`worker.php` executes task types 0 through 15 (maintenance, deliverable import, chain assignment, schedule, progress, time, publish, several downloads, resource import and resource actuals). Task type 11 (commented "Time Download") has an empty body.

Implementation: Implemented. The schedule that invokes the worker in production is **Unknown / Requires Confirmation**. `QFD/worker.vbs` calls `http://quantivia.local.com/quantivia/inc/worker.php` in a loop whose counter never increments.

### FR-009 — eGroupWare companion apps

The tree includes standard eGroupWare apps and custom trackers (NCR, risk, permits, shipments, works orders, actions). They are separate apps with their own setup registration. They are not the Quantivia progress database.

Implementation: Implemented as shipped code. Which of them are enabled in a running database is **Unknown / Requires Confirmation** (enable flags exist in setup files; runtime app list is data).

## Integrations

| System | Direction | Trigger | Data | Auth | Failure |
|---|---|---|---|---|---|
| eGroupWare MySQL `demo` | Read/write | Login, groups, accounts | Accounts, groups, sessions | SQL user in `header.inc.php` | Not separately handled in Quantivia; EGW setup/login fails closed to setup |
| Quantivia MySQL `demoppr` | Read/write | Quantivia pages and worker | Projects, deliverables, reports | SQL user in `quantivia_setings.php` | Not fully traced. Empty password is committed |
| Offload host | Outbound HTTP | Settings `ofload_location` | Offload URL hard-coded to `https://online.quantivia.com/quantivia/inc/ofload.php` | Unknown | Unknown |
| SMTP | Outbound | Progress status mail | HTML body via PHPMailer | Optional SMTP auth from Quantivia config | Timeout 15 seconds in notifier. Further failure behaviour **Unknown** |
| Primavera P6 | Inbound file | Project Admin upload | `.xer`, zip, XML | Session | Message: function supports only those types |
| AWS CodeDeploy | Deploy only | Old pipeline script | Zip of the tree to S3, then a deployment | Env vars `S3_BUCKET`, `APPLICATION_NAME`, `DEPLOYMENT_GROUP_NAME`, `DEPLOYMENT_CONFIG` | Script prints the boto3 error and returns false |
| License file | Local | Every Quantivia request that includes `common_functions.inc.php` | MAC, domain, project count, license type | Machine MAC | Unlicensed session stays `licensed = false`; company label "Unregistered - Demonstration Only !" |

## Important constraints

- PHP timestamp ceiling is hard-coded to `2147472000` (19 Jan 2038 00:00:00 UTC) and must fall on midnight (`common_functions.inc.php`). Timezone is forced to UTC.
- Reporting periods in settings: `report_period` and `time_report_period` are `4` (comment: weeks).
- CSV separator in settings is comma.
- File retention flag `file_retention` is true. Storage path is a Windows directory.
- Two version strings exist. Settings assign `1.2.000`. `common_functions.inc.php` then sets the version to the last changelog key, `2.0.013`, plus SO 216 and BO 276. Callers that include `common_functions` see `2.0.013`.
- `quantivia_setings.php` defines `EGW_SERVER_ROOT` as its own directory (`quantivia/setup`). Root `header.inc.php` defines `EGW_SERVER_ROOT` as the repository root. Which value is in force depends on include order.

## Non-goals observed in this tree

- No mobile-native client. `forms/Mobile.php` exists; it was not fully read. Treat a dedicated mobile product as **Unknown**.
- No Docker or nginx definition.
- No root product test suite.

## Open points

- Production hostname, database names, and whether the committed localhost/`demoppr` settings are only a demo snapshot.
- Whether `development` (`ba5f6c5`) replaced `master` for version 2.
- Whether menu disable rules are duplicated in every form action.
- Runtime auth type (SQL vs LDAP vs the other branches in `login.php`).
- Whether task type 11 was left unfinished on purpose.
