# Technical documentation — UnityApi

Evidence date: 2026-09-30.

Source: `git@bitbucket.org:overdrive/unityapi.git`, `master` at `23894c830a0442cec91488fea08d640311c5be63`.

The application is the Laravel 5.8 skeleton. Versions below are from `composer.json`, `composer.lock`, and `package.json` in that revision. `vendor/` and `node_modules/` are not in git.

## Architecture

Monolithic PHP application. HTTP enters through `public/index.php` (or `server.php`, which is the `php artisan serve` router). The HTTP kernel is `app/Http/Kernel.php`. Console entry is `artisan`, kernel `app/Console/Kernel.php`.

There is no separate front-end app, no API gateway, and no background worker process. The queue example is `sync`.

```text
public/index.php
    bootstrap/app.php
    app/Http/Kernel.php
        global middleware
        web group  -> routes/web.php   -> welcome view
        api group  -> routes/api.php   -> GET user (auth:api)
```

Service providers registered in `config/app.php`: `AppServiceProvider`, `AuthServiceProvider`, `EventServiceProvider`, `RouteServiceProvider`. `App\Providers\BroadcastServiceProvider` is commented out.

## Application structure

| Path | Role |
|---|---|
| `app/User.php` | Only Eloquent model |
| `app/Http/Controllers/Controller.php` | Base controller (framework traits) |
| `app/Http/Controllers/Auth/` | Five auth controllers, not referenced by routes |
| `app/Http/Middleware/` | Stock middleware classes |
| `app/Providers/` | Stock providers |
| `app/Exceptions/Handler.php` | Parent report/render; hides password fields from flashes |
| `app/Console/Kernel.php` | Empty schedule; loads `app/Console/Commands` (directory absent) and `routes/console.php` |
| `routes/web.php` | `GET /` |
| `routes/api.php` | `GET /user` under prefix `api` |
| `routes/channels.php` | One channel callback; not loaded |
| `routes/console.php` | `inspire` |
| `config/` | Framework config set |
| `database/migrations/` | `users`, `password_resets` |
| `database/factories/UserFactory.php` | Faker user; unused by the seeder |
| `database/seeds/DatabaseSeeder.php` | Empty `run()` |
| `resources/views/welcome.blade.php` | Only view |
| `resources/js/`, `resources/sass/` | Mix sources |
| `resources/lang/en/` | Framework language lines |
| `public/` | Front controller, `.htaccess`, `web.config`, `robots.txt`, favicon, committed `js/app.js` and `css/app.css` |
| `tests/` | One feature test, one unit test |
| `storage/` | Gitignore placeholders only |

No `app/Jobs`, `app/Events`, `app/Listeners`, `app/Policies`, `app/Console/Commands`, or `resources/views/auth`.

## Languages and frameworks

| Item | Version / constraint | Evidence |
|---|---|---|
| PHP | `^7.1.3` | `composer.json` |
| Laravel | `5.8.*`, lock `v5.8.19` | `composer.json`, `composer.lock` |
| fideloper/proxy | `^4.0` | `composer.json` (`TrustProxies`) |
| laravel/tinker | `^1.0` | `composer.json` |
| PHPUnit | `^7.5` | `composer.json` require-dev |
| Vue | `^2.5.17` | `package.json` devDependencies |
| Bootstrap | `^4.1.0` | `package.json` |
| Laravel Mix | `^4.0.7` | `package.json`, `webpack.mix.js` |
| axios | `^0.18` | `package.json` |

`composer.json` `"name"` is `laravel/laravel`, description `The Laravel Framework.`, license `MIT`. That metadata was not changed to UnityApi.

Node scripts: `dev`, `development`, `watch`, `watch-poll`, `hot`, `prod`, `production`. No `package-lock.json`.

## HTTP surface

| Method | Path | Middleware | Handler | Result |
|---|---|---|---|---|
| GET | `/` | `web` | closure in `routes/web.php` | view `welcome` |
| GET | `/api/user` | `api` (`throttle:60,1`, `bindings`) and `auth:api` | closure in `routes/api.php` | authenticated user, or framework unauthenticated response |

Global middleware, in order: `CheckForMaintenanceMode`, `ValidatePostSize`, `TrimStrings`, `ConvertEmptyStringsToNull`, `TrustProxies`.

`web` group: `EncryptCookies`, `AddQueuedCookiesToResponse`, `StartSession`, `ShareErrorsFromSession`, `VerifyCsrfToken`, `SubstituteBindings`. `AuthenticateSession` is commented out.

`TrustProxies`: `$proxies` unset; `$headers = Request::HEADER_X_FORWARDED_ALL`.

Route namespace for controller routes would be `App\Http\Controllers`. Both current routes are closures, so the namespace is unused.

`routes/web.php` and `routes/api.php` contain no named routes.

## Authentication

| Guard | Driver | Provider | Notes |
|---|---|---|---|
| `web` (default) | `session` | `users` | Eloquent `App\User` |
| `api` | `token` | `users` | `'hash' => false`; storage key `api_token` |

Password broker `users`: table `password_resets`, expire 60 minutes.

`User` fillable: `name`, `email`, `password`. Hidden: `password`, `remember_token`. Cast: `email_verified_at` => `datetime`. Does not implement `MustVerifyEmail` even though that interface is imported.

Hash driver: `bcrypt` (`config/hashing.php`).

Auth controllers and their traits are listed in `prd.md` WF-3. They are not mounted. Redirect property on login, register, reset, and verification is the string `/home`, and that path has no route.

## Database

Default connection: `env('DB_CONNECTION', 'mysql')`.

`.env.example` values: host `127.0.0.1`, port `3306`, database `homestead`, username `homestead`. The example password is the stock Homestead placeholder. `config/database.php` falls back to database name `forge` and username `forge` when those env vars are missing. MySQL charset `utf8mb4`, collation `utf8mb4_unicode_ci`, `strict` true, engine `null`.

Other defined connections, unused by the migrations' code (they use the default connection): `sqlite`, `pgsql`, `sqlsrv`. Redis client config is present for cache/queue and is not selected by `.env.example`.

### `users`

| Column | Definition |
|---|---|
| `id` | big increments, primary key |
| `name` | string |
| `email` | string, unique |
| `email_verified_at` | timestamp, nullable |
| `password` | string |
| `remember_token` | framework remember-token column |
| `created_at`, `updated_at` | timestamps |

No `api_token` column.

### `password_resets`

| Column | Definition |
|---|---|
| `email` | string, index |
| `token` | string |
| `created_at` | timestamp, nullable |

No seed data. `DatabaseSeeder` does not call another seeder. The commented line references `UsersTableSeeder`, and that class is not in the tree.

## Environment configuration

`.env` is gitignored. `.env.example` is the Laravel 5.8 example:

| Key | Example value | Notes |
|---|---|---|
| `APP_NAME` | `Laravel` | Config fallback `'Laravel'` |
| `APP_ENV` | `local` | Config fallback `'production'` |
| `APP_KEY` | empty | Required before encrypted cookies/sessions work |
| `APP_DEBUG` | `true` | Config fallback `false` |
| `APP_URL` | `http://localhost` | |
| `LOG_CHANNEL` | `stack` | Matches `config/logging.php` default |
| `DB_*` | Homestead MySQL placeholders | |
| `BROADCAST_DRIVER` | `log` | |
| `CACHE_DRIVER` | `file` | |
| `QUEUE_CONNECTION` | `sync` | |
| `SESSION_DRIVER` | `file` | |
| `SESSION_LIFETIME` | `120` | |
| `REDIS_*` | `127.0.0.1`, password `null`, port `6379` | Not selected as cache/session/queue |
| `MAIL_*` | `smtp.mailtrap.io`, port `2525`, username and password `null` | `config/mail.php` host fallback is `smtp.mailgun.org`; from address fallback `hello@example.com` |
| `AWS_*` | empty keys, region `us-east-1`, empty bucket | No application caller |
| `PUSHER_*` | empty, cluster `mt1` | Copied into `MIX_PUSHER_*` |

`config/services.php` also reads `MAILGUN_DOMAIN`, `MAILGUN_SECRET`, `MAILGUN_ENDPOINT`, `POSTMARK_TOKEN`, `SPARKPOST_SECRET`, `STRIPE_KEY`, `STRIPE_SECRET`, `STRIPE_WEBHOOK_SECRET`, `STRIPE_WEBHOOK_TOLERANCE` (default 300). None of those keys are in `.env.example`.

Post-install Composer hook copies `.env.example` to `.env` when `.env` is missing, and `post-create-project-cmd` runs `php artisan key:generate`. That is the skeleton hook, not evidence that a key was committed. No `APP_KEY` is in git.

## Storage, cache, sessions, mail, queues

- Filesystem default disk: `env('FILESYSTEM_DRIVER', 'local')`. Cloud name: `env('FILESYSTEM_CLOUD', 's3')`. No `Storage::` call in `app/` or `routes/`.
- Cache default: `file`.
- Session: file driver, lifetime 120, `'encrypt' => false`.
- Mail driver default: `smtp`.
- Queue default: `sync`. Connections for database, beanstalkd, sqs, and redis are defined in `config/queue.php` and not selected by the example env.
- Logging default channel: `stack`.
- `storage/logs`, `storage/framework`, and `storage/app` contain only `.gitignore` files. `storage/*.key` is gitignored.

## Front end

`webpack.mix.js`:

```text
mix.js('resources/js/app.js', 'public/js')
   .sass('resources/sass/app.scss', 'public/css');
```

`resources/js/bootstrap.js` is required by `app.js` (axios and Bootstrap/jQuery scaffold). Vue is mounted on `#app`. The welcome view does not provide that element and does not load the bundles. `public/js/app.js` and `public/css/app.css` are committed anyway, which matches the Laravel skeleton (build output checked in).

## Jobs, events, broadcasting

- No job classes.
- One listener map: `Illuminate\Auth\Events\Registered` → `SendEmailVerificationNotification`. Ineffective unless the user model implements `MustVerifyEmail`.
- `Broadcast::routes()` and `routes/channels.php` load only from `BroadcastServiceProvider::boot`, and that provider is not registered.
- Channel rule, if it were loaded: `App.User.{id}` allows the user whose id equals `{id}`.

## Security notes visible in the tree

- `.env.example` sets `APP_DEBUG=true`. A deployment that copied the example unchanged would show debug pages.
- API tokens are stored and compared in plaintext (`hash` false) and the column is missing.
- No application authorisation beyond auth middleware on the one API route.
- CSRF exceptions: none.
- `Handler` does not report to an external tracker. `$dontReport` is empty.
- Dependencies are the 2019 lockfile (`laravel/framework` v5.8.19). No later security patch is in this repository.
- Factory password hash is the public Laravel example string. The seeder does not insert it.
- README security contact is Taylor Otwell's Laravel address, copied from the framework README. It is not an Overdrive contact.

## Deployment and infrastructure

**Unknown / Requires Confirmation.** The repository does not contain:

- Dockerfile, docker-compose, Vagrant/Homestead YAML (Homestead filenames are gitignored: `Homestead.json`, `Homestead.yaml`)
- Bitbucket Pipelines, GitHub Actions, Travis config for this repo
- nginx/Apache site files other than `public/.htaccess`
- IIS rewrite file `public/web.config` (stock Laravel file)
- process manager, cron entry, or queue worker
- a domain name

`public/robots.txt` is the stock file. Whether it is what a host serves is **Unknown**.

## Development and testing

Install path implied by the skeleton, not by a project README (the README no longer contains UnityApi setup steps):

1. `composer install` (produces `vendor/`, not committed).
2. Copy `.env.example` to `.env` if needed (Composer post-root hook does this when `.env` is absent) and `php artisan key:generate`.
3. Create the database named in `.env` and `php artisan migrate`.
4. Optional assets: `npm install` and `npm run dev`.

Tests (`phpunit.xml`):

- Suites: `tests/Unit`, `tests/Feature`, suffix `Test.php`.
- Bootstrap: `vendor/autoload.php`.
- Coverage whitelist: `./app`.
- Forced env for the test process: `APP_ENV=testing`, `BCRYPT_ROUNDS=4`, `CACHE_DRIVER=array`, `MAIL_DRIVER=array`, `QUEUE_CONNECTION=sync`, `SESSION_DRIVER=array`.
- Feature test: `GET /` status 200. It uses `RefreshDatabase`.
- Unit test: `assertTrue(true)`. It imports `RefreshDatabase` and does not use the trait.

These tests were not run during documentation. PHPUnit is not part of a checked-in script beyond `phpunit.xml`.

StyleCI config: PHP preset `laravel`, rule `unused_use` disabled, finder skips `index.php` and `server.php`; JS finder skips `webpack.mix.js`; CSS enabled. Connection of that file to a StyleCI project is **Unknown**.

## Git history relevant to structure

| Commit | Effect |
|---|---|
| `2a22b30` | Adds `README.md` containing `# UnityApi` only |
| `23894c8` | Adds every other tracked file and replaces the README with the Laravel README. Commit subject is `Update artisan` |

Only branch: `master`. Author of both commits: Jaco Brits.

## Discrepancy with the onboarding file list

The issue that opened this documentation listed `sonar-project.properties` and `sonarqube_scan.bat` at the repository root. They are not tracked at `23894c8` and they are not in the parent commit. Treat them as absent from the source of truth for this revision unless someone produces those files.

## Related Silicon Ark directories

Other directories under Silicon Ark use a Unity name. This repository's code and README do not refer to them. A link between products is **Unknown / Requires Confirmation**.
