# Technical documentation — buddyfinance (Buddy Finance)

Evidence date: 2026-10-19. Revision: `master` `8d0ae20` (2022-10-05).

Secrets that are committed in the source tree are not copied here. That includes SQL passwords in `App.config` files and `BuddyFinance.Admin/appsettings.json`, TransUnion codes in the database seed, the platform profile identification number, and the bank account number hardcoded in `ProfilesIntegrator.ApproveProfile`.

## Architecture

Buddy Finance is a .NET solution. The website is ASP.NET Core 3.1 and calls an ASP.NET Web API 2 application on .NET Framework 4.8. Business rules live in integrator classes, not in the controllers. Persistence is Entity Framework 6 against SQL Server, with a SQL Server Data Tools project for schema and seed. Credit bureau access is a MEF plugin. Three console programs share the same model. An Android app is a WebView.

```text
BuddyFinace.sln
  BuddyFinance.Admin                         ASP.NET Core 3.1 website and staff UI
  BuddyFinance.WebApi                        ASP.NET Web API 2, .NET Framework 4.8
  BuddyFinance.Integration                   Integrators (business operations)
  BuddyFinance.Integration.Models            Request and response models, enums
  BuddyFinance.Integration.Transunion        MEF TransUnion plugin
  BuddyFinance.MEF                           Credit-bureau contracts
  BuddyFinance.Model                         EF6 EDMX
  BuddyFinance.Common                        Helpers, encryption, API response types
  BuddyFinance.Database                      SQL project
  BuddyFinance.Reports                       SSRS
  BuddyFinance.Billing                       Console, not in the solution
  BuddyFianance.BillingArrears               Console (folder name is misspelled)
  BuddyFinanceExpireLoanRequests             Console
  BuddyFinance.Mobile                        Android, not in the solution
  BuddyFinance.UnitTests
  BuddyFinance.Integration.UnitTests
```

The website also opens SQL directly through EF Core `BuddyFinanceDbContext` (`Startup.ConfigureServices`). Most product writes go through the Web API into EF6.

## Languages and frameworks

| Layer | Version or library | Evidence |
|---|---|---|
| Website | ASP.NET Core, `netcoreapp3.1` | `BuddyFinance.Admin.csproj` |
| Website data | EF Core 3.1.17 SQL Server; FluentValidation 7 | Same csproj |
| API | .NET Framework 4.8, Web API 2, OWIN, ASP.NET Identity | `BuddyFinance.WebApi.csproj`, `Startup.Auth.cs` |
| Domain and model | .NET Framework 4.8, Entity Framework 6.1.3 | `packages.config` in `BuddyFinance.Model` |
| Billing console | .NET Framework 4.6.2 | `BuddyFinance.Billing.csproj` |
| Other class libraries and consoles | .NET Framework 4.8 | Their csproj files |
| Database project | SQL Server 2012 schema provider `Sql110`; project target `v4.5.2` | `BuddyFinance.Database.sqlproj` |
| Reports | SSRS 2008 R2 (Debug) and SSRS 2016 (DebugLocal, Release) | `BuddyFinance.Reports.rptproj` |
| Mobile | Android compile SDK 27, min SDK 16, application id `buddyfinance.za.co.buddy3` | `BuddyFinance.Mobile/app/build.gradle` |
| Mobile libraries | Support library 27.1.0, Firebase 11.8.0 / perf 16.0.0 | Same file |
| API telemetry | Application Insights 2.18.0 | `BuddyFinance.WebApi/packages.config` |

## Application structure

### Website (`BuddyFinance.Admin`)

Controllers at the root serve the public and customer site: `AccountController`, `HomeController`, `LenderController`, `BorrowerController`, `ProfileController`, `StatementController`.

The `Admin` area serves staff: accounts, activity log, cash withdrawals, find, home, loan offers, loans, manage cash, profiles, static data (terms).

`BaseController` is `[Authorize(Policy = "LoggedIn")]`. `AccountController` and `HomeController` are `[AllowAnonymous]`. The policy handler succeeds when the session user id is not 0.

`apiRootUrl` in `appsettings.json` is `https://www.buddyfinance.co.za/service/api/`. `env` is `qa`. The connection string name is `buddyfinance`. Its catalog in the committed file is `BuddyFinanceDb_Prod`. The integration `App.config` catalog is `BuddyFinanceDB_QA`. Both name the same host. A commented connection string in `App.config` names a different host and catalog `BuddyFinanceDB`. Which one runtime uses is **Unknown / Requires Confirmation**.

Session idle timeout is 120 minutes. Razor runtime compilation is enabled. URLs are lowercased.

Customer HTML fragments live under `wwwroot/templates/` (lender, borrower, register, profiles). `wwwroot/lib` contains vendored jQuery, DataTables, Chart.js, Moment, Morris, Font Awesome, and related packages.

### Web API

Route prefixes:

| Prefix | Controller |
|---|---|
| `api/account` | Login, password, activate, deactivate, user save |
| `api/registration` | Register, OTP, verify, re-apply |
| `api/profiles` | Profile CRUD, documents, FICA, earnings, calculator, contact |
| `api/loans` | Loans, requests, repayments, payout, schedule, statement |
| `api/loanoffers` | Offers |
| `api/managecash` | Deposits, withdrawals, manual deductions |
| `api/scoring` | Scoring |
| `api/transactions` | Transactions and statement by date |
| `api/reporting` | Statement |
| `api/files` | Files and terms |
| `api/master` | Lookups |
| `api/administration` | Activity log (`activitlog`) |

OAuth token endpoint is `/Token`. Provider is `ApplicationOAuthProvider`. Access tokens last 14 days. `AllowInsecureHttp` is true. External login providers are commented out.

Controllers inherit `BaseController`, which only adds `LogException`. No `[Authorize]` attribute was found on these controllers.

`Project_Readme.html` is the Web API project template readme, not a product document.

### Integration layer

Public operations are classes in `BuddyFinance.Integration/Integrators`. Controllers construct those classes directly. There is no dependency-injection registration of integrators on the API.

`BaseIntegrator` loads `GlobalSetup` and the fee dictionary, and owns `LoanCulculator`.

Email templates are text files in `BuddyFinance.Integration/Notifications`. A second folder, `Notifications - Back`, holds copies. Placeholders such as `[names]` and `[amount]` are replaced in code.

`NotificationsIntegrator.SendEmail` uses `SmtpClient` on port 587. `EnableSsl` is commented out. `SendSMS` posts `type=sendparam` to the URL in `SMSPortalPostURL`. `SendEmailSendGridAsync` is a second implementation. App setting keys referenced from code include `TemplatesPath`, `SmtpServer`, `SmtpUsername`, `SmtpPassword`, `NoReplyEmail`, `NoReplyName`, `SMSPortalUserID`, `SMSPortalPassword`, `SMSPortalPostURL`, `LoginUrl`, and `LoanOfferExpiryDate`. `LoanOfferExpiryDate` was not present in the committed `App.config` that was read.

### Credit bureau

`BuddyFinance.MEF` defines `ICreditBureauIntegrator` and the customer credit profile types. `CreditBureauEnum` identifies the bureau. `BuddyFinance.Integration.Transunion.Integrator` is exported with MEF and calls `TransUnionService.ConsumerSoapClient.ProcessRequestTrans01`. Each call writes `RequestLog` with request XML, then response XML or the exception.

The generated Connected Service client produces very long filenames under `Connected Services/TransUnionService`. A checkout on Windows without long-path support fails on those names.

### Data

EF6 model is `BuddyFinance.Model/Model.edmx`. Entity classes are generated beside it. The database project tables match those entities: profiles, users, lenders, borrowers, loans, offers, requests, schedules, repayments, payouts, transactions, cash deposits and withdrawals, FICA, documents, addresses, employment, notifications, activity, and `RequestLog`.

Stored procedure in source: `dbo/Stored Procedures/ProfileTransactions.sql`.

Post-deployment seed is `dbo/Scripts/Script.PostDeployment1.sql`. It merges lookup rows and inserts the platform profile and one `GlobalSetup` row.

`BuddyFinance.Database.sqlproj` sets `SqlServerVerification` to false.

### Processes

| Program | Target framework | In solution | Behaviour |
|---|---|---|---|
| `BuddyFinance.Billing` | 4.6.2 | No | Service fee on billing day |
| `BuddyFianance.BillingArrears` | 4.8 | Yes | Arrears email |
| `BuddyFinanceExpireLoanRequests` | 4.8 | Yes | Expire New requests at 30 days |

Each `Main` opens `BuddyFinanceDBEntities`, prints to the console, and exits. No Windows service, SQL Agent script, or cron file is in the repository. How they are scheduled is **Unknown / Requires Confirmation**.

### Reporting

`Statement.rdl` and `Transactions.rdl`. Shared data sources `BuddyFinanceDB_Dev.rds` and `BuddyFinanceDb.rds`. Debug deploys to `http://localhost/reportserver` folder `BuddyFinance/QA/`.

### Mobile

`Splash` is the launcher. `MainActivity` enables JavaScript in a WebView, loads `https://buddyfinance.co.za/qa` when online, and `file:///android_asset/error.html` when offline. It listens for downloads. Permissions: Internet, Wi-Fi state, read and write external storage. Firebase is applied. A `Buddy3.zip` sits in the project folder. Its contents were not unpacked.

## Authentication

Website: cookie authentication, login path `/account/login`. The API access token is kept on `SessionManager.Current.CurrentUser` and sent by `WebApiHelper` when the website calls the API.

API: OAuth bearer tokens from `/Token`, plus `POST api/account/login` on `AccountController`. Password reset and change are on `SecurityIntegrator` (`GenerateToken`, `ResetPassword`, `ChangePassword`).

Encryption helpers live in `BuddyFinance.Common/Encryption`. Several API models carry an encrypted `ProfileId_` that integrators decrypt with `ToDecryptedInt`.

## Background work

There is no in-process queue, Hangfire, or hosted service. Background work is the three console programs. `origin/RenierDEV` adds `CronJobController` and is not on `master`.

## Storage

Uploaded documents and the terms file are `byte[]` columns on `FileData` (`DocumentsIntegrator.Upload`). No blob storage client was found.

## Monitoring and logging

- Web API `LogException` filter and Application Insights packages.
- `Logger` used by the SMS and email sender, writing through the integration logging types.
- `ActivityLog` rows for logins and the administration activity API.
- `RequestLog` for TransUnion XML.
- Billing consoles write to stdout and, on billing exceptions, contain a comment `TODO: log to database`.

## Security notes (from the tree, not a penetration test)

- SQL authentication passwords are committed in website and integration config, including a commented older connection string.
- `AllowInsecureHttp` is true on the OAuth server.
- SMTP SSL is commented out.
- Web API controllers do not declare authorization attributes.
- The Android app sets `allowBackup` true and requests broad storage permissions.
- `google-services.json` is committed.
- Lender approval embeds a live-looking bank account in source.

These are observations. Whether production overrides the committed config is **Unknown / Requires Confirmation**.

## Development and testing

No README describes how to build or run the system. The solution file is `BuddyFinace.sln`.

`BuddyFinance.UnitTests` has one active test, `TransunionTests.TestHelloWorld`, which calls a SOAP `HelloWorld`. `EncryptionTestFixtures.cs` is also in that project.

`BuddyFinance.Integration.UnitTests.ScoringIntegratorUnitTests` does not call the scorer. The body is commented, with a note that the test fails because Microsoft.Owin assemblies are missing. A personal keyboard comment at the bottom of that file is not a test.

The Android project has the template `ExampleUnitTest` and `ExampleInstrumentedTest`.

No CI pipeline file (no `bitbucket-pipelines.yml`, no GitHub workflow) was found on `master`.

## Environment configuration

| Setting | Where it appears | Notes |
|---|---|---|
| `apiRootUrl` | `appsettings.json` | `https://www.buddyfinance.co.za/service/api/` |
| `env` | `appsettings.json` | `qa` |
| `ConnectionStrings:buddyfinance` | `appsettings.json` | Catalog name `BuddyFinanceDb_Prod` |
| `BuddyFinanceDBEntities` | `BuddyFinance.Integration/App.config` | Catalog name `BuddyFinanceDB_QA` |
| `transunionService:EndpointUrl` | `appsettings.json` | Placeholder `{your-environment-endpoint-URL}` |
| TransUnion client | Connected service in the TransUnion project | Endpoint is the generated WCF client, not the placeholder above |
| Mobile start URL | `MainActivity.java` | `https://buddyfinance.co.za/qa` |
| Report server | `BuddyFinance.Reports.rptproj` | `http://localhost/reportserver` |

`appsettings.Development.json` exists beside the main website settings. Its secrets are not copied here.

## Dependencies that failed or were left unfinished

- Sonar files named at task creation (`sonar-project.properties`, `sonarqube_scan.bat`) are not in `master`.
- `LoanOfferExpiryDate` is required by offer save and was not found in committed app settings.
- Scoring unit test is disabled.
- Monthly billing is a different framework version (4.6.2) from the rest of the consoles (4.8) and is outside the solution.

## Unmerged technical surface (`origin/RenierDEV`)

Not built from `master`. The diff adds `StitchIntegrator`, Stitch token models, `StitchController`, `CronJobIntegrator`, `CronJobController`, cron result types, and changes to `LoanRequestIntegrator`, `LoanOffersIntergrator`, `BaseIntegrator`, `NotificationsIntegrator`, and `LoanSchedule`. Treat that as a second code line until someone confirms it is deployed.
