# Technical documentation — coreUnit

Evidence date: 2026-10-18.

Source: `git@bitbucket.org:overdrive/coreunit.git`, `master` at `e424b25` (2019-08-05). Commands below are what the repo contains. They were not run in this investigation.

## Repository layout

```text
coreunit/
  README.md                 Unity title, WAMP, Passport, yarn build
  .htaccess                 Access-Control-Allow-Origin: *
  api/                      Laravel 5.8 application
  frontend/                 Fuse React 3.0.0 (Create React App)
  public/                   Second Create React App plus Smart Admin assets
```

`origin/trev` (`5f44176`, 2019-09-02) moves `public/package.json` to `/package.json` and `public/src` to `/src`, and adds a root `.gitignore` and `package-lock.json`. `frontend/` and `api/` stay where they are. That branch is not merged.

The issue inventory named `sonar-project.properties` and `sonarqube_scan.bat`. They are not tracked at `e424b25`.

## Languages and frameworks

| Part | Stack | Evidence |
|---|---|---|
| API | PHP `^7.1.3`, Laravel `5.8.*`, Passport `^7.3`, `spatie/laravel-cors` `^1.5`, Tinker `^1.0` | `api/composer.json` |
| API front-end assets | Laravel Mix 4, Vue 2.5, Bootstrap 4.1, jQuery 3, Sass | `api/package.json`, `api/webpack.mix.js`, `api/resources/js/components/ExampleComponent.vue` |
| Fuse UI | React 16.8.6, React Scripts 3.0.1, Redux 4, React Router 5, Material UI 4.0.1, Axios 0.19, Tailwind 1.0.2 | `frontend/package.json` |
| Small UI | React 16.8.6, React Scripts 3.0.1, React Router 5, Formik 1.5, Yup 0.27, Axios 0.19 | `public/package.json` |

Dev-only API packages: Whoops, Collision, PHPUnit `^7.5`, Mockery, Faker, Laravel dump server. `minimum-stability` is `dev` with `prefer-stable` true, left over from the JWT `dev-develop` constraint. HEAD `composer.json` no longer requires `tymon/jwt-auth`.

`frontend/LICENSE` is `https://themeforest.net/licenses/terms/regular`. `frontend/CREDITS` lists stock photo and icon sources for the theme.

## Application structure

### Laravel

Standard 5.8 skeleton under `api/`. Application code that is not the skeleton:

- `app/Http/Controllers/API/AuthController.php` — namespace `App\Http\Controllers\Api`
- `app/Http/Controllers/API/RegisterController.php` — namespace `App\Http\Controllers\API`
- `app/Http/Controllers/API/ProductController.php` — namespace `App\Http\Controllers\API`
- `app/Http/Controllers/API/BaseController.php`
- `app/Http/Middleware/Cors.php`
- `app/Product.php`
- `app/User.php` — `HasApiTokens`, `Notifiable`, `MustVerifyEmail`
- `config/cors.php`
- `database/migrations/2019_07_13_213211_create_products_table.php`

`RouteServiceProvider` sets namespace `App\Http\Controllers`, maps `routes/web.php` with middleware `web`, and maps `routes/api.php` with prefix `api` and middleware `api`.

The controller directory is `API`. `AuthController`'s namespace segment is `Api`. On a case-sensitive volume those paths differ. See the PRD discrepancy list.

`api/vendor/` is gitignored. Package discovery (`extra.laravel.dont-discover` is empty) is what loads Passport and Spatie CORS. `config/app.php` does not list `PassportServiceProvider`. `AuthServiceProvider` calls `Passport::routes()` itself.

### Fuse

`frontend/src/index.js` renders `app/App` and unregisters the service worker. Routes are assembled in `frontend/src/app/configs/routesConfig.js`. The catch-all path `/` redirects to `/login`.

`frontend/src/app/auth/Auth.js` constructs the auth listeners and then leaves `jwtCheck()`, `auth0Check()`, and `firebaseCheck()` commented out. `jwtService` (`frontend/src/app/services/jwtService/jwtService.js`) still talks to `/api/auth`, `/api/auth/register`, `/api/auth/access-token`, and `/api/auth/user/update`. Those paths are not in `api/routes/api.php`.

### Small app

`public/src/index.js` is its own `ReactDOM.render` with `BrowserRouter`. It does not use the Laravel or Fuse build.

`public/src/components/assets/` is a Smart Admin tree (plugins, sounds, demo PHP). It includes AppleDouble `._*` files. The router does not import that tree.

## Data

Committed migrations:

| Table | File | Columns |
|---|---|---|
| `users` | `2014_10_12_000000_create_users_table.php` | `id` (bigIncrements), `name`, `email` unique, `email_verified_at` nullable, `password`, `remember_token`, timestamps |
| `password_resets` | `2014_10_12_100000_create_password_resets_table.php` | `email` index, `token`, `created_at` nullable |
| `products` | `2019_07_13_213211_create_products_table.php` | `id` (increments), `name`, `detail` text, timestamps |

Passport 7 expects `oauth_auth_codes`, `oauth_access_tokens`, `oauth_refresh_tokens`, `oauth_clients`, and `oauth_personal_access_clients`. Those migrations are not in `api/database/migrations/`. `createToken` needs them and a personal access client, which `passport:install` creates. The README does not mention that command.

Default connection is `env('DB_CONNECTION', 'mysql')` (`api/config/database.php`). `api/.env.example` sets MySQL on `127.0.0.1:3306`, database `homestead`, username `homestead`, password `secret`. That file is the Laravel sample. `api/.env` is gitignored and is not in the clone.

No foreign keys. `products.id` is a 32-bit increment. `users.id` is a big increment.

## HTTP API

Prefix `/api`. Throttle 60 requests per minute. JSON bodies.

| Method | Path | Auth | Controller | Success | Failure |
|---|---|---|---|---|---|
| POST | `/api/register` | none | `API\RegisterController@register` | 200 envelope, token name `MyApp` | 404 validation envelope |
| POST | `/api/v1/register` | `cors` | `Api\AuthController@register` | 200 `{success:{token}}`, token name `AppName` | 401 `{error}` |
| POST | `/api/v1/login` | `cors` | `Api\AuthController@login` | 200 `{success:{token}}` | 401 `{error: Unauthorised}` |
| POST | `/api/v1/getUser` | `auth:api` | `Api\AuthController@getUser` | 200 `{success: user}` | 401 from the guard |
| GET | `/api/user` | `auth:api` | closure | user model | 401 from the guard |
| GET, POST, GET `{id}`, PUT/PATCH `{product}`, DELETE `{product}` | `/api/products` | `auth:api` | `ProductController` | 200 envelope | 404 envelope, or Laravel 404 for missing route-model ids |
| GET | `/api/products/create` and `/api/products/{product}/edit` | `auth:api` | none | — | missing method |

`Passport::routes()` also registers Passport's `/oauth/*` routes on the application, outside the `api` prefix. The React code does not call them.

`GET /` (web middleware, no `api` prefix) returns the welcome view.

`Auth::attempt` in `login` uses the default guard `web`. The `api` group does not include `StartSession`. **Inferred:** a successful password check can throw `Session store not set on request` before the token is created. Not executed in this pass.

User JSON hides `password` and `remember_token` (`User::$hidden`).

## Authentication

1. Register hashes with `bcrypt` and stores the hash on `users.password`.
2. `createToken` inserts a personal access token through Passport.
3. Later calls send `Authorization: Bearer <token>`. The `api` guard's provider is the Eloquent `User` model.
4. The Fuse home page does not attach that header. It does not call `jwtService.setSession`.
5. Web `LoginController` would use the session guard and redirect to `/home`. It is not routed. `/home` is not a route.

Password reset expiry in `config/auth.php` is 60 minutes. No route sends a reset.

## CORS, cookies, CSRF

- Global middleware includes `\Spatie\Cors\Cors::class` plus the usual maintenance, post size, trim, empty-string, and trust-proxy middleware.
- Spatie profile: credentials allowed, origin `*`, methods POST GET OPTIONS PUT PATCH DELETE, headers `*`, max age 86400 seconds. Forbidden response body is `{message: Forbidden (cors)., status: 403}`.
- `App\Http\Middleware\Cors` runs only on the two v1 anonymous posts. It sets `Allow-Origin: *` and `Allow-Methods`. The `Allow-Headers` assignment is commented out, so this middleware does not add `Authorization` or `Content-Type` to the allow list. Spatie, which runs globally, allows every header.
- `VerifyCsrfToken` is on the `web` group only. API routes are not CSRF-protected.
- Three `.htaccess` files set `Access-Control-Allow-Origin: *` at Apache when `mod_headers` is loaded. They do not rewrite to `index.php`. Laravel's own rewrite remains `api/public/.htaccess`.

## Configuration and secrets

`api/.env.example` (sample values, not a deployed environment):

- `APP_NAME=Laravel`, `APP_ENV=local`, `APP_DEBUG=true`, `APP_URL=http://localhost`, `APP_KEY` empty
- `LOG_CHANNEL=stack`
- MySQL homestead settings above
- `BROADCAST_DRIVER=log`, `CACHE_DRIVER=file`, `QUEUE_CONNECTION=sync`, `SESSION_DRIVER=file`, `SESSION_LIFETIME=120`
- Redis on `127.0.0.1:6379` with password `null`
- Mail driver `smtp`, host `smtp.mailtrap.io`, port `2525`, username and password `null`
- Empty AWS and Pusher keys

`config/app.php` timezone is `UTC`. `APP_DEBUG` defaults to false when the env value is missing, and the example file sets it true.

`frontend/.env` is tracked. It sets `REACT_APP_MAP_KEY`. The value is a Google Maps browser key and is omitted here. The only reader found is `frontend/src/app/main/documentation/third-party-components/google-map-react/examples/simple.js`. `frontend/.gitignore` does not list `.env`.

No AWS, Redis, or Pusher client call exists under `api/app`.

## Queues, schedule, mail, storage

- Queue default is `sync`. `routes/console.php` defines `inspire`. `Console\Kernel::schedule` is empty. No job classes.
- Mail config is the framework file. The only listener is `SendEmailVerificationNotification`, and the API controllers do not dispatch `Registered`.
- Filesystems config is the Laravel default (`config/filesystems.php`). No upload controller exists.
- `storage/` and `bootstrap/cache/` contain the usual `.gitignore` placeholders. Logs are not committed.

## Frontend integration points

| Client | URL it actually requests | Matches a Laravel route |
|---|---|---|
| README | `http://localhost/coreUnit/api/public/api/v1/login` | Yes, if the vhost document layout matches that path |
| `Login.js` | `http://local.unity/api/public/api/v1/login` | Same path, different host |
| `Login2Page.js` | `http://localhost/coreUnit/api/public/api/v1/loginlogin` | No |
| `LoginForm.js` | none (constant `https://localhost/api/public/api` is unused) | No |
| `Dashboard.js` | `http://localhost/coreUnit/api/public/api/client/list` | No |
| Fuse e-commerce and other demos | paths such as `/api/e-commerce-app/products` | No |
| `jwtService` | `/api/auth` and related | No |

`Login.js` also sets `axios.defaults.headers.post['Access-Control-Allow-Origin'] = '*'`. That header is not an allowed request header in the usual browser set, and it does not change the response CORS policy.

## Infrastructure and deployment

**Documented** host: WAMP, with artisan run inside `api/`. The login URL implies the web root is the parent of `api/public`, not `api/public` itself, because the path includes `/api/public/`.

No Dockerfile, no `bitbucket-pipelines.yml`, no Forge or Envoy file, no server name in a vhost file. `local.unity` appears only as a string in `Login.js`.

Fuse production build, from `frontend/package.json`:

```text
yarn run tailwind && node ./purge-tailwindcss.js && cross-env GENERATE_SOURCEMAP=false react-scripts build
```

`yarn start` runs Tailwind and then the dev server (`frontend/README.md` says `http://localhost:3000`). The README at the repo root says `yarn build` when the branch is in development mode, and does not say which directory.

The small app uses `npm` script names (`react-scripts start` / `build`) and has no Tailwind step.

`api/package.json` builds the unused Vue welcome assets with Laravel Mix (`npm run dev`, `npm run prod`).

Apache `api/public/.htaccess` is the Laravel front-controller rewrite. `api/public/web.config` is the IIS equivalent shipped with Laravel. `api/server.php` is the `php artisan serve` router.

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

- `APP_DEBUG=true` in the example env. A missing `APP_KEY` is invalid for Laravel encryption.
- CORS origin `*` with `allow_credentials` true.
- Register and login are anonymous and share the 60/minute throttle. Passwords have no server-side length rule.
- Duplicate email surfaces as a database error.
- `frontend/.env` commits a third-party browser key.
- User factory comment records the well-known Laravel sample password. The seeder is not called.
- Smart Admin `public/src/components/assets/php/demo-register.php`, `demo-contacts.php`, and `demo-comment.php` are theme demos. The router does not include them. Whether Apache can still request them if `public/` is inside the web root was not tested.
- AppleDouble `._*` files are committed under that asset tree.

## Development and tests

Documented tools in `README.md`: WAMP, Visual Studio Code, HeidiSQL or phpMyAdmin, Postman, Chrome React tools.

Artisan is run from `api/` (`php artisan`, which the README spells `artasan`).

PHPUnit (`api/phpunit.xml`):

- Bootstraps `vendor/autoload.php`.
- Suites: `tests/Unit`, `tests/Feature`.
- Forces `APP_ENV=testing`, `BCRYPT_ROUNDS=4`, cache `array`, mail `array`, queue `sync`, session `array`.
- Does not set a testing database. The feature test hits the default connection only if the welcome view touches it. `tests/Feature/ExampleTest.php` asserts `GET /` is 200. `tests/Unit/ExampleTest.php` asserts `true`.
- Neither test covers register, login, or products.

No `*.test.js` or `*.spec.js` is tracked. `frontend/package.json` and `public/package.json` still define `react-scripts test`. `public/src/App.test.js` existed at `5cf8a13` and is not at HEAD.

StyleCI config is the Laravel default at `api/.styleci.yml`. No CI config calls it.

## Background processing and monitoring

No worker, scheduler entry, health check, or log shipper is configured beyond Laravel's `LOG_CHANNEL=stack` sample. Sonar files named in the 2026-09-28 issue inventory are not in this revision.
