# Account, tenant, and roles

ActivityLog has four nested concepts. Get these straight on day one and the rest of the product makes sense.

```
Account (your sign-up identity)
  └── Tenant (your billing + isolation boundary)
        └── System (one source of activity)
              └── Token (the credential that source uses)
```

A single account belongs to one or more tenants. A tenant owns systems, users, and tokens. **Tenant isolation is hard** — cross-tenant queries are impossible from a user JWT; the API will return 404 even if you happen to know an ID from another tenant.

## Sign up

Visit [`https://activitylog.com/portal/`](https://activitylog.com/portal/) and click **Sign up**. After verifying your email you land on the Dashboard with a brand-new tenant.

You don't pick a tier at sign-up — every new tenant starts on **Free**. Upgrade later from **Settings → Billing** (Pro/Enterprise contact pricing — see [`../Pricing.md`](../Pricing.md)).

![Sign-up confirmation showing tenant created](screenshots/portal-signup-confirmation.png)

## The tenant model

A **tenant** is the unit of:

- **Isolation** — no user in tenant A can query, see, or otherwise touch data in tenant B.
- **Billing** — usage and tier limits are per-tenant.
- **Quota** — system count, user count, retention, throughput all apply per-tenant.

| Capability | Free | Pro | Enterprise |
|---|---|---|---|
| Tenants per account | 1 | 1 | unlimited |
| Users per tenant | 3 | 25 | unlimited |
| Systems per tenant | 3 | 100 | unlimited |
| Tokens per system | 2 | 50 | unlimited |
| Retention default | 7 days | 90 days | configurable |
| Body size cap (inline) | 16 KB | 256 KB | per contract |

Source: [`../Pricing.md`](../Pricing.md). The numbers there are the source of truth — this table is a snapshot.

### Multiple tenants (Enterprise only)

If your account is on the Enterprise tier you can hold multiple tenants under one login (think MSP or agency model). Switch between them from the top-right tenant picker.

![Tenant picker dropdown](screenshots/portal-tenant-picker.png)

Free and Pro accounts have exactly one tenant. Adding a second requires an Enterprise contract.

## Roles inside a tenant

There are three role bits on each user inside a tenant:

| Role | Can | Typical assignment |
|---|---|---|
| **owner** | Everything below + invite/remove owners, change billing tier, delete tenant | Founder / primary operator |
| **admin** | Manage systems, tokens, members; mint/revoke; change retention; invite users | Engineering lead, ops |
| **member** | Read messages, view dashboards, run queries | Developers, support staff |

A user can hold multiple roles. The sign-up creator is auto-assigned **owner**.

> "admin" here is the **tenant admin** role. There's a separate Fyin-staff "platform admin" role used only by the operator portal — out of scope for this guide. See [`80-admin-portal.md`](./80-admin-portal.md).

### Changing a user's role

**Team → click the user → Edit role**. The change takes effect on their next login (or token refresh, within an hour).

![Team page member detail with role chips](screenshots/portal-team-member-detail.png)

Removing the last owner is blocked — you must promote another member first.

## Systems vs streams

A **system** is your source of activity. Examples:
- `my-backend` — your ASP.NET app
- `iphone-app` — your customer-facing iOS app
- `nightly-jobs` — your scheduled tasks runner

A **stream** is a logical channel inside a single system, set per-message via the `stream` field on POST. Examples within one system:
- `stream: "events"` — business events
- `stream: "audit"` — security/audit events
- `stream: "errors"` — exceptions

You don't pre-create streams; they're free-form per message. New streams just appear when their first message lands.

> **Convention tip:** many users encode an entity hierarchy in `stream` using `stream={entityType}:{entityId}`. For example `stream: "ticket:ACLOG-140906"` makes every ticket's activity individually filterable. See [`../Architecture.md`](../Architecture.md) § 11 for the full pattern.

## Account password and email

**Profile → Password** to change. We use Argon2id; minimum 12 characters.

**Profile → Email** to change. You'll re-verify the new address before the change takes effect; if you lose access to the old inbox use the password-reset flow on the sign-in page.

![Profile page](screenshots/portal-profile.png)

## What's next

| Goal | Doc |
|---|---|
| Mint your first system token | [`20-setup-system-tokens.md`](./20-setup-system-tokens.md) |
| Bring in a teammate | [`30-invites-and-team.md`](./30-invites-and-team.md) |
| Set up two-factor auth | [`40-totp-setup.md`](./40-totp-setup.md) |
| Wire your app | [`50-ingest-native.md`](./50-ingest-native.md) |

## Troubleshooting

**I see "Tenant not found" or 404 on every page.**
Your portal session is bound to a tenant that no longer exists (it was deleted, or you were removed). Sign out and back in to pick a tenant you have access to.

**The Invite button is greyed out.**
You're a `member` — only `admin` and `owner` can invite. Ask your tenant owner to promote you.

**"You have hit the user limit on the Free tier."**
Free is capped at 3 users per tenant. Either remove a user, or upgrade to Pro at **Settings → Billing**.
