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

11 KiB

Project repairs and multi-club setup

Implemented and tested October 18, 2026. Existing authentication work is described in 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:

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.

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.