Files
huntingclubroster/PROJECT-REPAIRS.md
T
jric11 1e63076123
Security and workflow regressions / regression (push) Has been cancelled
Chat's updates for security, db and workflow
2026-10-20 06:45:30 -04:00

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.