generated from jric11/baseProject
169 lines
9.8 KiB
Markdown
169 lines
9.8 KiB
Markdown
# Club tenancy and account access
|
||
|
||
Implemented for the requested model. On October 20, 2026, the development
|
||
database was backed up and migrated, and `james.richie@onesourceits.com` was
|
||
promoted to **Super System Administrator**. Its existing password was preserved;
|
||
old sessions were revoked. See the
|
||
[development migration report](TENANT-MIGRATION-2026-10-20.md) for backup,
|
||
restoration and live verification results.
|
||
|
||
## Access model
|
||
|
||
| Capability | Super System Administrator | Club Administrator | User/member |
|
||
| --- | --- | --- | --- |
|
||
| View clubs | All | Assigned clubs | Active joined clubs |
|
||
| View member records | All | All members of managed clubs | Own membership only |
|
||
| Invite members | Any club | Managed clubs | No |
|
||
| Appoint club administrators | Yes | No | No |
|
||
| Create a new club | Yes | No | No |
|
||
| Edit/archive/reactivate club | Any club | Managed clubs | No |
|
||
| Seasons, dues, payments, corrections/reversals | Any club | Managed clubs | Read own dues/history only |
|
||
| Export roster/financial data | Any club | Managed clubs | No |
|
||
| Tickets | All clubs | All tickets in managed clubs | Submit/read/reply to own tickets |
|
||
| Global accounts, credentials, notes, settings, journal | Yes | No | No |
|
||
|
||
An administrator assigned to two clubs can manage both. An administrator in one
|
||
club who is an ordinary member of another gets only member access in that other
|
||
club. Administrators sharing a club see the same membership and invitation data,
|
||
regardless of who issued the invitation. An account can belong to several clubs;
|
||
deactivating membership in one club leaves its global account and other club
|
||
memberships intact.
|
||
|
||
Club administration is stored on `club_memberships.membership_role`, not inferred
|
||
from the old global `Administrator` or `System Administrator` label. Those old
|
||
labels do not confer cross-club access. The exact global
|
||
`Super System Administrator` role grants platform access. Only a current Super
|
||
System Administrator can assign global privileges or appoint club administrators.
|
||
The last active Super System Administrator and the last active administrator
|
||
membership in a club cannot be disabled/demoted through their respective controls.
|
||
|
||
Members get club name/seasons and their own membership, dues, payment and
|
||
correction history. Other members' contact information and private tickets are
|
||
not shown to them. Site alerts, dropdowns, popovers and account notes remain
|
||
platform-wide features, editable only by the Super System Administrator; they
|
||
are not private club content editors.
|
||
|
||
## Invitations
|
||
|
||
Club administrators use **Invite to this club** within their club workspace,
|
||
instead of the global Users directory or a username/email lookup of existing
|
||
accounts. This prevents searching another tenant's accounts or changing shared
|
||
login credentials. Your Super System Administrator retains global user controls
|
||
and can directly assign an existing verified account when provisioning a club.
|
||
|
||
An invitation records the club, submitted email, inviter, role and seven-day
|
||
expiration. It does not create an account, reset a password, or grant immediate
|
||
access. The recipient signs up or signs in using that email, verifies mailbox
|
||
ownership using the existing verification/reset process, opens **Invitations**,
|
||
and explicitly accepts. A verified, signed-in matching email is required; an
|
||
invitation ID alone is not a bearer credential. Consequently an invitation URL
|
||
does not need to contain a secret token.
|
||
|
||
Invitations cannot be accepted by another account, after expiry/revocation, or
|
||
after the inviter loses authority. Acceptance and revocation serialize on the
|
||
club record. Repeated acceptance does not duplicate membership. Only the Super
|
||
System Administrator can issue administrator invitations. Deactivating an
|
||
existing membership revokes its outstanding invitations for that club. Sending
|
||
again requires a one-minute wait; per-actor/club limits also apply.
|
||
|
||
Delivery uses the configured trusted HTTPS `ApplicationUrl`; the email explains
|
||
signup, verification and acceptance. Failed delivery leaves a visible warning
|
||
and a pending invitation that the recipient can find after signing in. An
|
||
administrator can retry sending to the same email after a minute. Development
|
||
email delivery is not claimed to work by these tests.
|
||
|
||
## Tickets
|
||
|
||
Members submit a subject and message from **Tickets** or **My tickets** inside
|
||
their club. Only the author, assigned club administrators and the Super System
|
||
Administrator can see that ticket or its messages. Members may reply to open
|
||
tickets; administrators can reply, close and reopen them. Archived clubs keep
|
||
their history but do not accept new tickets/replies. Subject/message limits are
|
||
200/8,000 Unicode characters. Text is escaped on display, requests require CSRF
|
||
protection, and submission/reply rates are limited.
|
||
|
||
Tickets and replies commit with mandatory audit records. Successful submissions
|
||
redirect to a read page, so refreshing does not resubmit the form. Ticket lists use 25-item pages with subject search; count queries and every page
|
||
retain the same club/author restrictions. Older authorized tickets are discoverable
|
||
through page navigation or search. This feature supports text discussions,
|
||
not attachments or email notifications.
|
||
|
||
## Migration and rollout
|
||
|
||
Use a protected maintenance window for the coordinated code/schema change:
|
||
|
||
1. Back up the target database and retain the matching application release.
|
||
2. Ensure migrations 001–003 are already applied and the designated existing
|
||
login `james.richie@onesourceits.com` is active. This migration does not create
|
||
an owner account or guess a replacement if that email is missing.
|
||
3. With migration credentials, set `HCR_SUPER_ADMIN_EMAIL` to
|
||
`james.richie@onesourceits.com` and run `php bin/migrate-tenants.php`.
|
||
Remove that environment variable afterward; it is a one-time explicit
|
||
bootstrap selection, not a runtime setting.
|
||
4. Deploy this version with all new files and the updated runtime grants in
|
||
`deploy/runtime-grants.sql.example`. Run `bin/check-health.php`.
|
||
5. Sign in again as the designated owner. Promotion revokes existing sessions and
|
||
outstanding reset/verification tokens. Club memberships are **not** promoted
|
||
automatically: open each club, assign its intended existing verified accounts
|
||
if needed, and set their **Club role** to **Administrator**. Alternatively,
|
||
invite an administrator and have them accept.
|
||
6. Verify each club administrator/member with separate sessions, then reopen
|
||
service. Test production inbox delivery separately.
|
||
|
||
The migration adds `membership_role` and three InnoDB tables:
|
||
`club_invitations`, `club_tickets`, `club_ticket_messages`. Existing memberships
|
||
default to `member`; clubs without an explicit administrator remain visible and
|
||
manageable by the Super System Administrator. No historical financial records or
|
||
memberships are removed. Club display names no longer need to be globally unique;
|
||
club IDs remain the tenant boundary. Rerunning the migration is safe and does not
|
||
re-promote an already promoted account or repeatedly revoke sessions.
|
||
|
||
Do not deploy the new application by itself against the old schema: health
|
||
checks will reject missing tenancy tables. If rollback is required after using
|
||
the new roles, restore the matching backed-up database and release together;
|
||
older code does not understand the new Super System Administrator role.
|
||
|
||
## Implementation and verification
|
||
|
||
- `TenantAccess.php` centralizes current database-backed platform/club permissions.
|
||
`Base.php` restricts global routes and passes the navigation capability to XSL.
|
||
- `RosterService.php`, `LedgerService.php` and `RosterReports.php` enforce the
|
||
selected club's access for reads, writes and downloads. Membership changes and
|
||
permission checks participate in club transactions. Account services enforce
|
||
Super System Administrator access and protect the final platform administrator.
|
||
- `ClubInvitations.php`, `ClubTickets.php` and the new Roster screens implement
|
||
the invitation and ticket flows. `xsl/content.xsl` shows scoped navigation.
|
||
- `migrations/004_tenants.sql`, `bin/migrate-tenants.php`, runtime grants, release
|
||
packaging, role options and application cache version (`1.02`) were updated.
|
||
- Added separate migration, service, HTTP and browser tenancy suites; expanded
|
||
concurrency coverage for invitation acceptance and the last club administrator.
|
||
Test fixtures use generated scratch databases, capture invitation mail or
|
||
force SMTP to a closed loopback port, and promote only a test account.
|
||
|
||
Verification passed: **497 checks plus seven concurrency scenarios**, including
|
||
the complete prior regression suite and the final owner-assignment browser check.
|
||
|
||
| Suite | Passed checks |
|
||
| --- | ---: |
|
||
| Existing authentication, maintenance, security, ledger, browser, backup and release suites | 374 |
|
||
| Tenant migration | 8 |
|
||
| Tenant services | 32 |
|
||
| Tenant HTTP access and isolation | 75 |
|
||
| Tenant browser workflows, including owner assignment | 8 |
|
||
|
||
Source checks passed for 49 PHP files, 56 application JavaScript files and 39 XSL
|
||
stylesheets. Concurrency scenarios cover defaults, payment limits, financial
|
||
retries, the final platform administrator, invitation acceptance and the final
|
||
club administrator. The disposable local test databases were removed and their
|
||
loopback server stopped. No development records, real recipients or live account
|
||
privileges were changed.
|
||
|
||
That regression run preceded the separately authorized development migration.
|
||
The subsequent migration and 61 development acceptance checks are documented in
|
||
the linked migration report; temporary verification data was removed afterward.
|
||
|
||
See [the tenant repair follow-up](TENANT-REPAIRS-2026-10-20.md) for the invitation
|
||
reactivation policy, bounded transaction retries and Unicode-aware ticket forms.
|
||
|
||
Mandatory administrator MFA and capacity controls require the [security/capacity migration and deployment steps](SECURITY-CAPACITY-2026-10-20.md). Apply them before running this release.
|