# PRD — UnityApi

Evidence date: 2026-09-30.

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

Provenance labels used below: **Documented**, **Implemented**, **Inferred**, **Planned**, **Unknown**.

No requirements document exists in the source repository. The requirements in this file are the behaviour present in that revision. They are framework defaults unless a row says otherwise. Nothing in the tree states a product goal.

## Product purpose

**Documented:** the first commit's README heading was `# UnityApi`. That sentence was removed in `23894c8`. The current README describes the Laravel framework, not this repository.

**Unknown:** who the product is for, what problem it solves, and why the repository is named UnityApi. No issue, comment, or code comment in this tree answers that.

**Inferred:** the committed application is the Laravel 5.8 skeleton (`laravel/laravel`) and does not yet implement a distinct product.

## Users and roles

| Actor | Evidence | Status |
|---|---|---|
| Anonymous visitor | `GET /` has no `auth` middleware | **Implemented** |
| Authenticated web user | Auth controllers exist; no web route calls them | Controllers **Implemented**; a usable login journey is **not implemented** |
| API token holder | `GET /api/user` uses `auth:api` | Route **Implemented**; the `users` migration has no `api_token` column, so a user created from that migration cannot satisfy the token guard |
| Administrator or other role | No role column, Gate, or policy | **Not implemented** |

`config/auth.php` default guard is `web` (session). The `api` guard driver is `token`, provider `users`, `hash` => `false` (lookup value is not hashed).

`app/User.php` is an Eloquent `Authenticatable` with `Notifiable`. It imports `MustVerifyEmail` and does not implement that interface. Email verification is therefore not required for the model.

No seeder creates a user. `DatabaseSeeder::run()` is empty. `database/factories/UserFactory.php` can build a fake user for tests; nothing in the application calls it.

## Major workflows

### WF-1 — Open the site

- **Who:** anonymous visitor.
- **Trigger:** `GET /`.
- **Input:** none.
- **Behaviour:** `routes/web.php` returns view `welcome`. The view title is `Laravel`. It does not reference `public/js/app.js` or `public/css/app.css`.
- **Output:** HTTP 200 and the welcome HTML, if the framework boots. `tests/Feature/ExampleTest.php` asserts status 200 for `GET /`. That test was not executed during this inspection.
- **Errors:** framework exception handler (`app/Exceptions/Handler.php`) reports and renders via the parent handler. `APP_DEBUG` in `.env.example` is `true`. Config default when the env var is absent is `false` (`config/app.php`).
- **Provenance:** **Implemented** (stock route and view).

### WF-2 — Read the current API user

- **Who:** a caller holding an API token.
- **Trigger:** `GET /api/user`.
- **Input:** token guard credentials. With `hash` => `false`, Laravel's token guard reads `api_token` from the query string, request input, or bearer header, and compares it to the `api_token` column.
- **Behaviour:** middleware `auth:api`. On success the closure returns `$request->user()`.
- **Validation:** unauthenticated requests are rejected by the `auth` middleware (framework 401 for the `api` guard).
- **Gap:** `database/migrations/2014_10_12_000000_create_users_table.php` columns are `id`, `name`, `email` (unique), `email_verified_at` (nullable), `password`, `remember_token`, timestamps. There is no `api_token` column and no later migration. **Inferred:** a database migrated only from this tree cannot authenticate this route.
- **Provenance:** route **Implemented**; end-to-end success **not possible** from the shipped schema.

### WF-3 — Register, log in, reset password, verify email

- **Who:** would be a guest (`guest` middleware on login, register, forgot-password, and reset) or an authenticated user (verification controller uses `auth`).
- **Trigger:** none. `routes/web.php` does not call `Auth::routes()` or name these controllers. `resources/views/` contains only `welcome.blade.php`.
- **Behaviour present in the classes, if something else invoked them:**
  - Register (`RegisterController`): name required string max 255; email required string email max 255 unique on `users`; password required string min 8 confirmed. Creates a `User` with `Hash::make` on the password (bcrypt; `config/hashing.php` driver `bcrypt`). Redirect target `/home`.
  - Login (`LoginController`): trait `AuthenticatesUsers`. Redirect target `/home`. `guest` middleware except `logout`.
  - Forgot password (`ForgotPasswordController`): trait `SendsPasswordResetEmails`. `guest` middleware.
  - Reset password (`ResetPasswordController`): trait `ResetsPasswords`. Redirect target `/home`. `guest` middleware. Reset tokens use table `password_resets` and expire after 60 minutes (`config/auth.php`).
  - Verification (`VerificationController`): trait `VerifiesEmails`. Middleware `auth`; `signed` on `verify`; `throttle:6,1` on `verify` and `resend`. Redirect target `/home`.
- **Missing pieces:** no `/home` route, no `HomeController`, no auth Blade views, and `User` does not implement `MustVerifyEmail`. `EventServiceProvider` listens for `Registered` and maps `SendEmailVerificationNotification`, which does not send when the model does not implement that contract.
- **Provenance:** controller and config behaviour **Implemented** as unused scaffold. A user-facing auth workflow is **not implemented**.

### WF-4 — Scheduled or console work

- **Trigger:** `php artisan inspire` (closure in `routes/console.php`) prints a framework quote.
- **Schedule:** `app/Console/Kernel.php` `schedule()` is empty. No command class exists under `app/Console/Commands` (that directory is not in the tree). The kernel still calls `$this->load(__DIR__.'/Commands')`.
- **Provenance:** **Implemented** framework sample. No product job.

## Functional requirements

### FR-001 — Serve the welcome page

- **Requirement:** `GET /` returns the `welcome` view.
- **Who:** any caller.
- **Trigger:** HTTP GET `/`.
- **Inputs:** none.
- **Expected behaviour:** view `resources/views/welcome.blade.php` is rendered inside the `web` middleware group (cookies, session, CSRF, bindings).
- **Outputs:** HTML welcome page.
- **Validation:** none.
- **Errors:** view or boot failures use the framework exception handler.
- **Dependencies:** PHP, Composer autoload (`vendor/` not in git), `APP_KEY` for encrypted cookies once a real `.env` exists.
- **Evidence:** `routes/web.php`, `resources/views/welcome.blade.php`, `app/Providers/RouteServiceProvider.php`, `tests/Feature/ExampleTest.php`.
- **Implementation:** Implemented.
- **Confidence:** High.

### FR-002 — Expose the authenticated API user

- **Requirement:** `GET /api/user` returns the user resolved by the `api` guard.
- **Who:** a client that can pass the token guard.
- **Trigger:** HTTP GET `/api/user`.
- **Inputs:** API token as required by Laravel's token guard.
- **Expected behaviour:** `auth:api` then `return $request->user()`. The route is loaded with prefix `api` and middleware group `api` (`throttle:60,1` and `bindings`).
- **Outputs:** the user model as a response. `User::$hidden` hides `password` and `remember_token`.
- **Validation:** authentication failure is the framework unauthenticated response.
- **Errors:** schema has no `api_token` column, so a successful lookup against the migrated table is not supported by this repository.
- **Dependencies:** `users` table, `APP_KEY` not required for the token comparison itself, database credentials.
- **Evidence:** `routes/api.php`, `app/Providers/RouteServiceProvider.php`, `app/Http/Kernel.php`, `config/auth.php`, `app/User.php`, users migration.
- **Implementation:** Route implemented. Authenticatable schema incomplete.
- **Confidence:** High.

### FR-003 — Persist users and password-reset rows

- **Requirement:** migrations create `users` and `password_resets`.
- **Who:** an operator running migrations. No deploy doc says who that is.
- **Trigger:** `php artisan migrate` (framework command; not wrapped by a project script).
- **Inputs:** database connection from the environment. `.env.example` sets `DB_CONNECTION=mysql`, host `127.0.0.1`, port `3306`, database `homestead`, username `homestead`. The password in that example file is the published Homestead placeholder, not evidence of a live credential. `.env` is gitignored.
- **Expected behaviour:** `users` as in FR-002's column list; `email` unique. `password_resets` has indexed `email`, `token`, nullable `created_at`.
- **Outputs:** those two tables. No foreign keys.
- **Validation:** unique email at the schema and, if registration ran, in `RegisterController`.
- **Errors:** not customised.
- **Dependencies:** a reachable database. Whether migrations were applied anywhere is **Unknown**.
- **Evidence:** `database/migrations/2014_10_12_000000_create_users_table.php`, `database/migrations/2014_10_12_100000_create_password_resets_table.php`, `.env.example`, `config/database.php`.
- **Implementation:** Migration files implemented. Execution not evidenced.
- **Confidence:** High for the files; Unknown for any live database.

### FR-004 — Registration field rules (unreachable)

- **Requirement:** if `RegisterController::validator` runs, name, email, and password must match the rules in WF-3.
- **Who:** a guest, but only if a route called the controller. No such route exists.
- **Trigger:** not wired.
- **Inputs:** `name`, `email`, `password`, `password_confirmation`.
- **Expected behaviour:** validation failure returns the framework's redirect-back with errors for a web request. Success creates the user and the trait redirects to `/home`, which has no route.
- **Outputs:** a `users` row, or a validation error.
- **Provenance:** **Implemented** method, **not** an available product workflow.
- **Evidence:** `app/Http/Controllers/Auth/RegisterController.php`, `routes/web.php`.
- **Implementation:** Code present, not routed.
- **Confidence:** High.

## Integrations

No application code calls an external product API.

`config/services.php` holds empty credential slots for Mailgun, Postmark, SES, SparkPost, and Stripe. `.env.example` includes blank `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_BUCKET`, and Pusher keys, plus Mailtrap SMTP placeholders (`MAIL_HOST=smtp.mailtrap.io`, port `2525`). `config/mail.php` default from-address is `hello@example.com`. `config/filesystems.php` cloud disk name defaults to `s3`. No controller or job uses mail, Stripe, Pusher, or Storage.

**Inferred:** these entries are the framework template, not active integrations.

`BROADCAST_DRIVER=log` in `.env.example`. Application `BroadcastServiceProvider` is not registered, so `routes/channels.php` (channel `App.User.{id}`, allow when the user id matches) is not loaded.

Queue connection in `.env.example` is `sync`. Cache driver `file`. Session driver `file`, lifetime 120 minutes.

## Constraints

- PHP `^7.1.3` and Laravel `5.8.19`. Laravel 5.8 is outside current framework support. That is a property of the locked version, not a project decision recorded in docs.
- Application timezone `UTC`. Locale and fallback locale `en`. Translation files exist only under `resources/lang/en/` (auth, pagination, passwords, validation).
- API group throttle is 60 requests per minute (`throttle:60,1`).
- CSRF middleware is on the `web` group. `$except` in `VerifyCsrfToken` is empty.
- Session cookie encryption is off (`config/session.php` `'encrypt' => false`). Session lifetime example is 120 minutes.
- Trusted proxies: `TrustProxies::$proxies` is unset. Headers are `Request::HEADER_X_FORWARDED_ALL`.
- No rate-limit configuration beyond the two framework throttles above (API group, and the verification controller's `throttle:6,1`, which is not routed).
- No project CI. The README build badge points at `laravel/framework` on Travis, not at this repository.
- `.styleci.yml` uses the `laravel` PHP preset and disables `unused_use`. Whether a StyleCI account is connected to the Bitbucket repository is **Unknown**.

## Planned behaviour

None found. No TODO, roadmap, or commented product route describes future work. Commented framework samples (the hourly `inspire` schedule, the database user-provider alternative, `AuthenticateSession`) are the Laravel template, not a project plan.

## Assumptions that must not be treated as requirements

- That UnityApi is the HTTP API for the other Unity codebases. **Unknown / Requires Confirmation.**
- That login and registration are available to users. The classes exist; the routes and views do not.
- That `GET /api/user` works against a migrated database. The token column is absent.
- That SonarQube scanning is part of this project. The scan-host file list included `sonar-project.properties` and `sonarqube_scan.bat`; git at `23894c8` does not.
