# Business rules — nltis

Evidence date: 2026-10-08. Revision: `main` `a9ea681` (2024-11-24).

No business-rules document exists in the source repository. Rules below are taken from code. Each rule is marked **Inferred** when the code does not state it as policy, even if the behaviour is clear.

The repository does not contain NLTIS domain rules. Rules here are Neo Application Framework rules found in this tree. Stored procedures such as `Pr_SaveUser` are called and not defined here, so database rules beyond the call are **Unknown**.

SQL password values are omitted.

## Identity of the system

| Rule | Label | Evidence |
|---|---|---|
| The product name in assembly metadata is Neo Application Framework, company Neo Africa | Implemented | `Neo.Afx.Core/Properties/AssemblyInfo.cs` |
| The git repository name `nltis` is not used by the application | Implemented | Search of the tree finds no `nltis` |
| Default database catalog is `EPWP` on `(local)` | Implemented | Connection strings in `Web.config` and `App.config` |
| Release web transform points several EF contexts at `GROUPER\DEV09` / `VectorWorkflowsLive` | Implemented | `Neo.Afx.Services.Web/Web.Release.config` |

**Unknown / Requires Confirmation:** whether EPWP or VectorWorkflowsLive is an approved production catalog for whatever `nltis` was meant to be.

## Users and access

| ID | Rule | Label |
|---|---|---|
| BR-001 | Console actions require an authorized ASP.NET user. The attribute is `[Authorize]` with no role list | Implemented. `UserConsoleController`. The console `Web.config` does not configure authentication |
| BR-002 | The actor id passed into security writes is `Profile.UserID`, not the `UserID` of the record being edited | Implemented |
| BR-003 | The controller does not check that the actor may edit the target user | Implemented (absence of a check) |
| BR-004 | Active status written by the console is `1`. Inactive status is `2` | Implemented. Comments in `ActivateUser` and `DeActivateUser` name those meanings |
| BR-005 | Saving roles sends only selected role IDs, comma-separated. Clearing all roles sends an empty string | Implemented. `SaveUserRoles` |
| BR-006 | A fingerprint is stored as bytes converted from a hex string | Implemented. `SaveFingerprint` |
| BR-007 | Workflow service user name is the authenticated identity name in lower case, or empty when anonymous | Implemented. `WorkflowService.UserName` |
| BR-008 | Membership defaults, if the provider is configured with missing attributes: 5 invalid attempts, 10 minute window, minimum length 7, at least 1 non-alphanumeric, unique email required, question and answer required, reset and retrieval enabled, format Hashed | Implemented as `Initialize` defaults. Not wired in tracked config |
| BR-009 | Password hash is SHA1 of UTF-8 bytes, Base64. Salted hash is SHA1 of `password + salt`. SQL `HashPassword` calls `SecurePassword.Hash` without a salt | Implemented. `SecurePassword.cs`, `Authentication.cs` |

**Inferred:** status `1` and `2` match a user-status lookup in the database. The lookup table is not in this repository.

**Unknown:** lockout behaviour in production. The provider supports `UnlockUser` and invalid-attempt limits, and no site config sets them.

## Workflow

| ID | Rule | Label |
|---|---|---|
| BR-010 | Task statuses 1 through 11 are Outstanding, Approved, Rejected, Completed, RequestedCorrection, Cancelled, ReAssigned, New, Error, OnHold, Expired | Implemented in both workflow enums |
| BR-011 | The data-layer enum also has Override = 12, Escalated = 13, EscalationSentBack = 14. The worker enum does not | Implemented. Two files disagree |
| BR-012 | Step types are Approval = 1, DataCapture = 2, ParallelTasks = 3, Automated = 4 | Implemented. `WorkflowTemplateStepTypeEnum` |
| BR-013 | A background task with no `WorkflowTaskHandlerID` is skipped | Implemented. `WorkflowTaskProcessor` |
| BR-014 | A handler that returns status `0` or below does not update the task | Implemented. Comment: "Don't update task if status is zero" |
| BR-015 | A handler exception sets status Error (9), stores `ERROR: {message}` as comments, and calls `RaiseException` | Implemented |
| BR-016 | If the status update itself fails, the processor calls `UpdateTaskStatusFailover` and records the failure in the trace | Implemented. Comment: "Something horrible happened so stop the workflow" |
| BR-017 | `DefaultTask` succeeds without doing work | Implemented. Comment: "A task that does nothing and is always successful." |
| BR-018 | Escalation can be returned to the original user when `returnEscalation` is true | Implemented as a parameter. `EscalateWorkflowInstanceTask` |
| BR-019 | Reassign, escalate, cancel, and task action accept a comments string. The service does not require it to be non-empty | Implemented |
| BR-020 | Handlers are created once per processor lifetime from `GetHandlers()`, keyed by `WorkflowTaskHandlerID`. A constructor exception is traced and that handler is omitted | Implemented |

**Inferred:** workflow templates, assignees, and handler type names are data, not code. Changing a process does not require a code change if the handler type already exists.

**Unknown:** who may approve, reject, or cancel. `WorkflowInstanceTaskCanAssignToMe` exists. Its rule is inside the data layer or SQL, which was not fully expanded.

## Queries, correspondence, notifications

| ID | Rule | Label |
|---|---|---|
| BR-021 | Query status is InProgress = 1, Resolved = 2, Cancelled = 3, Completed = 4 | Implemented. Comments repeat the names and do not define a difference between Resolved and Completed |
| BR-022 | Creating a query can set type, source, entity, item, role assignee, user assignee, an assign-date flag, description, response email, and response contact address | Implemented. `QueryService.Create` |
| BR-023 | Message type Email = 1 and Sms = 2 | Implemented in both correspondence and message-worker enums |
| BR-024 | SMS delivery method Vodazone = 1 uses the Clickatell COM API. Swift = 2 uses Swift | Implemented. Class comment on `SmsVodazone`: "sending SMS's using the Clickatell (Vodazone) API." |
| BR-025 | Email uses SMTP settings from the database, including host, port, SSL, and optional network credentials | Implemented. `EmailSender.InitializeSender` |
| BR-026 | A notification is tied to a user, entity, item, category, and type, and can be marked read | Implemented. `NotificationsService` |
| BR-027 | The audit web method only reads audits. It does not write them | Implemented. `AuditService.GetAudits` |

## Documents and forms

| ID | Rule | Label |
|---|---|---|
| BR-028 | The only document store type in the enum is SQL = 2. The comment cites `[Doc].[DocumentStoreTypes]` | Implemented. Other store types may exist in the database and are not represented here |
| BR-029 | A document location is anonymous (1) or network credential (2) | Implemented. `LocationAuthTypeEnum` |
| BR-030 | A scan session records entity, item, related field key, document type, optional existing document id, store location, and user | Implemented. `CreateScanSession` |
| BR-031 | Checklist template status is Pending = 1, Active = 2, InActive = 3, Cancelled = 4 | Implemented as an enum. No `FormService` class exists to enforce it |

## Validation

| ID | Rule | Label |
|---|---|---|
| BR-032 | An RSA ID number is valid only when it is 13 digits and the check digit matches the sum implemented in `IsValidRsaIdNumber`. Empty or wrong length is invalid. Date digits are not interpreted | Implemented |
| BR-033 | An RSA company registration number is valid when it matches `YYYY/NNNNNN/NN` (four digits, slash, six digits, slash, two digits). No check digit | Implemented. The method comment says "check digit validation" |
| BR-034 | An RSA trust number uses the same pattern as a company registration number | Implemented. `IsValidRsaTrustNumber` |
| BR-035 | Company and trust validators are not created by `RegisterNeoAfxSqlServer.sql`. The ID validator is created as `System.Fn_IsValidRsaId` | Implemented |

## Integration data sources

| ID | Rule | Label |
|---|---|---|
| BR-036 | A data source has a name, command type, connection string, connection type, request query, headers, response XSL, entity schema, cache flag, cache minutes, and optional network credentials | Implemented. `DataSourceField` |
| BR-037 | Connection types are SQL Server, OLE DB, ODBC, Oracle, and Web | Implemented |
| BR-038 | `GetData(name)` returns XML for the named source. `ClearCache(name)` drops that cache | Implemented. `IntegrationService` |
| BR-039 | Cache behaviour depends on `IsCacheEnabled` and `CacheMinutes` on the row. Rows are not in this repository | Implemented as fields. Runtime values unknown |

## Security behaviour that is visible in code

These are implemented behaviours, not a statement that they are approved policy.

| ID | Rule | Label |
|---|---|---|
| BR-040 | SQL login names `EPWP` and `Legitimate` are stored in config files, with passwords in the same files | Implemented. Passwords omitted from this document |
| BR-041 | WCF metadata HTTP GET is enabled and fault exceptions include exception detail | Implemented. `Neo.Afx.Services.Web/Web.config` |
| BR-042 | The SQL registration script turns `TRUSTWORTHY` on and sets the database owner to `sa` before creating the CLR assembly as `EXTERNAL_ACCESS` | Implemented. `RegisterNeoAfxSqlServer.sql` |
| BR-043 | Service trace writes WCF messages, including entire messages, to `Traces.svclog`, with a cap of 3000 messages | Implemented. Same `Web.config` |
| BR-044 | The HTTP module `IHttpModuleHelper` reads `Request.InputStream` on begin request so the body is available in classic mode | Implemented. Comment in `IHttpModuleHelper.cs` |

## Rules that are not in this repository

- Eligibility, tariffs, or case rules for a land-transport or learner-transport programme. Not present. Do not treat the slug `nltis` as evidence of those rules.
- Contents of workflow templates, handler type names, mail settings, and integration data-source rows.
- The body of `Pr_SaveUser` and other stored procedures.
- Whether a buddy may act on tasks, and which roles may assign roles.
- Password policy actually configured on a running site.
