# Platform administration guide

This guide explains the platform-owner portal, company access, consulting relationships, licenses, users, roles, and the normal financial-model application.

## 1. The two application areas

| Area | Address | Intended users | Purpose |
|---|---|---|---|
| Platform portal | `/platform/login` | System Owners and authorized consulting administrators | Manage companies, licenses, relationships, branding, portal users, and platform access |
| Main application | `/login` | Users belonging to a company | Work with models, inputs, outputs, reports, company users, and company roles |

These areas use different authorization scopes. A System Owner is a dedicated global identity. A consulting administrator is a normal user belonging to a consulting company with consulting-portal access enabled.

## 2. Signing in

### System Owner

Open `http://localhost:3330/platform/login` and leave **Company** blank. Enter the email address and password stored in `platform_admins`.

Create or reset the first System Owner safely through environment variables:

```env
PLATFORM_ADMIN_EMAIL=owner@example.com
PLATFORM_ADMIN_NAME=Platform Owner
PLATFORM_ADMIN_PASSWORD=replace-with-a-long-password
```

```bash
npm run db:migrate
npm run db:seed-platform-admin
```

The password must contain at least 12 characters. Running the seed command again for the same email resets its password, unlocks it, and makes it active. Never commit real passwords to `.env.example`, source code, or this guide.

After signing in, use **System Owner users** in the sidebar to create additional System Owners, reset passwords, or activate/deactivate accounts. The system prevents deactivation of the final active System Owner.

### Consulting administrator

Open `/platform/login` and enter all three values:

- **Company:** the consulting firm's exact company name, for example `Philadelphia Consulting`.
- **Email:** a user belonging to that consulting firm.
- **Password:** that user's password.

The account must be active, have the legacy administrator or super-administrator compatibility role, and have `can_access_consulting_portal` enabled. The consulting firm's account and license must also permit access.

From the consulting portal sidebar, select **Open main application** to use the consulting firm's own models and company administration screens without signing in again. The same account can also sign in directly through `/login` using the consulting firm's company name.

### Ordinary company user

Open `/login` and enter the exact company name, email, and password. This applies to standalone companies, consulting firms, and consulting-managed clients. Users always belong to one company and never inherit access from a related company.

## 3. Company types and ownership rules

### Standalone company

- Created by a System Owner.
- Has no consulting-company relationship.
- Manages its own users and company-scoped roles in the main application.
- Displays only its own logo.

### Consulting firm

- Created by a System Owner.
- Has a configurable maximum number of managed client companies.
- Its authorized portal administrators can create only **consulting-managed clients** beneath their own firm.
- Its administrators can manage the consulting firm's own users and roles in the main application.
- A consulting administrator can see only its firm and its direct managed clients in the platform portal.

### Consulting-managed client

- Created by a System Owner or by its consulting firm.
- Must reference one consulting firm.
- Has its own users, roles, models, data, and license capacity.
- Its users do not inherit access from the consulting firm.
- The main header shows the client's logo on the left and the consulting firm's logo on the right.

## 4. Platform company management

Open **Companies** in the platform portal. Each company row provides company details and the relevant user-management action.

### Creating a company

1. Select **Add company**.
2. Enter the company identity and industry.
3. Choose its company type. A consulting-scoped administrator is automatically restricted to `Consulting-managed client`.
4. Set account state, license dates, and maximum active users.
5. For a consulting firm, set its maximum client-company allowance.
6. For a managed client created by a System Owner, select its consulting partner.

Every newly created company receives its own default company roles. Company data is isolated by `org_id` on the server.

### Editing a company

Select **Edit** on its row to change its details, license, capacity, relationship, or account state. The company logo editor accepts PNG, JPEG, WebP, or SVG images up to 1 MB and fits large or unusually shaped artwork inside a bounded preview.

### License rules

- **Active:** account enabled and license date valid.
- **Expiring soon:** license is near its end date.
- **Expired:** license end date has passed; normal company access is refused.
- **Suspended/Disabled:** normal company access is refused regardless of dates.
- Active-user capacity is calculated from active accounts; it is not manually entered.
- Activating or creating a user is refused when the company's `max_users` capacity is full.
- A managed client's license cannot begin before or end after its consulting firm's license.
- Reducing a consulting firm's dates cannot invalidate an existing managed-client license.
- A consulting firm cannot create more clients than `max_client_companies`.

System Owners remain able to enter the platform portal when a company is inaccessible so they can repair its state or license.

## 5. Managing users

### System Owner accounts

Use **System Owner users** in the platform sidebar. Accounts created there are global System Owners and are not company accounts. They can administer every company and consulting relationship.

### Consulting portal administrators

On a consulting firm's row, select **Portal users**. You can create an administrator, reset the password, activate/deactivate the account, and grant/remove consulting-portal access.

A consulting administrator cannot remove or deactivate its firm's final active portal administrator. A global System Owner may intentionally remove all portal access.

### Company users from the platform portal

On a standalone or managed-client row, select **Company users**. Users created there:

- Belong only to the selected company.
- Sign in through `/login` using that company's name.
- Count against that company's active-user limit.
- Can use any active system or custom role belonging to that company.
- Can have their role, state, and password changed.

### Company users from the main application

An authorized company administrator opens **Users & access** in the main navigation. It can create users, update access, suspend accounts, and reset passwords. Custom roles created for the company appear automatically in the role selector.

Passwords cannot be retrieved. They are stored only as bcrypt hashes; replace a forgotten password with a new one.

## 6. Roles and permissions

Company administrators open **Roles & permissions** in the main application. Consulting administrators may also manage their consulting firm's roles through the platform portal.

The default company roles are:

| Role | Typical purpose |
|---|---|
| Super administrator | Company administration without access to financial models |
| Administrator | Full model access, user administration, role administration, and model approval |
| Model manager | Model editing plus user administration; cannot approve/lock a model |
| Analyst (read-only) | Read-only model access |
| Board / outputs only | Output/report access without input access |

The permission matrix groups grants into these modules:

- `models`: view, edit, approve, and export.
- `users`: view and administer.
- `roles`: view and administer.
- `companies`: view and administer at the appropriate platform scope.
- `licenses`: administer license settings.
- `audit`: view sensitive activity.

To create a custom company role:

1. Open **Roles & permissions**.
2. Select **Create role**.
3. Enter a unique name and description.
4. Optionally duplicate an existing role.
5. Enable the required permissions in the matrix and save.
6. Open **Users & access** and assign the new role.

Custom permissions are loaded for every authenticated request and enforced by backend guards. Changing frontend markup cannot grant access. A role cannot be deleted while assigned to users; reassign those users first. System roles cannot be deleted or renamed.

## 7. Consulting security boundaries

The backend enforces all of these rules even if someone manually calls an API:

- A consulting administrator sees only its own consulting firm and direct managed clients.
- It cannot create standalone companies or other consulting firms.
- It cannot attach a client to another consulting firm.
- It cannot see or modify an unrelated company's users, roles, license, or branding.
- Client accounts do not grant access to the consulting firm's workspace.
- Consulting-firm accounts do not automatically grant access to client workspaces.
- A global System Owner can administer all companies but uses a separately stored platform identity.

## 8. Demo data

To seed example companies and capacity data:

```bash
npm run db:seed-platform-demo
```

Generated dummy users receive random unrecoverable passwords and cannot sign in. To create the optional RSM consulting login, set a password first:

```env
CONSULTING_DEMO_PASSWORD=replace-with-a-long-demo-password
```

Then run the demo seed again. The optional account is `consulting.admin@rsm-demo.local` in `RSM Advisory Demo`. Do not use demo credentials in production.

## 9. Installation and maintenance

```bash
npm install
npm run install:frontend
npm run db:install
npm run build
npm start
```

For an existing database:

```bash
npm run db:doctor
npm run db:migrate
```

The migration is additive and idempotent. It creates missing RBAC/platform structures, assigns existing users to their matching company roles, and restores missing default permission grants.

The in-place upgrade deliberately:

- Does not drop or truncate any table.
- Does not delete companies, users, models, financial data, passwords, logos, or custom roles.
- Keeps the legacy `users.role` value as a compatibility projection.
- Backfills a legacy role only when a user has no normalized `user_roles` assignment.
- Never adds a legacy role beside an administrator-selected custom role on later runs.
- Uses `INSERT IGNORE` for permissions and default roles so existing records and customizations are retained.
- Adds indexed, relational consulting-company references without converting company names into free text.

As with any production database change, take a database backup before deployment. Stop application writes during the short migration window, run `npm run db:migrate`, then run `npm run db:doctor`. A second migration run should report `0 change(s) applied`.

Recommended verification after changes:

```bash
npm run typecheck
npm test
npm run build
```

## 10. Troubleshooting

### Platform sign-in details are not recognised

- For a System Owner, leave Company blank.
- For a consulting administrator, enter the consulting firm's exact company name.
- Confirm the account is active and unlocked.
- Confirm the company is active and its license has not expired.
- Confirm consulting-portal access is enabled for a consulting administrator.
- Run `npm run db:seed-platform-admin` with new environment credentials to recover the initial System Owner.

### A company administrator cannot see Users or Roles

- Run `npm run db:migrate` to restore normalized role assignments and default grants.
- Confirm the user is assigned an active company role with `users.administer`, `roles.view`, or `roles.administer` as required.
- Sign out and sign back in after repairing an old account.

### A custom role is missing from the user dropdown

- Confirm the role belongs to the same company as the user.
- Confirm the role is active.
- Reload the screen after saving the role.
- Roles are never shared across unrelated companies.

### A user cannot be activated

Check the company's active-user count and `max_users` license capacity. Increase the licensed capacity or deactivate an unused account.

### A managed-client license cannot be saved

Confirm that its start/end dates fall entirely within the consulting firm's license and that the parent consulting account is valid.

### Database reports missing columns or tables

Run `npm run db:doctor`, followed by `npm run db:migrate`. Do not manually drop RBAC or licensing tables.

## 11. Important implementation locations

| Concern | Location |
|---|---|
| Platform routes and scope enforcement | `app/routes/platform.js` |
| Company administration and company-role APIs | `app/routes/admin.js` |
| Main authentication and company loading | `app/middleware/auth.js`, `app/routes/auth.js` |
| Platform/RBAC data access | `app/db/platform-repository.js` |
| Licensing calculations | `app/lib/licensing.js` |
| Additive migration | `scripts/migrate.js` |
| Initial System Owner seed | `scripts/seed-platform-admin.js` |
| Demo portfolio seed | `scripts/seed-platform-demo.js` |
| Platform UI | `frontend/src/pages/platform/` |
| Company user and role UI | `frontend/src/pages/admin/UsersPage.tsx`, `frontend/src/pages/admin/RolesPage.tsx` |
