# Technical documentation — nltis

Evidence date: 2026-10-08. Revision: `main` `a9ea681` (2024-11-24, Jaco Brits, `jaco@overdrive.co.za`, message `new repo`).

Remote: `git@bitbucket.org:overdrive/nltis.git`. Branch: `main` only. No tags.

The scan-host copy named on the onboarding issue was not on this machine. This note is from a clone of `a9ea681`.

Passwords that appear in config files are not copied here.

## What this tree is

A single-commit import of the Neo Application Framework (Neo Africa, assembly version 1.0.0.0, copyright 2020). The git slug is `nltis`. That word is not in the source. Configured SQL catalog names are `EPWP` and, in the web Release transform, `VectorWorkflowsLive`.

There is no README.

## Solution map

| Solution | Visual Studio | Projects |
|---|---|---|
| `Neo.Afx.WebServices.sln` | 15 (2017) | `Neo.Afx.Services.Web`, `Neo.Afx.Services.Data`, `Neo.Afx.Core`, `Neo.Afx.Services.Admin.Data` |
| `Neo.Afx.WindowsServices.sln` | 17 (2022) | Data, Core, `WinService.Common`, `WinService.Messages`, `WinService.Workflows`, `Neo.Afx.UnitTests` |
| `Neo.Afx.SqlServer.sln` | 16 (2019) | `Neo.Afx.SqlServer`, `Neo.Afx.SqlServer.Security`, `Neo.Afx.SqlServer.UnitTest` |
| `Neo.Afx.ActiveX.sln` | 15 (2017) | Document scanner, barcode printing. `Neo.ActiveX.FingerprintReader` is a project on disk and is not a member of any `.sln` |
| `Web/Afx.Consoles.sln` | 15 | `Afx.UserConsole`, Core, missing `Neo.Afx.Admin.Data` path, `Neo.Afx.Services.Data` |

Configurations on the solutions: Debug, QA, Release, Any CPU.

`Afx.Consoles.sln` project `Neo.Afx.Admin.Data` points at `..\Neo.Afx.Admin.Data\Neo.Afx.Admin.Data.csproj`. That file is not in the tree. The project GUID is the same as `Neo.Afx.Services.Admin.Data` (`{6D5A6449-FE9E-4395-8496-66B0A0A1B5B4}`), whose assembly name is `Neo.Afx.Services.Admin.Data`, root namespace `Neo.Afx.Admin`, assembly title `Neo.Afx.Admin.Data`.

## Frameworks and language

| Component | Target |
|---|---|
| `Afx.UserConsole` | .NET Framework 4.0, ASP.NET MVC 4.0.20505.0, Razor 2, WebPages 2, Web API client 4.0.20505.0, EF 6.1.3, Newtonsoft.Json 4.5.1. Project type is a web application (`ProjectTypeGuids` include the MVC and web GUIDs) with `OutputType` Library |
| `Neo.Afx.Services.Web` | .NET Framework 4.6.2 web project. WCF. EF 6.1.3. `OldToolsVersion` 4.0 |
| `Neo.Afx.Core`, Services.Data, Services.Admin.Data, SqlServer projects | .NET Framework 4.6.2 class libraries |
| WinService.* | .NET Framework 4.0 class libraries |
| Fingerprint reader, barcode printing | .NET Framework 2.0 |
| Document scanner | .NET Framework 4.6.2 |
| `Neo.Afx.UnitTests` | .NET Framework 4.8, MSTest |
| `Neo.Afx.SqlServer.UnitTest` | .NET Framework 4.6.2, MSTest |

Language is C#. Entity Framework models use EDMX and T4 (`.edmx`, `.tt`). Strong-name keys `Neo.snk` are tracked beside several projects.

## Application structure

```text
nltis/
  Neo.Afx.Core/                 shared security, MVC helpers, utilities
  Neo.Afx.Services.Data/        EF domain model and stores
  Neo.Afx.Services.Admin.Data/  admin EF model (namespace Neo.Afx.Admin.*)
  Neo.Afx.Services.Web/         IIS host for *.svc and *.ashx
  Web/Afx.UserConsole/          MVC user admin console
  Neo.Afx.WinService.Common/    scheduler
  Neo.Afx.WinService.Messages/  SMTP, Clickatell, Swift, POP3
  Neo.Afx.WinService.Workflows/ task processor
  Neo.Afx.SqlServer/            SQL CLR
  Neo.Afx.SqlServer.Security/   SQL CLR password functions
  Neo.ActiveX.FingerprintReader/
  Neo.Afx.ActiveX.DocumentScanner/
  Neo.Afx.ActiveX.Printing/
  Assemblies/                   vendored DLLs
  Deploy/                       service markup and SQL scripts copied for deploy
  Neo.Afx.DbScripts/            empty sample text file
```

`Neo.Afx.Services.Data` areas: Audits, Comments, Correspondence, Documents, Forms, Integration, Notifications, Performance, Queries, Reports, Security, Workflows, plus `Service References` and `Web References`.

`Neo.Afx.Services.Admin.Data` areas: Audit, Crm, Delegation, Doc, Form, Integration, Report, Security, Svc, Sys, Wf.

## Web services

Host markup uses `System.ServiceModel.Activation.WebServiceHostFactory`. Example from `WorkflowService.svc`:

```text
Service="Neo.Afx.Services.WorkflowService"
```

`Web.config` sets `aspNetCompatibilityEnabled` and `multipleSiteBindingsEnabled`. `webHttpBinding` uses streamed transfer and max buffer / message size 2147483647.

`IHttpModuleHelper` is registered as module `IHttpModuleHelper` and touches `Request.InputStream` on `BeginRequest`.

Services under `Neo.Afx.Services.Web/Services`:

| File | Contract namespace | Role |
|---|---|---|
| `WorkflowService.svc` | `neo:services:data` | Workflow instances and tasks |
| `DocumentService.svc` | `neo:services:data` | Documents and scan sessions |
| `CorrespondenceService.svc` | `neo:services:data` | Email and SMS records |
| `CommentService.svc` | `neo:services:data` | Comments |
| `AuditService.svc` | `neo:services:data` | Read audits |
| `QueryService.svc` | `neo:services:data` | Queries |
| `NotificationsService.svc` | `neo:services:data` | Notifications |
| `IntegrationService.svc` | `neo:afx:services` | Named data sources |
| `DocumentViewer.ashx` | n/a | Document HTTP handler |
| `EmailViewer.ashx` | n/a | Email HTTP handler |

A comment in `WorkflowService.svc.cs` shows a sample path `/Neo.Afx.Services/Workflows/WorkflowService.svc/...`. The file in source is `Services/WorkflowService.svc`.

Deploy folders also contain `FormService.svc` and `ValidationService.svc`. No `FormService` or `ValidationService` class is in the C# tree.

Service debug: `httpGetEnabled` true, `includeExceptionDetailInFaults` true. Message logging writes entire messages to `Traces.svclog` (max 3000).

Publish profile `afx V1`: filesystem, Release, `publishUrl` `C:\Deploys\Afx V1`, `DeleteExistingFiles` true, `ExcludeApp_Data` true.

## User console

Controller: `Afx.UserConsole.Controllers.UserConsoleController`, base `Neo.Afx.Mvc.ControllerBase`.

| Action | Verb | View or result |
|---|---|---|
| `Default` | GET | `Default.cshtml` |
| `Settings` | GET | `Settings.cshtml` |
| `Roles` | GET | `Roles.cshtml` |
| `Security` | GET | `Security.cshtml` |
| `Buddies` | GET | `Buddies.cshtml` |
| `Save`, `ActivateUser`, `DeActivateUser`, `SaveSettings`, `SaveUserRoles`, `SaveFingerprint`, `SaveBuddy`, `DeleteBuddy` | POST | JSON `{ ErrorMessage }` |

Each page has `Scripts/*-Init.cshtml` and `Scripts/*-Events.cshtml`.

`Web.config` sets MVC pages, client validation, and unobtrusive JavaScript. It has no connection strings and no authentication mode. `compilation debug` is true. Target framework on the compilation element is 4.0.

`Save` calls `SaveUser` with 7 arguments. `SecurityDatabase.SaveUser` in this tree takes 10 and forwards to `Pr_SaveUser`. Those two do not compile together as written.

NuGet HintPaths point at `Web\packages\...`. That folder is not tracked. `packages.config` lists only EntityFramework 6.1.3.

## Database

Provider: `System.Data.SqlClient` and Entity Framework 6 (`EntityFramework` 6.1.3). LocalDB factory `v11.0` is in the console `Web.config` `entityFramework` section. Service connection strings do not use LocalDB. They use a SQL catalog.

| Config | Server | Catalog | Login names (passwords omitted) |
|---|---|---|---|
| Service `Web.config`, data `App.config`, workflow `App.config`, admin `App.config` | `(local)` | `EPWP` | `EPWP` on most contexts. `Integration` uses `Legitimate` |
| `Neo.Afx.Services.Web/Web.Release.config` | `GROUPER\DEV09` | `VectorWorkflowsLive` | `EPWP` |

Contexts named in the service `Web.config`: `CorrespondenceContext`, `DocumentContext`, `FormContext`, `Integration`, `IntegrationContext`, `QueryEntities`, `WorkflowContext`, `ReportContext`.

Additional context names in `Neo.Afx.Services.Data/App.config`: `ConfigContext`, `CommentContext`, `AuditContext`, `SecurityContext`, `NotificationContext`, `NotificationsContext`, `PerformanceContext`, `QueriesContext`. Some of those use `integrated security` instead of the SQL login.

Workflow worker `App.config` names `WorkflowServiceContext` against catalog `EPWP`.

EDMX files (26) are the schema source available in git. Table names are visible on the EDMX entities. A full table dictionary was not extracted. Domain prefixes used by code comments include `[Doc].[DocumentStoreTypes]`.

`Neo.Afx.DbScripts` contains only `sample20190801.axiom.epwp.txt`, which is empty. It is not a migration set.

## SQL CLR

`Neo.Afx.SqlServer/RegisterNeoAfxSqlServer.sql`:

- Commented block shows `clr enabled`.
- `USE` a SQLCMD database variable.
- Drops previous functions and assemblies, including `System.Core` and `System.Xml.Linq`.
- Sets the database `TRUSTWORTHY` and owner `sa`.
- On SQL Server 2005 (`productversion` major 9), loads framework 3.5 `System.Core` and `System.Xml.Linq` as `UNSAFE` from `C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\`.
- Creates `Neo.Afx.SqlServer` from `E:\MSSQL\CLR\Neo.Afx.SqlServer.dll` as `EXTERNAL_ACCESS`.
- Creates the functions listed in the PRD. Grants execute to a SQLCMD login variable.

`RegisterNeoAfxSqlServerSecurity.sql` creates `Neo.SqlServer.Security` as `SAFE` from `C:\Development\Orca\Neo\SqlServer\V1\Deploy\Neo.SqlServer.Security.dll` in database `[DB_NAME]`. Functions: `HashPassword`, `CreatePasswordSalt`, `CreatePassword`.

Copies of both scripts are under `Deploy/NeoAfxSQLAssemblies/`.

## Background workers

No project subclasses `ServiceBase`. Hosting is outside this repository.

`Neo.Afx.WinService.Common` schedules work from database or file settings. Frequencies: minutes, hourly, daily, weekly, monthly, seconds (`PollFrequencyEnum`).

`WorkflowTaskProcessor` is an `IExecutable` `Worker`. It reads handlers and tasks through `WorkflowServiceDatabase` and invokes them by reflection (`HandlerTypeName`, `MethodName`).

`EmailSender` uses `System.Net.Mail.SmtpClient`. `SmsVodazone` uses `Interop.Clickatell`. `SmsSwift` uses `Interop.SwiftUniversal`. `Assemblies/Clickatell.bat` and `Swift.bat` run `tlbimp` against `SMS_COMAPI.dll` and `SwiftUniversal.dll`.

POP3 types exist (`Pop3Message`, `Pop3Extensions`) for inbound mail. A host that calls them was not identified.

## Reporting and external clients

`ReportGenerator` (`DevExpress.XtraReports.UI`) defines formats CSV, Excel, and PDF.

Two generated clients talk to SQL Server Reporting Services 2010:

- ASMX: `Neo.Afx.Services.Data/Web References/ReportingServices2010`. URL property `Neo_Afx_Services_Data_ReportingServices2010_ReportingService2010`.
- WCF: folder `Service References/Pilotfish.Afx.Services`. Metadata address stored in `Reference.svcmap`: `http://hannes-pc/Reportserver_HANNESDESKTOP/ReportService2010.asmx`.

The folder is named Pilotfish. The WSDL target namespace is `http://schemas.microsoft.com/sqlserver/reporting/2010/03/01/ReportServer`. This is a report-server client generated on a developer machine, not a separate Pilotfish integration in this tree.

## Device controls

| Control | Stack | Entry |
|---|---|---|
| `FingerprintReaderControl` | .NET 2.0, DigitalPersona assemblies under `Assemblies/DigitalPersona` (`DPUruNet`, `DPCtlUruNet`, and XUru variants) | `OpenReader`, `CaptureFingerAsync`. `DPFP.Capture.EventHandler` is commented off the class declaration |
| `DocumentScanner` | .NET 4.6.2, WIA (`Assemblies/Scanning/wiaaut.dll`, `Interop.Wiaaut.dll`) | `ScanDocument`. UI includes colour, duplex, ADF, resolution, source |
| `BarcodeLabelPrinterControl` | .NET 2.0 | `PrintLabels(BarcodeData, PrintedBy, Copies, PrinterPath, LabelHeight, LabelWidth, LeftMargin, Preview)` |

## Vendored binaries

`Assemblies/` is tracked (about 304 DLLs in the whole tree, including interop and reference copies):

| Folder or file | Contents |
|---|---|
| `AbcPdf` | ABCpdf |
| `DevExpress` | DevExpress (reports) |
| `DigitalPersona` | U.are.U fingerprint |
| `DocumentFormat.OpenXml.dll` | Open XML |
| `DynamicSoft` | DynamicSoft (name only; not traced to a call site in this pass) |
| `EntityFramework.dll`, `EntityFramework.SqlServer.dll` | EF 6 |
| `Messaging` | `Interop.Clickatell.dll`, `SMS_COMAPI.dll`, `Interop.SwiftUniversal.dll`, `SwiftUniversal.dll`, `Mail.dll` |
| `Newtonsoft.Json.dll` | JSON |
| `Scanning` | WIA |

## Authentication

Two mechanisms exist in code:

1. ASP.NET `[Authorize]` on the console, with no authentication mode in that project's `Web.config`. Workflow services read `HttpContext.Current.User`.
2. `DomainMembershipProvider` in `Neo.Afx.Core`, a custom `MembershipProvider` that reads a connection string by name and optional RSA settings (`RsaSettings.GetSection()`). Nothing in the tracked configs adds this provider to `<membership>`.

`SecurePassword` uses `SHA1Managed`. `CreateSalt` uses `RNGCryptoServiceProvider`. Default salt size is 7 bytes, returned as Base64. `GeneratePassword` in the SQL assembly calls `CreateSalt(length)`, so the SQL function named generate-password returns a salt-sized random Base64 string, not a password policy.

## Security notes visible in the tree

These are observations, not a remediation plan.

- SQL passwords are stored in plaintext in several `Web.config` and `App.config` files that are tracked. Values are omitted here. Logins include `EPWP` and `Legitimate`.
- WCF fault details and full message traces are enabled in the service `Web.config`. `compilation debug` is true on the console and the service site.
- The CLR install script enables `TRUSTWORTHY` and assigns ownership to `sa`.
- `.snk` strong-name files are tracked.
- `webHttpBinding` accepts very large streamed bodies (int max).

**Unknown:** whether these configs match any deployed environment, and whether the committed passwords are still valid. Confirmation should include rotation if they were ever used outside a local database.

## Build and test

No solution builds all projects. Build the solution that matches the area.

Expected obstacles from static review:

- Missing `Neo.Afx.Admin.Data` project path from `Afx.Consoles.sln`.
- `UserConsoleController.Save` argument count does not match `SecurityDatabase.SaveUser`.
- NuGet packages for MVC are referenced and not present under `Web\packages`.
- ActiveX projects target .NET 2.0 and need a machine that can still build that target.
- SQL projects need the SQL Server SDK (`Microsoft.SqlServer.Server`).
- Tests call a database. `DataSourceTest.GetDataTest` requests `GetVerifiedLicenceToUseXml` with query `olnumber=TODO3202000001/1` and does not assert. `TestGetLookups` requests data source `OfficeLocations` and does not assert.

No CI definition, Dockerfile, or `sonar-project.properties` is in git. The onboarding issue listed Sonar files at the scan-host root. They were not in the clone.

## Environments

| Name | Evidence | What it points at |
|---|---|---|
| Debug | Solution configuration and default configs | `(local)` / `EPWP` |
| QA | Solution configuration | For Admin.Data and WinService.Workflows, the QA configuration builds the Release output. Other projects have a QA configuration |
| Release | `Web.Release.config`, publish profile | `GROUPER\DEV09` / `VectorWorkflowsLive`, publish folder `C:\Deploys\Afx V1` |
| Developer SSRS | Service reference metadata | `http://hannes-pc/Reportserver_HANNESDESKTOP/ReportService2010.asmx` |

No production URL, IIS binding, or server inventory is in the repository.

## Monitoring

WCF system.diagnostics XML trace to `Traces.svclog`. Membership provider can write exceptions to the Windows event log when `writeExceptionsToEventLog` is true (the code default). No application metrics pipeline is in the tree.

## File that is not documentation

`Neo.Afx.DbScripts/sample20190801.axiom.epwp.txt` is zero bytes. The name is the only hint of an Axiom/EPWP sample dated 2019-08-01.
