generated from jric11/baseProject
195 lines
11 KiB
Markdown
195 lines
11 KiB
Markdown
# Project repairs and multi-club setup
|
|
|
|
Implemented and tested October 18, 2026. Existing authentication work is described
|
|
in [AUTHENTICATION.md](AUTHENTICATION.md).
|
|
|
|
## Database rollout
|
|
|
|
The roster migration was applied to the development database on October 18, 2026,
|
|
after the implementation tests and a fresh, verified backup. The development
|
|
verification is recorded below. Existing accounts and passwords were preserved.
|
|
|
|
After backing up the target database, run from the project directory with the
|
|
application's database configuration and PHP runtime:
|
|
|
|
```text
|
|
php bin/migrate-roster.php
|
|
```
|
|
|
|
The migration adds five InnoDB tables: clubs, memberships, seasons, dues, and
|
|
payments. It preserves existing records, can be rerun, and uses foreign keys to
|
|
prevent orphan records and cross-club dues assignments. It does not rebuild the
|
|
database. The authentication migration remains a prerequisite for this version;
|
|
it was already applied to development during the earlier authentication work.
|
|
|
|
The existing backup was restored locally, its SHA-256 and all ten original table
|
|
counts were checked, then both migrations were rehearsed. Running the roster
|
|
migration twice preserved all ten original counts. The restored copy was removed.
|
|
On other installations, until the roster migration is applied, the home page
|
|
explains that setup is needed.
|
|
|
|
Use the PHP version and Composer requirements in AUTHENTICATION.md. Report tests
|
|
used the curl, zip, gd, fileinfo, mbstring, openssl, PDO MySQL, and XSL extensions.
|
|
Run Composer's platform requirements check with the web server's PHP configuration.
|
|
|
|
## Security and deletion safeguards
|
|
|
|
- Dropdown usage metadata no longer selects arbitrary PHP callbacks or SQL
|
|
identifiers. Only the supported no-reference rule is accepted; unsupported
|
|
legacy rules fail closed rather than exposing settings or allowing deletion.
|
|
- IDs and booleans are validated, and dropdown writes use bound parameters.
|
|
A dropdown must belong to the requested type and be active to become default.
|
|
Switching defaults is transactional and serialized by type. Deactivation clears
|
|
the default. Default dropdowns and types containing dropdowns cannot be deleted.
|
|
- Account deletion, disablement, and role changes protect the last active
|
|
administrator, including simultaneous requests. Administrators cannot delete
|
|
themselves; ordinary administrators cannot modify System Administrator accounts.
|
|
Accounts with notes or club memberships must be retained. Reset tokens are
|
|
removed transactionally when an otherwise unused account is deleted.
|
|
- Status saves validate fields and enforce at most one default; inactive defaults
|
|
and deletion of the current default are rejected. Removed dependencies on
|
|
nonexistent requests and workorders tables from usage checks.
|
|
- Notes validate type, text, target, and existing note on the server. Target user
|
|
locks coordinate note creation with account deletion. Queries are bound and
|
|
displayed note text is escaped.
|
|
- Routing allows only supported actions, with administrative access enforced on
|
|
maintenance and exports. Removed arbitrary helper dispatch and obsolete report
|
|
dispatch. Failures return meaningful HTTP statuses and escaped messages;
|
|
AJAX no longer treats an empty successful write as invalid JSON.
|
|
|
|
## Accounts, lists, navigation, and browser behavior
|
|
|
|
- Administrative account creation validates first and last names, username,
|
|
email, and role. It stores an unknown random hashed password and sends a setup
|
|
link. A mail failure reports that the account exists and offers a resend path;
|
|
retrying cannot silently duplicate the account. No temporary password is exposed.
|
|
- Repaired account summaries, notes, and login history without the missing
|
|
Subscriptions dependency. Corrected username lookup and invitation resend.
|
|
- Restored audit entries for successful login, reset requests, password resets,
|
|
and password changes; club saves, dues, and payments also write journal entries.
|
|
Audit write errors are logged without breaking authentication.
|
|
- Pagination now uses correct last-page offsets, stable ordering, bounded page
|
|
sizes, empty-list handling, and independent state per list. Fixed incorrect
|
|
per-page fields, added status page-size refresh, escaped search patterns, and
|
|
added last-name account search and display.
|
|
- Replaced dead permit, zoning, subscription, support-ticket, and payment links
|
|
with Clubs and dues, Help, and a working report catalog. Retired three legacy
|
|
permit report implementations and obsolete metrics dependencies.
|
|
- Converted synchronous browser requests to asynchronous requests and fixed their
|
|
callers. Save/confirmation controls wait for requests, errors appear visibly,
|
|
and failed deletion checks never open a confirmation dialog. Default-checkbox
|
|
failures restore the prior selection.
|
|
- Hidden form inputs are built as DOM text values; toast and error content use
|
|
text rendering. Cached form restoration excludes hidden routing fields, IDs,
|
|
CSRF tokens, and passwords. Fixed ZIP lookup routing, logout request handling,
|
|
tooltip initialization, and jQuery callback compatibility.
|
|
|
|
## Multi-club roster features
|
|
|
|
- Site administrators create, rename, archive, and reactivate multiple clubs.
|
|
They assign existing accounts to separate club memberships, maintain membership
|
|
status and joined dates, and add dated seasons.
|
|
- Ordinary members see active clubs to which they have active membership, their
|
|
club's active contact roster, and only their own dues. Changing a URL or form ID
|
|
cannot grant access to another club. Membership changes take effect in existing
|
|
sessions. Signup alone grants no club membership.
|
|
- Administrators record season dues and received payments in a **manual USD
|
|
ledger**. Amounts use integer cents, reject fractional cents and negative values,
|
|
and payments cannot exceed the remaining balance. Repeated payment submissions
|
|
use an idempotency key to avoid duplicate entries. Dates and club relationships
|
|
are checked on the server.
|
|
- Archiving retains membership and financial history and prevents further writes
|
|
until reactivation. History is not exposed through destructive delete controls.
|
|
- Administrators can export a club roster as CSV, Excel, or PDF. Spreadsheet
|
|
formula injection is neutralized, Excel cells are explicit text, and PDF fields
|
|
are escaped.
|
|
|
|
This is a multi-club foundation managed by global site administrators. It does not
|
|
provide delegated club administrators, online payment processing, refunds, ledger
|
|
correction workflows, or automatic billing. These are separate features.
|
|
|
|
## Verification
|
|
|
|
All final suites passed against generated disposable local databases:
|
|
|
|
| Suite | Result |
|
|
| --- | --- |
|
|
| Authentication service and templates | 49 checks |
|
|
| Authentication HTTP routes | 27 checks |
|
|
| Maintenance validation and pagination units | 52 checks |
|
|
| Project HTTP, access boundaries, ledger, exports, and paging | 88 checks |
|
|
| Headless Chrome workflows | 15 checks |
|
|
| Concurrent default and administrator updates | 2 scenarios |
|
|
|
|
Total: **231 checks plus 2 concurrency scenarios**. Browser tests verified account
|
|
creation, visible invitation failure, account summary, blocked and successful
|
|
deletion, restricted dropdown metadata, club/membership/season creation, dues,
|
|
payments, and CSV download without unexpected JavaScript errors. Mail failure was
|
|
deliberately simulated; this round did not retest real delivery.
|
|
|
|
Source checks also passed for 24 application PHP classes, four CLI scripts, four
|
|
PHP test scripts, main.php, 54 JavaScript files, and 39 compiled XSL stylesheets.
|
|
All disposable databases were cleaned up and the isolated database server stopped.
|
|
|
|
Tests require an explicitly configured isolated MySQL/MariaDB server through
|
|
`HCR_TEST_DSN`, `HCR_TEST_USER`, and `HCR_TEST_PASSWORD`. HTTP tests additionally
|
|
require matching `HCR_DB_HOST`, `HCR_DB_PORT`, `HCR_DB_USER`, and `HCR_DB_PASSWORD`.
|
|
`PHP_TEST_COMMAND` accepts a JSON argument array for the test PHP runtime.
|
|
`NODE_TEST_COMMAND` selects Node and `NODE_PATH` locates Playwright for browser
|
|
tests. Do not point these tests at the application database.
|
|
|
|
```text
|
|
php tests/auth_integration.php
|
|
php tests/maintenance_unit.php
|
|
python tests/auth_http.py
|
|
python tests/project_http.py
|
|
python tests/concurrency.py
|
|
python tests/browser_runner.py
|
|
```
|
|
|
|
These tests cover application behavior in isolation; deployment still needs the
|
|
new migration on any other target and validation with its actual PHP, HTTPS, and
|
|
mail configuration.
|
|
|
|
## Development database rollout and verification
|
|
|
|
At the user's request, the roster migration was applied to
|
|
`192.168.1.190/huntingclubroster` on October 18, 2026 at 8:23 p.m. Eastern.
|
|
The previously approved unencrypted database connection was used.
|
|
|
|
Before migration, a fresh complete SQL backup was saved at
|
|
`.tools/backups/20261018-202150/huntingclubroster.sql` (37,317 bytes). Its SHA-256 is
|
|
`f4458cce64404063d9760c2fe06f9779cf8904c0dc27d301541b24486382157a`.
|
|
The backup was restored on an isolated local server; the checksum and row counts
|
|
for all 12 original tables matched. All existing rows were fingerprinted before
|
|
and after migration and were unchanged. Five new roster tables are ready.
|
|
|
|
Then **54 checks passed against the development database**, through a local HTTP
|
|
application server using three temporary accounts, two temporary clubs, separate
|
|
memberships, three dues records, and received payments. The checks covered:
|
|
|
|
- Creating multiple clubs, seasons, and memberships, including one account in two
|
|
clubs and rejection of duplicate memberships and dues.
|
|
- Membership and season boundaries, member financial privacy, administrative
|
|
permissions, CSRF enforcement, and protection against account deletion.
|
|
- Exact cents, partial payments, correct balances, idempotent payment retries,
|
|
changed-key-payload rejection, overpayment rejection, and full settlement.
|
|
- Immediate access revocation for inactive membership or archived clubs, blocked
|
|
writes while archived, and successful reactivation with preserved ledger data.
|
|
- Valid CSV, Excel, and PDF downloads.
|
|
|
|
An initial verification-helper session setup error was corrected before the
|
|
successful run; its temporary records were also removed. This required no change
|
|
to application code.
|
|
|
|
All temporary accounts, club records, dues, payments, test audit entries, rate
|
|
limit records, and sessions were removed afterward. Every row across all 17
|
|
tables matched the pre-test fingerprint. Auto-increment sequences may have
|
|
advanced during testing. No existing passwords were changed and no emails or
|
|
online payment transactions were sent. These are manually recorded payments.
|
|
|
|
Private backup metadata, migration results, and the check-by-check verification
|
|
report are retained alongside the backup in `.tools/backups/20261018-202150/`.
|
|
That directory is ignored by Git and blocked by the development router. The local
|
|
restore copy was removed and the isolated local database server stopped.
|