ChatGPT's update to harden software and run db updates.

This commit is contained in:
2026-10-21 06:53:45 -04:00
parent 1e63076123
commit acc8cb70f5
171 changed files with 9325 additions and 404 deletions
+168
View File
@@ -0,0 +1,168 @@
# 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.