# Technical documentation — Paymyfines-CronJob

Evidence date: 2026-10-07.

Source: `git@bitbucket.org:overdrive/paymyfines-cronjob.git`, `master` at `cbc8461` (2021-10-18, Lloyd `sherewalloyd@gmail.com`). Only branch: `master`. Previous commit on the same minute: `14106e7` (`.gitignore`, `.gitattributes` only).

Secret literals are omitted. A database password is present in `TMTCronJob/appsettings.json`. An SMTP password in `MailService.cs` is the placeholder `xxxxxx`.

## Stack

| Item | Value | Evidence |
|---|---|---|
| Language | C# | `TMTCronJob/*.cs` |
| Framework | ASP.NET Core web, `netcoreapp3.1` | `TMTCronJob.csproj` |
| SDK style | `Microsoft.NET.Sdk.Web` | `TMTCronJob.csproj` |
| Host | `Host.CreateDefaultBuilder` and `Startup` | `Program.cs` |
| IDE | Visual Studio 16 (2019), solution format 12.00 | `TMTCronJob.sln` |
| JSON | Newtonsoft.Json 13.0.1 | `TMTCronJob.csproj` |
| MySQL client | MySql.Data 8.0.26 | `TMTCronJob.csproj` |
| Tests | None | Solution contains only `TMTCronJob` |
| Container / pipeline / IaC | None | Not in the tree |

`Program.CreateHostBuilder` does not set URLs. Ports come from the launch profile or the hosting environment.

## Layout

```text
TMTCronJob.sln
TMTCronJob/
  Program.cs
  Startup.cs
  appsettings.json
  appsettings.Development.json
  Controllers/CronJobController.cs
  Services/PaymentService.cs
  Services/MailService.cs
  Helper/Helper.cs
  Model/InfringementPayment.cs
  Model/PayEnatisInfringement.cs
  Model/PayIForceInfringement.cs
  Model/ENatisPaymentResponse.cs
  Model/IForcePaymentResponse.cs
  Model/ErrorResponse.cs
  Properties/launchSettings.json
```

Namespace root: `TMTCronJob`.

## Process model

One web process. Work runs inside the HTTP request `GET /CronJob`. There is no `BackgroundService`, no `Timer`, no queue client, and no cron file.

`Startup.Configure`:

1. Developer exception page when the environment is Development.
2. HTTPS redirection.
3. Routing.
4. Authorization (no authentication service is registered).
5. `MapControllers`.

`ConfigureServices` registers controllers and a transient `MySqlConnection` from `ConnectionStrings:DefaultConnection`. The controller does not take that connection. It builds a second `ConfigurationBuilder`, adds only `appsettings.json`, and opens `MySqlConnection` itself. Environment variables, command-line args, and `appsettings.Development.json` therefore do not affect the connection string the job uses.

The controller field `_reader` starts null. `PaymentService` uses its own commands and readers. The controller reader is used only in the admin-mail block.

## HTTP surface

| Method | Path | Action | Response |
|---|---|---|---|
| GET | `/CronJob` | `CronJobController.Get` | 200, body `Cronjob completed` |

No other controller exists. The action takes no parameters. `[HttpGet(Name = "RunCronJob")]` sets the endpoint name. It does not change the path.

`Properties/launchSettings.json`:

| Profile | URLs | Launch path | Environment |
|---|---|---|---|
| IIS Express | `http://localhost:51558`, SSL port `44377` | `CronJob` | `Development` |
| TMTCronJob | `https://localhost:5001` and `http://localhost:5000` | `CronJob` | `Development` |

Anonymous authentication is true. Windows authentication is false. `launchBrowser` is true, so a Visual Studio start issues `GET /CronJob` and runs settlement against whatever database is in `appsettings.json`.

`AllowedHosts` is `*`.

## Configuration

`appsettings.json` holds logging levels, `AllowedHosts`, and `ConnectionStrings:DefaultConnection`.

The connection string names:

| Key | Value recorded here |
|---|---|
| server | `paymyfines-instance-1.cehgxa1eerul.eu-west-1.rds.amazonaws.com` |
| database | `paymyfines_qa` |
| `convert zero datetime` | `True` |
| userid, password | Present in the file. Omitted from this document |

`appsettings.Development.json` repeats logging levels and does not override the connection string.

No user secrets file, no environment-sample file, and no AWS Secrets Manager reference.

## Data access

Driver: `MySql.Data.MySqlClient`. Statements are concatenated. No `MySqlParameter` is used.

`LoadInfringements` assigns `CommandText`, calls `ExecuteNonQuery`, then `ExecuteReader`, and maps columns by name. This investigation did not execute that sequence.

Tables and the column typos the SQL depends on are listed in `prd.md` (Data touched). There is no schema script in this repository. Whether `refTrasactionID` and `strRecieptNumber` match the live database is **Unknown / Requires Confirmation**.

`PaymentService` keeps the connection it was given. It does not open or close it. The controller opens it and disposes it with `using`.

## Outbound HTTP

`PaymentService` constant `base_url`: `http://192.168.0.41:8080/`.

| Method | Relative URL | Request type | Success type | Error type |
|---|---|---|---|---|
| POST | `infringement/payinfringement` | `PayEnatisInfringement` | `ENatisPaymentResponse` | `ErrorResponse` |
| POST | `IForce/registerpayment` | `PayIForceInfringement` | `IForcePaymentResponse` | `ErrorResponse` |

Content type `application/json`, UTF-8. One `HttpClient` per `Process*` call, not disposed, no `Timeout` set. `HttpClientHandler.ServerCertificateCustomValidationCallback` is `Helper.ServerCertificateCustomValidation`, which returns `true`.

JSON names are the C# property names as declared (camel case on the DTO, PascalCase is not applied). Newtonsoft default contract resolver is used. No `JsonProperty` attributes.

## Mail

`System.Net.Mail.SmtpClient` (the .NET Framework-style client available to this target).

| Setting | Value |
|---|---|
| Host | `smtp.gmail.com` |
| Port | `587` |
| SSL | enabled |
| Delivery | network |
| From / To | the commit author's Gmail address, display name `Lloyd` |
| Password | placeholder `xxxxxx` in source |
| Subject | `PMF Error Payments` |
| Body | ASCII lines of infringement id and notice number |

CC comes from the caller. The caller intends rows of `user` with `strRole = '["ADMIN"]'`. The reader is opened on a `MySqlCommand` that has no `CommandText` yet. **Inferred** exception before send.

## Security

Implemented characteristics, not a recommendation list:

- `GET /CronJob` has no authentication.
- The RDS user id and password are in `appsettings.json` in git. Rotate them. They are not repeated in Silicon Ark.
- SMTP uses a personal mailbox. The password in git is not a usable secret (`xxxxxx`).
- SQL is interpolated, including ids and error text returned by the upstream API.
- TLS certificate checks on the outbound handler accept every certificate.
- `AllowedHosts` is `*`.
- HTTPS redirection is on, and the upstream fine API URL is plain HTTP.
- The job return value does not change when settlement fails, so a caller cannot use the status code as a success signal.

## Logging and monitoring

`appsettings.json` sets default log level Information, Microsoft Warning, hosting lifetime Information.

No application code writes a log. Commented calls use `WriteLog` with categories `CRONJOB` and a source label `TMT`. Those calls would not compile against `ILogger` if uncommented without a different logger type. No metrics, health endpoint, or APM package is referenced.

## Build and local run

Evidence from the project file and launch settings only. This investigation did not build or run the application.

```text
dotnet build TMTCronJob.sln
dotnet run --project TMTCronJob
```

`dotnet run` uses the `TMTCronJob` launch profile when launched from the project directory with the SDK defaults, and the profile's `launchUrl` is `CronJob`. A machine that can reach the RDS instance and `192.168.0.41` will attempt live settlement on startup. **Inferred** from `launchSettings.json`. Not observed.

The csproj has no `RuntimeIdentifier` and no publish profile.

## Deployment

No Dockerfile, no `serverless.yml`, no pipeline YAML, no IIS `web.config`, and no deploy script are in git.

Where this binary was hosted, and whether it still is, is **Unknown / Requires Confirmation**.

## Scan-host files absent from git

The onboarding issue listed `sonar-project.properties` and `sonarqube_scan.bat` beside the solution. They are not in `cbc8461` and they were not in the clone. Contents: **Unknown / Requires Confirmation**.

## Related Silicon Ark records

`pmf-backend-ah` documents a 2022 Lambda that settles the same status values through the same two relative paths, against a different base URL, with different filters and with `SETTLED` commented out. `paymyfines-worker` has no source and is not this service. See `project-plan.md` and the conflict table in `prd.md`.
