# Business rules — UnityApi

Evidence date: 2026-09-30.

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

No business-rules document exists in the source repository. The rules below are taken from code and config. Each rule is marked **Inferred** when it is a framework default observed in this tree rather than a stated domain policy. No rule unique to a Unity product was found.

Do not treat an unreachable controller as a live policy. Where a rule sits in a class that no route calls, the row says so.

## Identity and access

### BR-001 — Web requests are session-based by default

- **Rule:** the default guard is `web` (session driver, Eloquent provider `App\User`).
- **Provenance:** **Inferred** from `config/auth.php`. This is the Laravel 5.8 template.
- **Enforcement:** framework auth manager. No project policy class is registered. `AuthServiceProvider::$policies` is empty.

### BR-002 — API authentication is an unhashed token

- **Rule:** the `api` guard uses the `token` driver, provider `users`, `'hash' => false`.
- **Provenance:** **Inferred** from `config/auth.php`. Framework template. `hash => false` means the stored token is compared directly.
- **Enforcement:** `GET /api/user` applies `auth:api` (`routes/api.php`).
- **Conflict with schema:** the `users` migration does not create `api_token`. The guard's storage key is `api_token`. The route and the table do not agree. **Requires confirmation** only if someone expects this endpoint to work; the code discrepancy itself is evidenced.

### BR-003 — There are no roles or permissions

- **Rule:** no role, permission, tenant, or ownership check exists beyond the single broadcast-channel callback (BR-010), which is not registered.
- **Provenance:** **Inferred** from the absence of Gate definitions, policies, and extra user columns.
- **Evidence:** `app/Providers/AuthServiceProvider.php`, `app/User.php`, users migration.

### BR-004 — Password and confirmation are not flashed back

- **Rule:** validation errors must not flash `password` or `password_confirmation`.
- **Provenance:** **Inferred** framework default in `app/Exceptions/Handler.php` `$dontFlash`.

## Registration rules (code present, no route)

### BR-005 — Registration field constraints

- **Rule:** name is required, string, max 255. Email is required, string, email, max 255, unique on `users`. Password is required, string, minimum 8 characters, and must match `password_confirmation`.
- **Provenance:** **Inferred** from `RegisterController::validator`. Same rules as the Laravel 5.8 skeleton. Not a separately documented product policy.
- **Enforcement:** only if that method is called. `routes/web.php` never routes to `RegisterController`.
- **On success:** `User::create` stores `name`, `email`, and `Hash::make(password)`. Mass-assignable fields are `name`, `email`, `password` (`app/User.php` `$fillable`).

### BR-006 — Email is unique

- **Rule:** `users.email` is unique.
- **Provenance:** **Implemented** in the migration (`$table->string('email')->unique()`) and repeated in BR-005.
- **Enforcement:** database unique index when migrated. Application validator only on the unrouted registration action.

### BR-007 — Guest-only auth actions and post-auth redirect

- **Rule:** login, registration, forgot-password, and reset-password controllers apply `guest` (login excludes `logout`). After login, registration, reset, or verification the redirect property is `/home`.
- **Provenance:** **Inferred** from the five auth controllers.
- **Gap:** `/home` is not a route. These controllers are not routed. The rule does not run in the shipped router.

### BR-008 — Password reset token lifetime

- **Rule:** password reset tokens for provider `users` expire after 60 minutes. Storage table is `password_resets`.
- **Provenance:** **Inferred** from `config/auth.php` `'expire' => 60`. Framework default.
- **Related table:** `email` (indexed), `token`, nullable `created_at`. No unique constraint on email is declared in the migration.

### BR-009 — Email verification is not required

- **Rule:** `User` does not implement `MustVerifyEmail`. The verification controller would require `auth`, a signed URL on `verify`, and throttle `6` attempts per `1` minute on `verify` and `resend`, but it is not routed.
- **Provenance:** **Inferred** from `app/User.php` and `VerificationController`. The `Registered` → `SendEmailVerificationNotification` listener is registered and does not apply while the model omits the contract.
- **Evidence:** `app/Providers/EventServiceProvider.php`, `app/User.php`, `VerificationController.php`.

### BR-010 — Private user broadcast channel

- **Rule:** channel `App.User.{id}` authorises only when the authenticated user's id equals the channel id.
- **Provenance:** **Inferred** from `routes/channels.php`. Framework sample.
- **Enforcement:** not active. `App\Providers\BroadcastServiceProvider` is commented out in `config/app.php`, so the channel file is not loaded.

## Request limits and session

### BR-011 — API rate limit

- **Rule:** routes in the `api` middleware group allow 60 requests per 1 minute per client, using the framework throttle.
- **Provenance:** **Inferred** from `app/Http/Kernel.php` `'throttle:60,1'`. The only API route is `GET /api/user`.
- **Not applied to** `GET /`.

### BR-012 — Web CSRF

- **Rule:** state-changing `web` requests require a valid CSRF token. No URI is excluded.
- **Provenance:** **Inferred** from the `web` group and `VerifyCsrfToken::$except` (empty). `GET /` does not change state.

### BR-013 — Session lifetime

- **Rule:** session lifetime is `SESSION_LIFETIME` minutes, default 120. The session cookie is not encrypted (`'encrypt' => false`).
- **Provenance:** **Inferred** from `config/session.php` and `.env.example` (`SESSION_LIFETIME=120`, `SESSION_DRIVER=file`).
- **Driver actually used in a deployment** depends on env and is **Unknown**.

## Data rules

### BR-014 — User row shape

- **Rule:** a user row has a big-increment id, name, unique email, nullable `email_verified_at`, password string, remember token, and `created_at` / `updated_at`.
- **Provenance:** **Implemented** in the users migration.
- **Hidden from array/JSON output:** `password`, `remember_token`.
- **Cast:** `email_verified_at` to datetime.

### BR-015 — Passwords are bcrypt hashes

- **Rule:** the hash driver is `bcrypt`. Registration uses `Hash::make`.
- **Provenance:** **Inferred** from `config/hashing.php` and `RegisterController::create`.
- **Factory note:** `UserFactory` sets a fixed public bcrypt string commented as `password`, and sets `email_verified_at` to `now()`. The seeder does not call the factory. This is the Laravel example factory, not a production account.

### BR-016 — No domain validation beyond the framework language lines

- **Rule:** `resources/lang/en/validation.php`, `auth.php`, `passwords.php`, and `pagination.php` are the English framework message catalogues. No custom attribute or domain message was identified as project-specific.
- **Provenance:** **Inferred** (stock files). Locale `en`, fallback `en`, timezone `UTC` (`config/app.php`).

## Operational rules

### BR-017 — Queued work runs inline unless env changes it

- **Rule:** example env sets `QUEUE_CONNECTION=sync`. Config default is the same. No job class exists.
- **Provenance:** **Inferred** from `.env.example`, `config/queue.php`, and the absence of `app/Jobs`.

### BR-018 — Nothing is scheduled

- **Rule:** the scheduler registers no command.
- **Provenance:** **Implemented** empty `schedule()` in `app/Console/Kernel.php`. The commented `inspire` hourly line is the template, not an active rule.

### BR-019 — Maintenance mode is the framework switch

- **Rule:** `CheckForMaintenanceMode` is global middleware. No custom allowance list was added in this project file beyond the class that extends the framework middleware.
- **Provenance:** **Inferred** from `app/Http/Kernel.php` and `app/Http/Middleware/CheckForMaintenanceMode.php`. `$except` is empty, so maintenance mode blocks every URI.

## Rules that were not found

- Pricing, tenancy, approval chains, or retention periods.
- A product owner, support process, or audit requirement.
- Any rule that names Unity, a customer, or another Overdrive system.

If a business owner holds rules for UnityApi outside this repository, they are **Unknown / Requires Confirmation** and are not invented here.
