# Multi-tenant security model

- Every business-owned table has a mandatory `business_id` foreign key and a supporting tenant index.
- Login resolves one user to one business. API tokens store only a hash and are joined back to that user on every request.
- `business_id` is never accepted from Android, browser JSON, query strings, imports or forms.
- Every object lookup includes both the object ID and the authenticated `business_id`.
- Import rows are assigned the authenticated business ID inside the transaction.
- Invoice email loads the canonical invoice using `WHERE id=? AND business_id=?`; another tenant receives `404`.
- Mail idempotency is unique within the authenticated business.
- React/Vite should call these JSON endpoints and must not connect directly to MySQL.
- Production should add request rate limits, daily mail quotas, audit events, backup monitoring and automated cross-tenant authorization tests.

## Required isolation tests

1. Tenant A token cannot list Tenant B customers, employees, suppliers or stock.
2. Tenant A token plus Tenant B invoice ID returns `404` and sends no mail.
3. A spreadsheet cannot include or override `business_id`.
4. Reusing an idempotency key in another tenant does not reveal the first tenant's job.
5. Disabled users and expired tokens cannot access any protected route.
