# PRD — neoafrica_qa

Evidence date: 2026-10-09.

Source: `git@bitbucket.org:overdrive/neoafrica_qa.git`, `main` at `3f8d683` (2026-06-19).

There is no prior PRD in Silicon Ark. The source repository has a one-paragraph README, an environment checklist, an e-hailing feature note, and a CSV test pack. Requirements below are recovered from those documents, the web and API projects, and SQL scripts. Provenance is labelled. Credential values are omitted.

## Product purpose

**Documented.** `Environment_Readiness_Checklist.md` describes Legitimate Licences as web applications, an API, Windows services, a desktop application, and SQL Server databases, for dev, test, and production. `README.md` points only at the NPTR e-hailing app-provider module.

**Implemented.** The web solution is a staff application (forms login, anonymous users denied) that hosts workflow modules for operating licences, accreditations, routes, vehicles, members, gazettes, adjudication, verification, reports, and e-hailing providers.

**Inferred.** This is the regulator back office for NPTR and PRE operating-licence administration, including migration from older OLAS and LTPS data. The inference comes from division comments in SQL, report folders named `NPTR Reports`, and migration scripts titled OLAS and LTPS. It is not stated as a product goal in a PRD.

**Unknown / Requires Confirmation:** the legal name of the customer, which provinces are live, and whether "Neo Africa" is the product brand or only the internal codebase name.

## Users and interactions

| Actor | What they do | Evidence | Status |
|---|---|---|---|
| Authenticated staff user | Signs in with username and password. Optional fingerprint. Uses consoles and workflow tasks | `AuthController.SignIn.cs`, `Web.config` forms auth, `<deny users="?" />` | **Implemented** |
| NPTR user | National division (`DivisionTypeID = 2`). E-hailing registry and 14-day gazette period for provider applications | `docs/EhailingProviders.md`, gazette settings script | **Documented** and **Implemented** in SQL/docs |
| PRE user | Provincial division (`DivisionTypeID = 1`). Scholar gazetting rule. Metered-taxi conversion type 63 is PRE only | Scholar script header; type 63 script header | **Documented** in SQL comments |
| Inspector | Inspection lists and scheduling; applicant name and SMS | `Pr_ApplicationsAwaitingInspectionsGet.sql`, `Pr_InspectorInspectionsGet.sql`, `1164_InspectionScheduling_ApplicantNameAndSms.sql` | **Implemented** in SQL. The job title "inspector" is **Inferred** from those names |
| Adjudicator | Captures a decision. E-hailing issue/reissue requires the adjudication approval securable | `docs/EhailingProviders.md` | **Documented** for e-hailing. General adjudication UI exists (`AdjudicationConsole`) |
| Desktop operator | Prints and scans via the desktop client and ActiveX controls | Checklist sections 4.1 and 4.2; API printing and scanning methods | **Documented** in the checklist, **Implemented** as projects and API methods |
| System account | Windows service loads services and runs them as the system user id from the database | `DatabaseServiceScheduler.Start` | **Implemented** |
| Applicant / operator | Captured as member and application data. Receives email and optional SMS. E-hailing notifications go to applicant email and optionally a proxy email | E-hailing doc notifications section | **Documented** as a data subject. Whether they have a login is **Unknown** |
| Anonymous public user | No route is allowed without a forms login | `Web.config` authorization | **Implemented** as denied |

Securable names that are explicit for e-hailing:

- `ApplicationsModule_Home_StartNewApplication` — start an application.
- `ApplicationsModule_ApplicationRequest_Adjudication_CaptureDecision` — capture an adjudication decision.
- Registry read: NPTR or PRE, and `ehailing.providers.enabled` must be TRUE. A dedicated securable is described as optional and not required yet.

Provenance: **Documented** in `docs/EhailingProviders.md`.

## Major workflows

### Operating-licence application (general)

**Inferred** end-to-end path from module names, workflow controllers, and SQL step checks. A single narrative document of every step was not found.

1. Staff start an application of a chosen `ApplicationRequestType` (seeded types 1–38, plus later types 60–63).
2. Capture applicant, documents, vehicles, and routes. Step check functions such as `Fn_ApplicationStep3Checks` enforce data gates.
3. Verification queue. `MessageHub` broadcasts add, assign, and remove events to all connected clients.
4. Referral to an authority where the workflow requires it (referral scripts from 2024 onward).
5. Gazette when the division/type rule says so, then inspection where required, then adjudication.
6. Issue, renewal, transfer, cancellation, or upliftment through the matching request project.
7. Letters and reports (DevExpress and SQL report definitions), including NPTR pre- and post-adjudication letters.

### E-hailing app provider registration (NPTR)

**Documented** in `docs/EhailingProviders.md` and **Implemented** by the 2025 provider SQL chain and `ProvidersRegistry` / `AppProviderIssueRequest` projects.

1. Feature flag `ehailing.providers.enabled` must be TRUE or the start-application chooser hides types 60, 61, and 62 and the registry nav is hidden. Endpoints stay RBAC-guarded.
2. Type 60 new, 61 renewal, 62 amend conditions. Display titles after script `1103` drop the `NPTR:` prefix.
3. Payment reuses the payment-details console. The documented fee is R5 000. The QA pack expects that amount.
4. On approval of type 60, NPTR generates a certificate. Number format `NPTR-EHP-YYYY-####`. Expiry is issued date plus 7 years.
5. Types 61 and 62 reissue a new number and keep history via `ReissuedFromID`.
6. Registry search for NPTR or PRE: `GET /ProvidersRegistry/Search`.
7. Email templates in `Crm.MessageTemplates` for submission, approved, rejected, issued, and reissued. Return-for-correction email is documented as not wired.

### Gazette

- NPTR gazettes that contain types 60, 61, or 62 use notice expiry of print date plus 14 days (`GazettePeriodDaysEhailing`). PRE uses 21 days.
- "Bypass expiry date" in the Gazette Console is for e-hailing only, and only when `AllowBypassGazetteExpiryForEhailing` is TRUE. The script default inserted is TRUE, with a comment to use FALSE in production.
- Scholar service on a PRE new operating licence (type 1): contracted answer sets `IsGazettingBypassed` and the application does not gazette; a non-contracted scholar does gazette. NPTR is left unchanged. **Documented** as a requirement in the script header.

### Metered taxi to e-hailing (PRE)

Application type 63, title `Conversion of Metered Taxi to E-hailing`. Script header: PRE only, all provinces except National (province id 10), gazette required, adjudication meeting required, inspection required. Seeded cost is 0.00 with the comment that the fee is governed by tariff configuration.

### Corrections that skip payment

When a workflow task is completed with status 2 or 4 and another task in the same instance has status 5 (Requested Correction) at a later step, the next step is the step that requested the correction, not the template's normal next step. The script comment says this is how an application change request returns to payment without taking the normal path, and that other statuses are unchanged.

### Authentication

1. `GET` login page, `POST` `SignInUser` with username, password, and optional fingerprint.
2. Forms ticket, sliding expiration, 30 minutes (`Web.config`).
3. Forgot-password uses a security question. Membership is configured with `requiresQuestionAndAnswer="true"`.
4. Password reset of the signed-in user takes old and new password.
5. Fingerprint enrolment uses DigitalPersona FMD import. App setting `FingerprintAuthenticationEnabled` exists. Whether it is on in each environment is **Unknown**.

## Functional requirements

### FR-001 — Staff sign-in

The system requires an authenticated user for web pages. Sign-in accepts a username and password and can capture a fingerprint.

- Trigger: user opens the site or a session expires.
- Inputs: username, password, optional fingerprint template.
- Behaviour: forms login URL `~/Auth/Login`. Anonymous users are denied. Timeout is 30 minutes with sliding expiration.
- Error: security and general error actions exist (`ErrorController`).
- Evidence: `Web.config` authentication and authorization; `AuthController.SignIn.cs`.
- Implementation: **Implemented**.
- Confidence: High.

### FR-002 — Start and process an application

A permitted user can start an application of a configured type and move it through workflow tasks (approve, reject, cancel, escalate, request change, return escalation, submit).

- Evidence: `Applications` and `ApplicationRequest` projects; shared views under `Views/Shared/Afx/Actions/`.
- Implementation: **Implemented**.
- Confidence: High for the existence of the actions. The exact status machine for every type was not fully traced.

### FR-003 — Application type catalogue

The system stores application types with a fee amount and flags for which source systems the type applies to (OLAS, LTPS, LG).

- Evidence: `Md.ApplicationRequestTypes` inserts in `DBUp/Scripts/Migration/Step 1 - OLAS Data Seed.sql`, plus types 60–63 in later scripts.
- The seeded fees are data, not proof of the current tariff. See business rules.
- Implementation: **Implemented** as seed data.
- Confidence: High that the seed exists. Medium that those amounts are still charged.

### FR-004 — Verification queue live update

When a verification task is added, assigned, or removed, connected browsers are notified.

- Evidence: `Hubs/MessageHub.cs` methods `AddVerificationToList`, `SetVerificationAsAssigned`, `RemoveVerificationFromList`, each calling `Clients.All`.
- Implementation: **Implemented**.
- Constraint: the hub methods do not show an authorization check in that file. **Requires confirmation** that the SignalR pipeline authenticates the connection.

### FR-005 — Documents, correspondence, and comments

Users can attach documents, send SMS from the correspondence UI, and record comments and audit entries on a workflow.

- Evidence: `AfxController.Documents.cs`, `AfxController.Correspondence.cs`, `Views/Shared/Afx/Correspondence/SendSMS.cshtml`, comment and audit controllers.
- Implementation: **Implemented**.
- Confidence: High that the screens exist. SMS delivery depends on Clickatell configuration (**Unknown** per environment).

### FR-006 — eNatis vehicle lookup

The web application can call eNatis login and query URLs using a client certificate and configured account.

- Evidence: `Web.config` app settings `eNatisLoginURL`, `eNatisQueryURL`, `eNatisCertificatePath`, `eNatisCertificatePassword`, `eNatisUsername`, `eNatisPassword`, `eNatisOpModInd`, and related terminal fields. Checklist names the production host `ifprod.enatis.co.za`. Git history from 2025-01-17 records "eNatis integration".
- Implementation: **Implemented** as configuration and subsequent fix commits. The live mode (`LIVE` versus a test mode) is an environment value and was not read out.
- Confidence: High that the integration exists. The checklist's stored secrets are not repeated here.

### FR-007 — Operating licence and route registers

Staff can search and maintain operating licences, routes, members, associations, and vehicles through consoles.

- Evidence: view folders `OperatingLicences`, `OperatingLicenceConsole`, `Routes`, `RouteConsole`, `Members`, `MemberConsole`, `Associations`, `AssociationConsole`, `Vehicles`, `VehicleConsole`.
- Implementation: **Implemented**.
- Confidence: High.

### FR-008 — Accreditations

Staff can request a new accreditation, renew it, add an operating licence, issue it, or cancel it.

- Evidence: projects `AccreditationIssueRequest`, `AccreditationCancelRequest`, `AccreditationConsole`, `Accreditations`. Seeded types 31, 32, 33, 38.
- Implementation: **Implemented**.
- Confidence: High.

### FR-009 — Gazette production

Staff produce a gazette. For NPTR e-hailing applications the notice period is 14 days. PRE uses 21 days. A bypass control exists for e-hailing when the setting allows it. A zero region returns all rows in the print procedure after the 2026 bugfix script.

- Evidence: `docs/EhailingProviders.md`; `74_E-Hailing App Provider Gazetting/System_Settings_GazetteEhailing.sql`; `74_BugFix_Pr_PrintGazetteReport_ReturnAllWhenRegionZero`.
- Implementation: **Implemented** in SQL and documented for the e-hailing period.
- Confidence: High for the settings. Medium that every province's gazette rule matches the scholar script's description outside type 1.

### FR-010 — E-hailing provider registry

An NPTR or PRE user, when the feature flag is TRUE, can search providers by name, registration number, or certificate number, filter by status (Active, Expired, Cancelled), and optionally by days until expiry.

- Inputs: `q`, `status`, `expiringWithinDays`, `page`, `pageSize`.
- Output: `Success` and `Result.items` plus `total`, as in the e-hailing doc.
- Evidence: `docs/EhailingProviders.md`; `Verified.Vw_ProviderRegistry` scripts; `Neo.LegitimateLicences.ProvidersRegistry`.
- Implementation: **Implemented** (doc plus SQL and project). The HTTP method body was not re-read line by line beyond the doc and project presence.
- Confidence: High.

### FR-011 — Issue and reissue a provider certificate

On approval, an authorised user issues or reissues a certificate. Issue upserts the provider by business registration number and inserts a certificate. Reissue inserts a new certificate pointing at the previous one. Both send email. The documented duration is seven years. A later script is named `1106_App_Pr_IssueProviderCertificate_Alter_Duration.sql`.

- Evidence: `docs/EhailingProviders.md`; issue and reissue SQL files listed in that doc.
- **Requires confirmation:** whether script 1106 changed the seven-year duration. This pass did not open that procedure body.
- Implementation: **Implemented**.
- Confidence: Medium on the exact expiry rule after script 1106.

### FR-012 — Provider certificate printing

The API returns print data for a verification token, including a `ProviderCertificateData` shape (legal name, certificate number, issue and expiry, registrar, reprint and test-print flags).

- Evidence: `LegitimateLicencesApiController.Printing.cs`.
- Implementation: **Implemented**.
- Confidence: High that the DTO exists.

### FR-013 — Desktop print and scan

The desktop client obtains print or scan payloads from the API and uploads a scanned document.

- API: `GetPrintoutData(verificationToken)`, `GetScanningData(scanToken)`, `UploadScannedDocument`.
- Checklist: custom protocol `legitimatedesktop`; ActiveX printing for accreditation certificates and decals, operating licences, payment advice, receipts, and temporary licences.
- Implementation: **Implemented** as API and projects. End-to-end device behaviour was not executed.
- Confidence: High for the API surface. Medium for the protocol registration, which is checklist text.

### FR-014 — Reports

Staff open a report list and a report definition. Report projects cover application, member, route, operating licence, NPTR letters, IT audit, general, and a `Hidden` folder.

- Evidence: `ReportsController`, `Neo.LegitimateLicences.Reports` subfolders.
- Implementation: **Implemented**.
- **Unknown:** which reports are hidden in production and why the `Hidden` folder exists.

### FR-015 — Scheduled jobs

A Windows service named `DatabaseServiceScheduler` reads services from the database and runs each on its poll schedule. It records start failures to an audit log and continues with the other services.

- Evidence: `ConfigureService.cs`, `DatabaseServiceScheduler.cs`.
- Implementation: **Implemented**.
- **Unknown:** the production service catalogue (which SMS, cleanup, and trigger jobs are rows in the Services table). `122_Pr_Svc_CleanseUnusedVehicleData.sql` shows at least a vehicle-data cleanse procedure.

### FR-016 — Database update on web startup

On application start the site runs DbUp against `ConnectionString` for embedded scripts whose resource name contains `Legitimate`. Failure is caught and written with `Debug.WriteLine`. The site still starts.

- Evidence: `Global.asax.cs`, `DBUp/DatabaseUpdator.cs`.
- Implementation: **Implemented**.
- The upgrade result object is not checked after `PerformUpgrade`.
- Confidence: High.

### FR-017 — Scholar contracted-service question

For a PRE new operating licence, the operator is asked whether the scholar service is contracted. Contracted applications bypass gazetting. Non-contracted scholar applications gazette. NPTR is unchanged.

- Evidence: `121_Scholar_Contracted_Gazetting_Rule.sql` header, which calls this a requirement. Git history: branch `#152_Scholar-service--add-question-to-drive-gazetting` merged 2026-06-10.
- Implementation: **Implemented** in that script.
- Confidence: High for the SQL rule. The UI question text was not opened in this pass.

### FR-018 — Historical data migration

Migration scripts load OLAS data, master data, routes, licences, associations, DOT users, and accreditations.

- Evidence: `DBUp/Scripts/Migration/Step 1` through `Step 7`.
- Implementation: **Implemented** as scripts. Whether they are still executed on new environments or were one-time is **Unknown**. The checklist says to run `DBUp/Scripts/Migration/`.

## Integrations

| System | Direction | Trigger | Data | Auth | Failure |
|---|---|---|---|---|---|
| SQL Server (`LegitimateNational`, and `LtpsEntities` / KZN LTPS) | App to database | Every module | Applications, workflow, verified registers | Connection strings in config. Checklist describes a SQL login. Password omitted | Web startup logs DbUp failure and continues. Other calls were not catalogued |
| eNatis | Outbound HTTPS | Vehicle validation | Login and query. Checklist host `https://ifprod.enatis.co.za:4443/...` paths `X0000` and `X1001` | Client certificate file plus username and password settings | Git history records several eNatis fix commits. Exact user-facing error text was not extracted |
| Clickatell | Outbound | SMS send, including inspection scheduling scripts | Message text | API id, username, password passed into `SmsVodazone`, which authenticates on construct | Constructor throws the innermost message if authenticate does not return `OK:` |
| Sentry | Outbound | Unhandled errors and EF | Exceptions, traces | DSN app setting | Not described. `Debug = true` and `TracesSampleRate = 1.0` are set in code |
| SonarQube | CI outbound | Push or pipeline on `main` | Source scan | `SONAR_TOKEN` variable | Pipeline definition has no other failure step |
| Desktop protocol host | Local | User opens `legitimatedesktop` | Print and scan tokens | API claims (`UserID`) | **Unknown** beyond API `IsValidClaim` |
| Neo.Afx master tree | Developer machine copy | Manual bat file | Assemblies | Local paths under `C:\Development\NeoAfrica` | The bat file `pause`s; it is not a service |

API CORS is `origins: "*"`, `headers: "*"`, `methods: "*"` on `LegitimateLicencesApiController`. That is **Implemented**. It is a wide allowance and **Requires confirmation** that it is intended.

## Important constraints

- .NET Framework 4.6.2 and IIS. Checklist says the main site app pool is 4.6.2.
- Forms authentication. Membership `passwordFormat="Clear"` is set in `Web.config`. Passwords are configured to be stored without hashing. **Requires confirmation** that this is still accepted.
- Anonymous HTTP is denied on the web app.
- E-hailing UI is flag-gated. API and page endpoints for that module stay permission-checked when the flag is off, according to the feature doc.
- DbUp script filter keeps only embedded resources whose name contains `Legitimate`. A script that is not embedded does not run at startup.
- Certificate numbering for providers is `NPTR-EHP-YYYY-####`.
- Business registration number is unique on `Verified.PlatformProviders`. Certificate number is unique on `Verified.ProviderCertificates`.

## Behaviour that is documented as not done

From `docs/EhailingProviders.md` known limitations:

- No provider API for real-time suspensions or expulsions. Manual update only. Marked future.
- Returned-for-correction email is not wired.
- No QR code on the provider certificate. The doc says the client asked to skip it.

These are **Documented** limitations, not inferred gaps.

## Requirements traceability notes

| ID | Primary evidence | Implementation |
|---|---|---|
| FR-001 | `Web.config`, `AuthController.SignIn.cs` | Implemented |
| FR-010 | `docs/EhailingProviders.md`, provider SQL, `ProvidersRegistry` | Implemented |
| FR-016 | `Global.asax.cs`, `DatabaseUpdator.cs` | Implemented |
| FR-017 | `121_Scholar_Contracted_Gazetting_Rule.sql` | Implemented |

## Unknown / requires confirmation

- Live tariff versus seeded `Cost` values.
- Effect of `1106_App_Pr_IssueProviderCertificate_Alter_Duration.sql` on the seven-year rule.
- Which DbUp files are embedded versus present only on disk.
- Production URLs, office list, and which division each office serves.
- Whether fingerprint login is mandatory anywhere.
- Intended audience of the API given CORS `*`.
- Whether applicants can authenticate.
- Contact block in the checklist is still the placeholder text `[Contact Info]`.
