One person could not work for two businesses, and signup and staff
creation told anyone whether an email or phone was registered anywhere
on the platform.
- User email and phone are now unique per business: indexes on
(businessId, email) and (businessId, phoneNumber). Duplicate checks in
signup and branch-manager creation are scoped to the business, so they
no longer reveal other businesses' users.
- Login finds the email in every business and checks the password
against each account. One match signs straight in; several return 300
with the businesses to choose from, and the login page shows a picker.
A wrong password returns the same 401 as before and reveals nothing;
failures count against each candidate account, and a correct password
only resets the accounts it opens.
- Platform-operator access now also needs a platformAdmin flag on the
account. With per-business emails, an email match alone would have let
any owner create a staff account with the operator's email and open the
cross-tenant console. The flag is only set by the seed and the
migration; removing the email from PLATFORM_ADMIN_EMAILS still revokes.
- npm run migrate:identity flags today's operators (while each listed
email still matches one account) and syncs the User indexes, dropping
the old unique email_1 and phoneNumber_1. Checked against a database in
the old shape; safe to re-run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The initial test report (run before the pilot-readiness changes) raised
seven findings and a retest plan. This closes the ones still open.
- F-01: a business on its free trial may run 2 active branches whatever
its tier, so an owner can try transfers and per-branch stock. Only
active branches count towards any limit.
- F-06: owners can rename branches and deactivate/reactivate them from
the Branches page. A branch can only be deactivated once it holds no
stock and no active staff; its history stays in every report, and it
leaves every picker.
- F-04: the Products page lists deactivated products under a toggle with
Reactivate. Deactivating warns about stock still on hand, which stays
on the Stock page so it can be transferred or counted out.
- F-05: products carry a unit (L, ml, kg, g, pcs, tray, pack) instead of
everything being litres.
- CAT-12: product prices must be above zero and names are unique per
business, ignoring case.
- F-03: a reversed report period is refused by the page and the API, and
the page labels which period the cards show. Report dates are Nairobi
business days.
- F-07: cost of goods sold is units sold x average buying price. Stock
bought in the period is reported separately, with a cash surplus line,
so unsold stock no longer shows as a loss.
- STA-04: staff and new branch managers can be invited with a one-time,
7-day link; the person sets their own password. Managers can issue a
new link for their own cashiers.
- OFF-02 / POS-02: the till shows each product's stock and deducts every
sale immediately, online or offline; it warns before selling more than
the recorded stock, and has a Clear sale button.
- npm run backfill:stock turns purchases recorded before the stock ledger
into stock, so existing tenants (and the report's ZERRO fixtures) start
from what they bought.
tests/retest-plan.test.ts runs the report's completion and retest plan
and checks every balance and total it predicts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>