docs(prd): add events product with form-gated registration (#788)
* docs(prd): add form-gated workshop access Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com> * docs(prd): scope form-gated workshops to workshop PRD Remove workshop-specific scope from the Forms PRD and document Forms prerequisites and required extensions in the Workshops PRD instead. Address review feedback: send calendar invites only after redemption, defer CE assessment to Phase 5, and remove undeferred external registration. Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com> * docs(prd): resolve workshop review feedback on access and limits Public workshops are replay-only; scheduled sessions require form-gating. Block workshop form submission when the org student limit is reached. Add Forms extensibility note for future attachment consumers. Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com> * docs(prd): reframe workshops as events with format metadata Rename the Workshops PRD to Events and treat webinar, livestream, workshop, and bootcamp as formats of a single Event product. Add format and delivery metadata, timezone-explicit scheduling reusing course.metadata.sessionTimezone, countdown and live-now catalog states, post-event resources via lesson.documents, on-page add-to-calendar and share links, and an invariant that format never drives behavior. Expand non-goals to fence off ticketing, venues, and event series. Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com> * docs(prd): address remaining Events PR review comments - Close student-limit TOCTOU with locked reservation or redeem recheck - Narrow anonymous EVENT playback to public replay-only invariants - Require accessMode, durationMinutes, and callUrl scheduling rules - Document admin auth scope and Forms access-grant route contract - Clarify Forms attachment precedence for integrated submissions Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com> * docs(prd): resolve second-pass Events PR review comments - One active EVENT attachment per course with same-org tenant invariant - Single student-limit strategy: transactional seat reservation at submit - Require complete metadata.event; server defaults for accessMode - Split admin vs public route blocks; authorize grant revoke and context dispatch Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
This commit is contained in:
co-authored by
Rotimi Best
Cursor Agent
parent
a1c4ee720f
commit
64112dfc4f
@@ -154,8 +154,8 @@ A standalone form with a share link is table stakes. Every roadmap decision shou
|
||||
8. File upload is supported in Forms, but public file upload must be guarded with rate limits and storage controls.
|
||||
9. Existing exercise question types are reused first; new form-only block types can be added later.
|
||||
10. The first implementation prioritizes reuse over perfect naming cleanup. Renaming `exercise-question` to a broader package is optional follow-up, not a blocker.
|
||||
11. **Binding is attachment-level, not form-level.** A form is a reusable org-owned asset. A `form_attachment` binds a form to a platform context (course, lesson, landing page, checkout). Every response records which attachment it came through, so course pages show only their own responses while the form library shows all responses with a per-context breakdown.
|
||||
12. **Per-attachment settings vs per-form settings**: lifecycle windows (open/close dates), response limits, and one-response-per-respondent live on the **attachment**. Question content and identity settings (anonymous, collect name/email) live on the **form**. Editing a form's questions applies everywhere it is attached; question versioning is deferred.
|
||||
11. **Binding is attachment-level, not form-level.** A form is a reusable org-owned asset. A `form_attachment` binds a form to a platform context (course, lesson, landing page, checkout). Every response records which attachment it came through, so course pages show only their own responses while the form library shows all responses with a per-context breakdown. The attachment model is intentionally extensible: new platform features can add additional `context_type` values, per-context settings, and integration consequences in their own PRDs without reworking the core Forms product.
|
||||
12. **Per-attachment settings vs per-form settings**: lifecycle windows (open/close dates), response limits, and one-response-per-respondent live on the **attachment**. Question content and identity settings (anonymous, collect name/email) live on the **form**. Editing a form's questions applies everywhere it is attached; question versioning is deferred. Future platform features may add new attachment contexts and consequence hooks (verified-email access grants, enrollment handoffs, etc.). Those integrations extend `form_attachment` and the runner/submission layer; they are specified in the consuming feature's PRD, not enumerated here. **Precedence**: for any integrated attachment, services read lifecycle, limit, and dedup fields from `form_attachment` only — never from the reusable `form` row. Legacy `form.starts_at`, `form.ends_at`, `form.response_limit`, and `form.allow_multiple_responses` columns may remain for bare share-link forms with no attachment, but must not be consulted when a response is tied to an attachment.
|
||||
13. **MVP ships two integration loops**: (a) application → enrollment, including the purchase-request pipeline that replaces the hardcoded course payment modal, and (b) per-lesson pulse feedback. A landing-page form section and a reviews display block are part of MVP surface work.
|
||||
14. **Create-in-context authoring**: every attachable surface (course settings, lesson, landing-page builder, checkout config) gets an "Attach a form" picker that lists existing org forms and offers "Create new", which opens the builder in a modal/drawer pre-seeded with a context-appropriate template. The form is saved to the org Forms library and attached in one motion. The Forms area is the library: manage forms, see where each is attached, view global results.
|
||||
15. **Default purchase-request form**: every org is seeded with a default "Course purchase request" form attached to the checkout context of paid courses. It replaces the hardcoded fullname/email payment modal. Submit stores a pending response, then redirects to the course's `paymentLink`. Admins review pending purchase requests in the response inbox and approve to enroll the student. This also fixes the current theme-based paid path, which dead-ends on a "requires payment or invite" message with no purchase flow at all.
|
||||
@@ -334,6 +334,8 @@ Requirements:
|
||||
3. Responses record `attachment_id`; context views filter by attachment, the library view aggregates across attachments with a per-context breakdown.
|
||||
4. Detaching a form preserves its responses.
|
||||
|
||||
Future platform features may add new attachment contexts and consequence hooks (verified-email access grants, enrollment handoffs, etc.). Those integrations extend `form_attachment` and the runner/submission layer; they are specified in the consuming feature's PRD, not enumerated here.
|
||||
|
||||
### FR-9: Purchase-Request Pipeline (default org form)
|
||||
|
||||
1. Every org is seeded with a default "Course purchase request" form, auto-attached to the checkout context of paid courses.
|
||||
@@ -459,6 +461,8 @@ Notes:
|
||||
|
||||
- Lifecycle windows, limits, and dedup rules live here (per-attachment), not on `form`.
|
||||
- A share link is modeled as a link-type attachment or as the bare form URL; either way responses always resolve to at most one attachment.
|
||||
- When a response records `form_attachment_id`, attachment fields are authoritative. Do not read timing/limit columns from `form` for that submission path.
|
||||
- New `context_type` values, per-context `settings`, DB check constraints, and integration consequences (access grants, context-specific identity overrides) are introduced by consuming feature PRDs and implemented alongside those features — not as implicit scope inside this MVP document. The first such extension is the Events product (`prd/events/README.md`): `EVENT` context bindings, tenant/uniqueness invariants, `form_response_access_grant`, scanner-safe redemption routes, and token-to-session exchange.
|
||||
|
||||
#### 2.4 New `form_response` table
|
||||
|
||||
|
||||
Reference in New Issue
Block a user