Skip to content

Test Plan: Member-Created Events

Generated by /plan-eng-review on 2026-06-05 Branch: master Repo: rakletadmin/rakletv3 Source design doc: member-created-events-design.md

Affected Pages/Routes

Member portal (App2 area, gercek.raklet.net)

  • /Events/Submit — member submission form (new)
  • /Events/MySubmissions — member's own submissions list (new)
  • /Events/Submissions/{id}/Edit — edit pending OR approved-with-draft submission (new)

Admin panel (Raklet.Backend, gercek.raklet.org)

  • Existing events list — now shows pending member submissions with badge (no new tab)
  • Existing event detail page — now has approval panel embedded inline when SubmissionStatus=Pending

APIs touched

  • POST /api/app/events/submissions — member submission endpoint (new)
  • PATCH /api/app/events/submissions/{id} — member edit (new)
  • GET /api/app/events/submissions/mine — member's submissions list (new)
  • POST /api/v2/events/{id}/approve — admin approval (new)
  • POST /api/v2/events/{id}/reject — admin rejection (new)
  • All existing event-read endpoints (/api/app/events, /api/v2/events, public Explore, Zapier, etc.) — refactored to use EventQueryFilters.VisibleTo() helper

Key Interactions to Verify

Member submission flow (browse-tests required — happy path + double-click idempotency)

  • Fill all required fields → submit → land on My Submissions with new pending row
  • Submit twice rapidly → only one event created
  • Submit with PaymentAccountId from another org → 403
  • Submit without cover image → succeeds
  • Navigate away mid-form → form discards cleanly (no orphan blobs)

Member edit flow (browse-tests for explicit-submit pattern)

  • Open approved event → edit fields → Save → public event unchanged
  • Save multiple times → all changes accumulate in PendingDraft
  • Click Submit-for-approval → SubmissionStatus flips to Pending; public still shows old version
  • Admin approves → PendingDraft merges into top-level fields atomically
  • Member edits Pending event while admin is mid-approval → second-writer-wins OR Concurrency exception (verify expected behavior)

Admin approval (browse-tests — load admin events list → click pending → approve)

  • Pending events appear in existing events list with badge
  • Approval panel embedded in detail page with bank-account dropdown
  • Click Approve with default PaymentAccountId → SubmissionStatus=Approved, IsPublished=true
  • Click Approve with override PaymentAccountId → routing reflects override
  • Click Reject with reason → SubmissionStatus=Rejected, member receives email with reason
  • Approval is atomic — partial-success state never observable

Notifications

  • Submission created → admin bell counter increments real-time
  • Daily digest fires at scheduled time with N pending events for opted-in admins
  • Opted-out admin (via ManagerEmailSettings.PendingEventSubmissionEmails=false) receives nothing
  • Empty queue day → no email sent
  • 3-day SLA reminder fires for events still Pending
  • 7-day owner escalation fires for events Pending too long
  • Org with zero admins → escalation logs warning, no crash

Reminders

  • Approved event with no explicit reminder → 24h-before reminder fires (hardcoded default)
  • Admin sets per-event explicit reminders → those override the default

Edge Cases

Filter helper (EventQueryFilters.VisibleTo())

  • Member context → only IsPublished=true AND SubmissionStatus=Approved
  • Admin context (with Manage Events permission on this org) → all events in org including pending and rejected
  • Public/anonymous context → same as Member
  • Null caller context → safest filter (Public)
  • Admin context for ANOTHER org → only public events of that org (no cross-org pending leak)

Data model edge cases

  • EventDoc with PendingDraft=null → unchanged behavior for all read paths
  • EventDoc with PendingDraft + IsPublished=true → public reads see top-level fields only; never PendingDraft
  • EventDoc with SubmissionStatus=Rejected → no public read paths return it
  • Approving an event whose PendingDraft has invalid ticket prices (e.g., negative) → reject with validation error before write

Background jobs

  • Daily digest job — idempotent on retry (no duplicate emails)
  • Daily digest job — partial admin failure (some sends fail) → log + continue, don't fail entire job
  • SLA escalation job missed for 25h → alert fires (observability requirement)
  • SLA escalation backfills missed days on startup after outage

Member portal

  • Member without auth tries /Events/Submit → redirect to login
  • Member of Org A tries to edit Org B's pending event → 403
  • Submission form max-length validation matches admin form (reused DTO)
  • Cover image upload partial-failure → orphan blob cleanup runs within 24h
  • Member with read-only role (if applicable) can't submit — verify auth gates

Critical Paths (must work end-to-end)

  1. Hiking-leader happy path: Member opens portal → submission form loads in <2s → fills form → submits → sees Pending status immediately → admin sees pending event in events list within 10s → admin approves → member receives approval email within 60s → event appears in public event listing.

  2. Admin daily-digest flow: 5 events submitted across a day → next morning admin receives one email listing all 5 → admin clicks first event → lands in event detail with approval panel → approves → returns to email/list → approves second → digest correctly excludes already-approved events on subsequent days.

  3. Rejection feedback loop: Admin rejects with reason "ticket prices too high" → member receives email with reason → member edits pending event with new prices → Submit-for-approval → admin approves → published.

  4. Edit-after-approval draft pattern: Member edits approved event description → Save → public event still shows old description → Submit-for-approval → public still shows old description until admin approves → admin approves → public now shows new description.

  5. SLA escalation: Submit event → admin doesn't review → 3 days pass → admin gets reminder email → still no review → 7 days pass → org owner gets escalation email → submission still visible in queue (not auto-rejected, not auto-approved).

Regression Test Scope (IRON RULE — 24 callsites)

Per skill: the 24 EventDoc-touching callsites refactored to use EventQueryFilters.VisibleTo() ALL need regression tests proving filter behavior matches pre-refactor for legacy admin-created (SubmissionStatus=Approved AND IsPublished=true) events.

Integration tests preferred over Moq per feedback_no_test_only_di_seams.md. Hit a real EventDoc test fixture (or test Cosmos container) with a known set of legacy approved events + new test pending events + new test rejected events; assert each callsite returns the expected subset.

High-priority regression targets (member + public facing)

  • Raklet.Api/Controllers/App/Events/EventsController.cs:41 (member-facing read)
  • Application/Areas/Events/Controllers/HomeController.cs (public event detail page)
  • Raklet.Api/Controllers/Public/ExploreController.cs (public event listing)
  • Raklet.Api/Controllers/App/Zapier/ZapierEventsController.cs (third-party integration)
  • Raklet.Api/Controllers/V2/V2EventsController.cs:417 (admin list — visibility-aware)

Medium-priority (services + background work)

  • Services/EventOrgSummaryService.cs
  • Services/EmailServices/EventEmailService.cs
  • Services/EmailServices/EventEmailReminderInstanceSyncService.cs
  • Services/EmailServices/EventEmailReminderSchedulerService.cs
  • Services/Integrations/UseCases/Zoom/ParticipantJoinedWebhookInteractor.cs
  • Raklet.WebJobs.Secondary/Export/ExportFunctions.cs
  • Raklet.WebJobs.Secondary/Email/EmailFunctions.cs

Lower-priority (smoke test acceptable)

  • Remaining ~12 callsites surfaced at implementation time via full grep audit

Tooling

  • Unit tests: xUnit + integration test infrastructure already present (per Raklet.UnitTests/EventOrgSummaryServiceTests.cs)
  • Browse tests: browse-tests/payment-regression/ style — extend with events-submission/ suite covering member portal flows on .raklet.net
  • CI: PR-CI workflow already runs on every PR; browse-smoke dispatches against ci-runner pool

NOT in this test plan (deferred)

  • LLM eval suites — no LLM in v1 (AI submission deferred to v1.5)
  • Load / stress testing — defer until 30-day post-launch metrics inform whether scale concerns materialize
  • Accessibility / screen-reader audit — separate concern; cover in /plan-design-review