A synthesis of four review passes (Office Hours, CEO, Engineering, Design) plus two independent codex outside-voice runs. One critical state-machine bug caught at plan stage. Zero unresolved decisions. Ready for implementation.
Four review passes, two cross-model outside voices, zero unresolved decisions. Every cell in this grid was a real conversation, not a checkbox.
Today only admins create events. A growing share of customers (federations, hiking clubs, multi-chapter orgs, student-club platforms, volunteer orgs) have distributed event organizers who run their own events on behalf of the parent brand. Today's workflow loses members to Meetup.
For hiking-club-style customers specifically: members use Meetup in parallel with Raklet for member-organized events. We are not replacing nothing. We are replacing Meetup for this workflow.
Orgs where event organizing is naturally distributed. The admin is not being lazy. They cannot be the bottleneck. The org has 5, 20, 100 sub-leaders (chapter heads, club presidents, volunteer coordinators, location managers) who each run their own events on behalf of the parent brand.
800-member volunteer org with 50 hike leaders organizing their own events. Customer is in 2-week trial. Board recommendation in mid-July. Asked specifically about an "event manager role with limited access." Three use cases described: (1) Simple event scheduling for 50 hike leaders (currently using Meetup); (2) Paid outing management; (3) Lodge booking with approval workflow + fee collection.
Six YC-style demand and specificity questions. Each answer narrowed the design. Verbatim user input below; takeaways follow each.
OrganisationManagerSettingsDoc.ManagerEmailSettings per-manager opt-in scaffolding already exists, which moved "configurable notification recipients" from v1.5 to v1 (free).Three approaches sketched in Office Hours. User picked C. The other two stay as fallback options if scope ever needs to flex.
| Approach | Data model | Effort (human) | Risk | Decision |
|---|---|---|---|---|
| A · Minimal viable Status field on EventDoc; pending events as a tab in admin events list |
1 enum + 2 fields on existing EventDoc | ~4 weeks | Low | Fallback if timeline tightens |
| B · Textbook clean Separate EventSubmissionDoc mirroring ApplicationDoc; conversion on approval |
2 documents joined by SourceId | ~7-8 weeks | Medium (model drift over time) | Rejected |
| C · Status field + dedicated UI (chosen) | Same as A; refined to two-status model after codex pass #2 | ~5-6 weeks | Low-medium | SELECTED |
Approach B's model drift is a real long-term tax for an app that adds event fields regularly. Approach A's "tab in events list" UX is not the queue experience the hiking-club admin needs. C buys A's velocity and most of B's UX clarity. Backend in C is identical to A — fallback path exists if the timeline ever needs A's lower UI scope.
| Proposal | Why it was tempting | Effort (CC) | Decision |
|---|---|---|---|
| AI-assisted submission | The Meetup-killer moat. Hike leader types 2 sentences, AI fills the form. | ~3-5 days | v1.5 |
| Auto-approve trusted creators | Hiking-club customer literally asked for this ("event manager role with limited access"). | ~1-2 days | v1.5 |
| "Create another like this" | Weekly-hike pattern means leaders submit ~52 events/year. | ~30 min | v1.5 |
| Recurring events | Hiking-club's weekly recurring meetups would benefit. | ~3-5 days | v1.5 |
| Submission analytics dashboard | Without it, can't measure feature success in-product. | ~30 min | v1.5 |
| Tagged rejection reasons + Request Changes + marketing kit | Friction reduction for admin + growth surface for member. | ~1-2 days | v1.5 |
| Org-configurable default reminders (was pre-req) | Admins want it independently of this feature. | ~1 week | v1.5 |
| Capability | Implementation |
|---|---|
| Member submission form | New surface under Application/Areas/App2/ |
| Member "My Submissions" view | Status badges · designed empty state · mobile-first |
| Mandatory admin approval | Inline approval panel on existing admin event detail page (no new tab) |
| Edit-after-approval draft pattern | Save (draft) + Submit-for-approval — GitHub PR-draft model |
| Payment routing | Always org account; admin picks specific account at approval time |
| Real-time in-app notification | Existing SignalR fan-in to admin bell counter |
| Daily digest email | Reuses existing job-lease pattern; per-manager opt-in via existing scaffolding |
| SLA escalation | 3-day admin reminder + 7-day org-owner escalation |
| Hardcoded 24h reminder default | Per-event reminder until org-level defaults ship in v1.5 |
| Feature flag wraps entire flow | Rollback without code revert |
| Centralized visibility filter helpers | 24-callsite refactor + boundary audit (added by codex challenge) |
Codex read the design doc + CEO plan with no session context. 10 findings. Verbatim. Each tagged with how it was resolved.
EventDoc is faster, but the leak risk is being underpriced in an old multi-tenant codebase with many event query paths. Either use a separate submission model or make unpublished/pending exclusion enforced centrally below controllers. accepted — centralized filter helper + 24-callsite refactor + boundary auditLocked after codex pass #2 caught a state-machine conflict in the original single-status design. Public visibility depends only on PublishStatus; draft review state lives on a parallel DraftStatus axis. They never collide.
PublishStatus controls public visibility. DraftStatus controls admin queue. They never collide.Original single-status design used one SubmissionStatus enum for both purposes. When a member edited a live event → status flipped to Pending → visibility filter (Status=Approved) hid the event from public. Live events would disappear during member edits. Two-status model makes this structurally impossible.
Approach C: status fields on EventDoc with dedicated UI. Heavy reuse of existing Raklet patterns.
| Pattern | Source |
|---|---|
| Approval queue blueprint | ApplyController.cs:1946-1958 (membership applications) |
| Payment routing | EventDetailsEditViewModel.PaymentAccountId + OrganisationDto.DefaultPaymentAccountId |
| Per-manager email opt-in scaffolding | OrganisationManagerSettingsDoc.ManagerEmailSettings |
| Member portal area | Application/Areas/App2/ (Razor MVC + AngularJS widgets) |
| Real-time notification fan-in | SignalR (already wired in Application/Scripts/) |
| Cover image upload | Existing CDN flow |
| Job lease / checkpoint pattern | Existing Raklet.WebJobs.Secondary infrastructure |
EventDoc {
// Approved fields (publicly visible)
Title, Description, StartDate, TicketTypes, PaymentAccountId, ...
IsPublished, PublishStatus: enum { Draft, Published, Archived },
// Draft review state (independent of publish state)
DraftStatus: enum { None, Pending, Rejected },
DraftCreatedAt: DateTime?,
SubmittedByMemberId: Guid?,
SubmittedAt: DateTime?,
// Member's pending edits (allowlisted fields only)
PendingDraft: {
Title, Description, StartDate, Capacity, CoverImageUrl,
// NOT: PaymentAccountId, TicketTypes prices, IsPublished, PublishStatus
SubmittedAt: DateTime?
}
}
Codex read the locked engineering decisions and challenged them. 10 findings. Verbatim. This pass caught a critical bug.
SubmissionStatus=Pending on an already-approved event conflicts with the visibility rule SubmissionStatus=Approved, so submitting an edit can make the live approved event disappear. Split published approval state from pending-draft review state, or make the visibility filter explicitly treat approved top-level data with pending draft as visible. CRITICAL BUG · fixed via two-status model (D6)EventQueryFilters.VisibleTo(callerContext) will become a hidden permission oracle if every caller has to encode admin/member/public/job semantics correctly. Make the API explicit: VisibleForPublic, VisibleForMember, VisibleForAdmin, VisibleForSystemJob. Deny by default. accepted — per-surface helpers lockedPendingDraft duplicates sensitive mutable fields like tickets, payment account, dates, and publish state, which creates merge bugs and finance/reporting inconsistencies. Use a strict allowlist of draft-editable fields, block or separately review financial fields, and require ETag/version checks on approve. accepted — field-level allowlist lockedEventDetailsEditViewModel for member submissions couples member validation to admin editing assumptions and will accidentally expose admin-only fields over time. Keep shared validators, but introduce a member submission command/view model with field-level authorization. accepted — shared validators + member-specific command DTOSubmissionStatus=Pending conflates first-time submissions with pending edits to approved events. Store separate timestamps and reason/state for original submission versus pending draft. accepted — solved by two-status model + DraftCreatedAt fieldDraftCreatedAt timestamp)Indicative layouts using Raklet's existing Bootstrap 4 + FontAwesome conventions. Final pixel work in /design-review against live screenshots.
Your submission goes to an admin for review.
Submit your event details for admin review. Once approved, your event publishes under your org's brand.
+ Submit your first eventReuse Raklet's existing Bootstrap 4 + FontAwesome + Social* CSS conventions. No new design vocabulary. All user-facing strings localized across 5 locales (de, en, fr, sv, zh).
| Decision | Locked value |
|---|---|
| Member form field order | Title → When → Where → Capacity → Ticket → Description → Cover image (member task flow, not admin order) |
| My Submissions empty state | Centered card · fa-calendar-plus icon · designed headline + primary CTA |
| Mobile-first member surfaces | Single column always · native HTML5 inputs · sticky bottom action bar · 44px touch targets |
| Admin pending badge | Prominent badge badge-warning + fa-clock · click into detail for action (no inline shortcut) |
| Edit form button hierarchy | Save primary (btn-primary) · Submit-for-approval secondary (btn-default) |
| Notification cadence | Daily digest email + real-time in-app bell + real-time email on decision |
| SLA escalation | 3-day admin reminder + 7-day org-owner escalation |
Original "300 events approved" metric was a vanity proxy. Codex pass #1 flagged it. Replaced with a 4-metric stack that tracks the actual business goal.
Fewer than 2 paying orgs use the feature by day 60, OR the hiking-club customer does not convert / drops Raklet after trial.
Step 1 (foundational model + filter helper) blocks everything else. After Step 1, six lanes parallelize across worktrees.
EventDoc query callsites (IRON RULE: integration tests against real store, not Moq, per project convention)Four reflections from the conversation, captured verbatim from the design doc. These are not "things to do" — they're patterns worth keeping for the next feature.
The original request layered three concerns (UI, approval, payment routing) and surfaced the "default reminders is a site feature" gotcha unprompted. Most product briefs hand off "let members create events" and leave the reminders surprise to engineering. Naming dependencies in the opening message saved a round of discovery.
When the sub-leader / regular-member distinction was introduced, the response was "why did you ask, what's the difference?" — not nodding. That question is the reason the design is right. If the distinction had been accepted, v1 would be a two-tier system instead of a single flow with v2 auto-approve. Worth keeping the instinct to ask "but why" when an AI sounds confident.
Notification timing flipped: real-time → daily digest → ("but admins shouldn't keep members waiting") → digest with real-time bell + real-time submitter email on decision. Not flip-flopping. Holding the user experience as the load-bearing concern over engineering convenience. Worth doing more of, even when the AI argues against you.
This is the move that separates the people who get useful designs from AI from those who get plausible-sounding ones. The codebase research is what changed "per-manager opt-in is v1.5" to "per-manager opt-in is free in v1." That single finding probably saved a quarter of cycle time on this feature.
| Document | Source (GitHub) | Rendered (docs site) |
|---|---|---|
| Design doc (canonical) | repo | docs site |
| CEO plan (scope decisions) | repo | docs site |
| Test plan | repo | docs site |
| Deferred v1.5 items | TODOS.md | — |