Test Plan: Guest Portal
User/Member whose account has no ACTIVE membership (created via public event registration, see findOrCreateGuestMember in auth-service/src/services/guest/ and auth-service/src/handlers/publicEventsHandlers.ts). Guest data flows through the same EventRegistration model as members (registrationType: GUEST), the same admin guest roster endpoint (GET /api/admin/guests, handlers/adminGuestListHandler.ts), and the same event-registrations-roster endpoint (GET /api/events/:eventId/registrations/guests, handlers/eventRegistrationsHandler.ts) used for member attendee lists. See the green banner below for everything new on stage since Jun 19. Trust this page + the code over the older TC-GUEST-002 page where they disagree — e.g. TC-GUEST-002 predates the current admin nav path (Members → Guests) and the server-side CSV export.
- Guest profile card shows "Guest" type (#368, Jun 19 release):
frontend/pwa-app/src/components/home/profile/ProfileCard.tsxrenders the TYPE row asprofile.memberType || (isGuest ? "Guest" : "Member")— a guest whose account has no explicitmemberTypenow shows "Guest", not a blank cell or "Member".GuestHomePage.tsxpassesisGuest={true}into the card. See TC-GUEST-003. - Guest CSV export moved server-side + formula-injection guard (#340, Jun 19 release): the admin guest-roster export now downloads from
GET /api/admin/guests/export.csv(exportAdminGuestsCsvHandler) instead of being assembled client-side inAdminGuestsPage.tsx. Every cell is routed through the sharedcsvQuote/sanitizeCsvCell(auth-service/src/utils/csvSanitize.ts) — a cell whose value starts with=,+,-, or@is neutralized with a leading'before it reaches the CSV, and the whole cell is RFC-4180 quoted. See TC-GUEST-003. - PII redaction on guest-registration responses (#486, security, Jun 29 release):
GET /api/events/:eventId/registrations/guestsnow computesshowSensitive = isPrivileged || isOwnRegistrationper row — a non-privileged viewer (noEVENTS:VIEW:registrations) of another attendee's or a guest's registration does NOT receiveinvitedBy.email,attendeeEmail/memberEmail/guestEmail,checkInCode,displayTicketCode, or theinvoicesub-object (all setundefined/null). Privileged roles (ADMIN, EVENT_MANAGER, etc.) and the registration's own owner still see the full row. Cross-linked with the RBAC section's TC-RBAC-004. See TC-GUEST-003.
1. Scope
A "guest" is a User/Member record created automatically the first time someone with no MemberVu account registers for a public event (findOrCreateGuestMember, auth-service/src/services/guest/guestMemberService.ts, invoked from publicEventsHandlers.ts). Guests get portal access (password-setup email, login, a reduced dashboard) but are NOT members — no membership dues, no member directory, no members-only event pricing — until an admin/membership-chair converts them via the membership application flow. This section covers: guest login + dashboard, the guest profile "Guest" type label, admin guest-roster listing/search/export, and the PII redaction on the guest-registration roster response. Membership conversion mechanics (guest → member) live in TC-GUEST-002; new data-handling/security surfaces from this pass live in TC-GUEST-003.
2. Where it lives
| Area | Route / how to reach |
|---|---|
| Guest login | https://stg-rcme.membervu.com/login — same login page as members; the JWT/role determines the reduced view. |
| Guest dashboard | GuestHomePage.tsx (frontend/pwa-app/src/pages/GuestHomePage.tsx) — renders ProfileCard with isGuest={true}, GuestWelcomeCard, GuestRegistrationsCard. |
| Guest "My Registrations" | MyGuestsTab.tsx under Account — a member's own invited-guests tab, distinct from the guest's own dashboard. |
| Admin guest roster | /admin/guests — AdminGuestsPage.tsx. Sidebar under Members → Guests. Search/filter by event, status, name/email. |
| Admin guest export | "Export CSV" button on AdminGuestsPage.tsx → exportAdminGuestsCSV() API client call → GET /api/admin/guests/export.csv. |
| Event attendee roster (member/guest view) | GET /api/events/:eventId/registrations/guests — used both by the event detail page's attendee list and by member self-service views. |
| Prospect management | Members → Prospects — separate from guests; a prospect has no account yet. |
3. Key API endpoints
| Action | Endpoint | Guard |
|---|---|---|
| Admin: list all guests (paginated) | GET /api/admin/guests | EVENTS:VIEW:registrations |
| Admin: export guest roster CSV | GET /api/admin/guests/export.csv | EVENTS:VIEW:registrations |
| Event guest roster (member/guest view) | GET /api/events/:eventId/registrations/guests | requireLoggedInAuth + per-row PII redaction (#486) |
| Add a guest to own event registration | POST /api/events/:eventId/guests | requireMemberId() |
| Cancel own added guest | DELETE /api/events/:eventId/guests/:registrationId | requireMemberId() |
| Member's own invited-guests list | GET /api/members/me/invited-guests | requireMemberId()-scoped auth |
| Public event registration (creates guest account) | POST /api/public/:tenantSlug/events/:eventId/register (see publicEventsHandlers.ts) | public / publicActionLimiter |
| GDPR delete of a cancelled guest registration | DELETE /api/admin/registrations/:registrationId | EVENTS:EDIT:registrations |
4. Test data (RCME seed)
- Seeded guest:
guest@demo.membervu.com/Guest123!(Guest — Roberto Mendoza in the older guide's naming). - Guests are stored as
EventRegistrationrows withregistrationType: GUEST— a guest has noMember.membershipTypeIdand noACTIVEmembership status. - Payment gateway is INERT on staging (Paynamics) — a guest's paid-event invoice creates
Invoice/Paymentrecords only, never a live charge.
5. Test Cases
| TC | Topic | Detailed |
|---|---|---|
| TC-GUEST-002 | Guest Experience & Conversion | detailed |
| TC-GUEST-003 | 🆕 Guest Experience & Data Handling (#368, #340, #486) | detailed |