# Technical documentation — magusEventsXamarin

Evidence date: 2026-10-09. Inspected revision: `master` at `607005b` (2020-08-17).

Source: `git@bitbucket.org:overdrive/maguseventsxamarin.git`. 261 tracked files. One branch, `master`.

## Solution layout

```text
maguseventsxamarin/
├── .gitignore
├── Screenshots/                          eight PNGs
└── MagusEvents/
    ├── MagusEvents.sln                   Visual Studio 2019 (16.0)
    ├── hideAndShowKeyboard.cs            unused Android helper, namespace APP.Resources.Utils; not referenced by a csproj
    └── MagusEvents/
        ├── MagusEvents/                  shared library, netstandard2.0
        │   ├── App.xaml / AppState.cs
        │   ├── EventScan, EventSettings, SelectMode
        │   ├── ApplicationScan, ApplicationSettings
        │   ├── VAPScan, VAPSettings
        │   ├── HeaderBar, OTPDialog
        │   ├── classes/                  SQLite and HTTP
        │   ├── Services/IAudio.cs
        │   ├── customcontrols/CheckBox_Custom.cs
        │   ├── packages/                 vendored NuGet trees
        │   └── Properties/PublishProfiles/FolderProfile.pubxml
        ├── MagusEvents.Android/          Xamarin.Android, target v9.0
        │   ├── MainActivity.cs
        │   ├── FileAccessHelper.cs
        │   ├── DroidKeyboardHelper.cs
        │   ├── Services/Audio.cs
        │   └── Assets/database.sqlite3
        └── MagusEvents.iOS/              Xamarin.iOS shell
            ├── AppDelegate.cs
            └── Info.plist
```

`MagusEvents/.vs/MagusEvents/v16/Server/sqlite3/db.lock` is tracked. Other `.vs` noise is listed in `.gitignore` and is not part of the product.

## Frameworks and language

| Piece | Version or setting | File |
|---|---|---|
| Language | C# | project files |
| UI | Xamarin.Forms 4.2.0.848062 | shared, Android, and iOS csproj |
| Shared TFM | `netstandard2.0` | `MagusEvents.csproj` |
| Android | `TargetFrameworkVersion` v9.0, `minSdkVersion` 21, `targetSdkVersion` 28, ABIs `armeabi-v7a;x86` in Debug | Android csproj, `AndroidManifest.xml` |
| Android package | `com.companyname.magusevents`, `versionCode` 1, `versionName` 1.0, `installLocation` preferExternal | `AndroidManifest.xml` |
| iOS | minimum 8.0, display name MagusEvents, bundle `com.companyname.MagusEvents`, bundle version 1.0, iPhone and iPad | `Info.plist` |
| IDE | Visual Studio Version 16 | `MagusEvents.sln` |
| JSON | Newtonsoft.Json 12.0.1 vendored; shared csproj hints that DLL | `MagusEvents.csproj` |
| SQLite | sqlite-net-pcl 1.6.292 (`using SQLite`) | `Database.cs` |

`System.Drawing.Common` hints a path under Visual Studio 2019 Professional (`Xamarin.iOS` facades). A machine without that path will not resolve the reference the way the csproj is written.

`FolderProfile.pubxml` publishes the shared library to `bin\Debug\netstandard2.0\publish\` with protocol FileSystem, configuration Release. It is not an Android package step.

## How a screen is shown

There is no navigation stack. `App.NavigateToDetail` assigns a new page to `MainPage`.

`DetailPages`: `EventScan`, `EventSettings`, `ApplicationScan`, `SelectMode`, `VAPScan`, `ApplicationSettings`, `VAPSettings`.

`AppState` holds the accreditation id, one `Database`, and the server string. The server is the literal `https://footprintapp.net/`. `https://qa.footprintapp.net/` is commented above it.

## Android startup

`MainActivity.OnCreate`:

1. Requests `WriteExternalStorage` and `ReadExternalStorage` if not granted. Those permissions are not listed in the checked-in manifest.
2. Inits `Xamarin.KeyboardHelper`, Forms, ZXing.Net.Mobile.Forms, Xamarin.Essentials.
3. Calls `FileAccessHelper.GetLocalFilePath("database.sqlite3")`, which copies the asset if the personal-folder file is missing.
4. Inits `DroidKeyboardHelper` and `LoadApplication(new App())`.

The returned path is not passed into `Database`. `Database` opens `Path.Combine(Personal, "database.sqlite3")` itself. On Android those are the same folder, so the copy is the file the shared code opens. That coupling is **Inferred** from the two paths, not from a shared variable.

Checked-in manifest permissions: `ACCESS_NETWORK_STATE`, `CAMERA`, `FLASHLIGHT`. `INTERNET` is not in that file. Whether the Xamarin build merges it is **Unknown / Requires Confirmation**. Camera and flashlight match a ZXing setup. No XAML hosts a scanner view.

`Audio` is registered with `[assembly: Dependency(typeof(Audio))]` and plays `Resource.Drawable.ok` and `Resource.Drawable.Bazz`.

## iOS startup

`AppDelegate.FinishedLaunching` calls `Forms.Init` and `LoadApplication(new App())`. It does not copy a database, init ZXing, or register keyboard or audio services. `DependencyService.Get<IAudio>()` and `Get<IKeyboardHelper>()` have no iOS class. Call sites catch the failure. The personal-folder database is created empty by sqlite-net when the asset copy never runs, so the `Events` and `ScanLog` tables from the asset are absent unless something else creates them. `Database` does not call `CREATE TABLE`. The create methods are commented out.

## Local database

Path: `{SpecialFolder.Personal}/database.sqlite3`.

Engine: `SQLiteConnection` from sqlite-net-pcl. `ExecuteData` returns true when `Execute` reports a row count greater than 0.

Bundled schema in `Assets/database.sqlite3` (empty business tables, two `ScanLog` rows):

| Table | Role in the client |
|---|---|
| `Events` | One active accreditation. Columns include dates, location, logo, barcode length, meal fields, `Active`. |
| `Persons` | Applicants. Unique `AASID`. Lookup by `Barcode` or `SCANID` plus `AC`. |
| `Permits` | Vehicle permits. Unique `PID`. Lookup by `Barcode` or `SCANID` plus `AC`. |
| `Zones` | Application zones. `Lock`, `Active`, `Hidden`, `ZTID`, `Icon`, times. |
| `Loading_Zones` | Same shape as `Zones`, used by VAP. |
| `Gates` | One row after VAP submit. `GID`, `AC`, `Number`, `Description`, `Color`. |
| `ScanLog` | Application decisions. `LogID` integer primary key autoincrement. |
| `Food` | Created in the asset. No live writer. |

`GetPersonProfile` and `GetVapProfile` map query rows in a loop and keep the last row. They are also used to run `DELETE` statements (`DownloadFootprintApplications` passes a delete string into `GetPersonProfile`). The delete may run, and the method then tries to map a result. Failures are caught.

Queries concatenate values into SQL text.

## HTTP

`WebClient` (`System.Net`). No `HttpClient` timeout is set. No certificate pinning. Download callbacks are async. UI updates from those callbacks are not marshalled in the code that was read.

| Method | Path |
|---|---|
| GET | `{Server}api/Accreditation/getevents` |
| GET | `{Server}api/accreditation/getapplicantsandroid/ac/{AC}/id/{AASID}` |
| GET | `{Server}api/accreditation/getaccreditationupdated/ac/{AC}` |
| GET | `https://footprintapp.net/local_data/accreditations/{AC}.json` |
| GET | `{Server}api/accreditation/getvapandroid/ac/{AC}/id/{PID}` |
| GET | `{Server}api/accreditation/getapplicantsupdatesandroid/ac/{AC}/date/{stamp}` |
| GET | `{Server}api/accreditation/getvapupdatesandroid/ac/{AC}/date/{stamp}` |
| GET | `{Server}api/accreditation/scanlog/scanlog/{urlEncodedJson}` |
| GET | `https://www.footprintapp.net/api/tourn/` (probe only) |
| FTP STOR | `ftp://footprintapp.net/public_html/public/local_data/logs/scan_{AC}.txt` |

The scan-log payload is a JSON array on the URL, not a POST body. Batch size is 3.

FTP credentials are string literals in `UploadScanLog`. They are not copied here. Treat the source file and git history as exposed.

The four-digit settings code is four character literals in `OTPDialog.xaml.cs`. It is not copied here.

## Background work

| Timer | Page | Interval | Action |
|---|---|---|---|
| Running | `ApplicationScan` | 30 minutes | `UploadScanLog` on a `Thread` if the probe succeeds |
| Running | `ApplicationScan` | 2 seconds | decrement `BUSY`, reload the page at 0 |
| Commented | `ApplicationScan` | 300 seconds | accreditation file check |
| Commented | `ApplicationScan` | 240 seconds | applicant delta |
| Commented | `VAPScan` | 240 seconds | VAP delta and applicant delta |
| One-shot | `EventSettings` | 1 second | load events, then the flag stops it |
| One-shot | zone settings | 100 milliseconds | load events, then the flag stops it |
| One-shot | VAP scan | 5 or 7 seconds | reset after a vehicle or driver result |

Threads are aborted in `KillRunningProcesses` (`Thread.Abort`).

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

- Settings code and FTP password are in source.
- Accreditation API calls carry no token.
- Scan JSON is placed on a query string.
- SQL is concatenated.
- The Android asset `ScanLog` contains a person's name in `ProfileFullName`.
- Storage permission is requested in code and not declared in the checked-in manifest. `INTERNET` is absent from that manifest.
- `Button_exit` kills the process.

## Configuration and environments

There is no `.env`, no build flavour for QA versus live, and no CI file. Switching host means editing `AppState` (and the hardcoded accreditation file URL, which does not read `AppState.Server`).

`.gitignore` ignores `bin/`, `obj/`, most of `.vs`, and `Database/database.sqlite3`. The Android assets are not ignored. `Database/database.sqlite3` is not a tracked path.

## Testing and development

No test project, no `*Test*.cs` under the app trees, no pipeline YAML. The only manual evidence checked in is `Screenshots/`.

Building expects a Xamarin workload that can target Android 9 and the hint paths in the shared csproj. That was not executed for this document.

## Monitoring

None in the client. `Console.WriteLine` is used around SQL and download URLs. Empty `catch` blocks drop errors. The header version string is not read from the manifest.

## Related products

This repository only calls Footprint hosts. Other Silicon Ark directories document other Footprint and magus.events sites (`permits.magus.events` is a vehicle-permit desk, for example). No project reference or URL in this repo points at those directories. A shared accreditation database is **Inferred** from the API names and is **Requires Confirmation** before anyone treats those sites as the backend for this scanner.
