Repository source: docs/plans/archive/lobby_board_invite_link_step4_implementation_summary.md
Redeemable Board Invitations — Step 4: Implementation Summary
Stage 1 - Invitation lifecycle foundation
Changes:
Added canonical invitation records for issued, revoked, and redeemed events.
Added a ledger that rejects duplicate issuance, hash mismatches, foreign revocation, and repeated redemption.
Validated hash-only canonical data and optional internal destinations.
Verification:
php tests/run.php CanonicalRecordParsersTestpassed.
Notes:
Invitation records intentionally contain only a SHA-256 verification hash; bearer secrets are not represented in canonical records.
Stage 2 - Site-wide invitation issuance and destination selection
Changes:
Added signed, approved-session invitation issuance and issuer-only revocation APIs.
Added a shared Invite navigation action that opens a generator from any board page with that page as its optional target.
Added a generated-link flow using a browser-only fragment secret and Activity labels for issue/revoke events containing the verification hash only.
Verification:
PHP lint passed for the application, writer, and read-model updates.
node --check public/assets/invite_issuance.jsandnode --check public/assets/invite_navigation.jspassed.php tests/run.php CanonicalRecordParsersTest ReadModelBuilderTimingTest LocalAppSmokeTest::testPrivateLobbyOnlyExposesLobbyAccountAndAuthenticationSurfacespassed.
Notes:
External and malformed targets are rejected before a signed invitation is created; the final target access check remains part of redemption.
Stage 3 - Lobby identity creation and redemption
Changes:
Added a Lobby redemption surface that reads the bearer secret only from a URL fragment and removes it after successful use.
Added signed redemption preparation/finalization bound to the recipient browser identity, with single-use, expiry, revocation, and hash checks under the write lock.
Kept redemption available to Lobby users while requiring a published browser-key identity before it can proceed.
Verification:
PHP lint passed for application, writer, and invitation ledger updates.
node --check public/assets/invite_redemption.jspassed.php tests/run.php CanonicalRecordParsersTest LocalAppSmokeTest::testPrivateLobbyOnlyExposesLobbyAccountAndAuthenticationSurfacespassed.
Notes:
The recipient is intentionally prompted to set up a fresh browser key; no key-restore path was added to the invitation surface.
Stage 4 - Approval derivation and session transition
Changes:
Extended both full and incremental approval derivation to recognize a valid issued invitation followed by its signed redemption as an inviter-attributable approval.
Added a redeemed Activity event linked to the same verification hash.
Preserved the validated optional destination through redemption and use it only after browser-key authentication succeeds.
Verification:
PHP lint passed for both read-model implementations.
node --check public/assets/private_site_auth.jsandnode --check public/assets/invite_redemption.jspassed.php tests/run.php ReadModelBuilderTimingTest PrivateSiteAuthTest LocalAppSmokeTest::testApprovedPrivateSessionCanViewOwnProfileAndBoardpassed.
Notes:
Invalid, expired, revoked, or already redeemed invitations cannot become approval candidates.
Stage 5 - Security regression coverage and operator guidance
Changes:
Added private Lobby route-matrix coverage for the redemption preparation endpoint.
Documented invite generation, seven-day expiry, revocation, Activity hash visibility, disposable keys, target routing, and secret-leak response in the production runbook.
Made invitation redemption start the standard browser key-generation flow when the recipient has no key, and made generated links select-on-focus with an explicit Copy action.
Shortened new bearer secrets to 32-character hexadecimal values (128 bits), while retaining redemption compatibility for previously issued base64url and 256-bit hexadecimal links.
Verification:
php tests/run.php LocalAppSmokeTest::testPrivateLobbyOnlyExposesLobbyAccountAndAuthenticationSurfaces CanonicalRecordParsersTest ReadModelBuilderTimingTest PrivateSiteAuthTestpassed.php tests/run.php BrowserSigningNormalizationTestpassed after hardening browser initializers for the minimal DOM environment used by the regression suite.php tests/run.phppassed.php tests/run.php BrowserSigningNormalizationTest LocalAppSmokeTest::testApplicationRendersCoreRoutes PrivateSiteAuthTestpassed after the invitation interaction refinement.git diff --checkpassed for feature changes; the pre-existingtodo.txttrailing-blank-line warning remains unrelated.
Notes:
The bearer secret is intentionally confined to a browser fragment and the private redemption request; the canonical repository and Activity expose only its verification hash.