Migrate project artifacts to spec-kit format
- Move cross-cutting docs (personas, design system, implementation phases, Ideen.md) to .specify/memory/ - Move cross-cutting research and plans to .specify/memory/research/ and .specify/memory/plans/ - Extract 5 setup tasks from spec/setup-tasks.md into individual specs/001-005/spec.md files with spec-kit template format - Extract 20 user stories from spec/userstories.md into individual specs/006-026/spec.md files with spec-kit template format - Relocate feature-specific research and plan docs into specs/[feature]/ - Add spec-kit constitution, templates, scripts, and slash commands - Slim down CLAUDE.md to Claude-Code-specific config, delegate principles to .specify/memory/constitution.md - Update ralph.sh with stream-json output and per-iteration logging - Delete old spec/ and docs/agents/ directories - Gitignore Ralph iteration JSONL logs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
94
specs/008-rsvp/spec.md
Normal file
94
specs/008-rsvp/spec.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Feature Specification: RSVP to an Event
|
||||
|
||||
**Feature**: `008-rsvp`
|
||||
**Created**: 2026-03-06
|
||||
**Status**: Draft
|
||||
**Source**: Migrated from spec/userstories.md
|
||||
|
||||
## User Scenarios & Testing
|
||||
|
||||
### User Story 1 - Submit an RSVP (Priority: P1)
|
||||
|
||||
A guest opens an active event page and indicates whether they will attend. If attending, they must provide their name. If not attending, the name is optional. The RSVP is sent to the server and persisted. The guest's choice, name, event token, title, and date are saved in localStorage.
|
||||
|
||||
**Why this priority**: Core interactive feature of the app. Without it, guests cannot communicate attendance, and the attendee list (US-2) has no data.
|
||||
|
||||
**Independent Test**: Can be fully tested by opening an event page and submitting "I'm attending" with a name, then verifying the attendee list updates and localStorage contains the RSVP record.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a guest is on an active event page, **When** they select "I'm attending" and enter their name, **Then** the RSVP is submitted to the server, persisted, and the attendee list reflects the new entry.
|
||||
2. **Given** a guest is on an active event page, **When** they select "I'm attending" but leave the name blank, **Then** the form is not submitted and a validation message indicating the name is required is shown.
|
||||
3. **Given** a guest is on an active event page, **When** they select "I'm not attending" without entering a name, **Then** the RSVP is submitted successfully (name is optional for non-attendees).
|
||||
4. **Given** a guest submits an RSVP (attending or not), **When** the submission succeeds, **Then** the guest's RSVP choice, name, event token, event title, and event date are stored in localStorage on this device.
|
||||
5. **Given** a guest submits an RSVP, **When** the submission succeeds, **Then** no account, login, or personal data beyond the optionally entered name is required.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Re-RSVP from the Same Device (Priority: P2)
|
||||
|
||||
A returning guest on the same device opens an event page where they previously submitted an RSVP. The form pre-fills with their prior choice and name. Re-submitting updates the existing RSVP rather than creating a duplicate.
|
||||
|
||||
**Why this priority**: Prevents duplicate entries and provides a better UX for guests who want to change their mind. Depends on Story 1 populating localStorage.
|
||||
|
||||
**Independent Test**: Can be tested by RSVPing once, then reloading the event page and verifying the form is pre-filled and a second submission updates rather than duplicates the server-side record.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a guest has previously submitted an RSVP on this device, **When** they open the same event page again, **Then** the RSVP form is pre-filled with their previous choice and name.
|
||||
2. **Given** a guest has a prior RSVP pre-filled, **When** they change their selection and re-submit, **Then** the existing server-side RSVP entry is updated and no duplicate entry is created.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - RSVP Blocked on Expired or Cancelled Events (Priority: P2)
|
||||
|
||||
A guest attempts to RSVP to an event that has already expired or has been cancelled. The RSVP form is not shown and the server rejects any submission attempts.
|
||||
|
||||
**Why this priority**: Enforces data integrity and respects the event lifecycle. Cancelled event guard deferred until US-18 is implemented.
|
||||
|
||||
**Independent Test**: Can be tested by attempting to RSVP to an event whose expiry date has passed and verifying the form is hidden and the server returns a rejection response.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** an event's expiry date has passed, **When** a guest opens the event page, **Then** the RSVP form is not shown and no RSVP submission is possible.
|
||||
2. **Given** an event's expiry date has passed, **When** a guest sends a direct RSVP request to the server, **Then** the server rejects the submission with a clear error response.
|
||||
3. **Given** an event has been cancelled (US-18), **When** a guest opens the event page, **Then** the RSVP form is hidden and no RSVP submission is possible [deferred until US-18 is implemented].
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when a guest RSVPs on two different devices? Each device stores its own localStorage entry; the server holds both RSVPs as separate entries (no deduplication across devices — acceptable per design, consistent with the no-account model).
|
||||
- What happens when the server is unreachable during RSVP submission? The submission fails; localStorage is not updated (no optimistic write). The guest sees an error and can retry.
|
||||
- What happens if localStorage is cleared after RSVPing? The form no longer pre-fills and the guest can re-submit; the server will create a new RSVP entry rather than update the old one.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The RSVP form MUST offer exactly two choices: "I'm attending" and "I'm not attending".
|
||||
- **FR-002**: When the guest selects "I'm attending", the name field MUST be required; submission MUST be blocked if the name is blank.
|
||||
- **FR-003**: When the guest selects "I'm not attending", the name field MUST be optional; submission MUST succeed without a name.
|
||||
- **FR-004**: On successful RSVP submission, the server MUST persist the RSVP associated with the event.
|
||||
- **FR-005**: On successful RSVP submission, the client MUST store the guest's RSVP choice and name in localStorage, keyed by event token.
|
||||
- **FR-006**: On successful RSVP submission, the client MUST store the event token, event title, and event date in localStorage (to support the local event overview, US-7).
|
||||
- **FR-007**: If a prior RSVP for this event exists in localStorage, the form MUST pre-fill with the stored choice and name on page load.
|
||||
- **FR-008**: Re-submitting an RSVP from a device that has an existing server-side entry for this event MUST update the existing entry, not create a new one.
|
||||
- **FR-009**: The RSVP form MUST NOT be shown and the server MUST reject RSVP submissions after the event's expiry date has passed.
|
||||
- **FR-010**: The RSVP form MUST NOT be shown and the server MUST reject RSVP submissions if the event has been cancelled [enforcement deferred until US-18 is implemented].
|
||||
- **FR-011**: RSVP submission MUST NOT require an account, login, or any personal data beyond the optionally entered name.
|
||||
- **FR-012**: No personal data or IP address MUST be logged on the server when processing an RSVP.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **RSVP**: Represents a guest's attendance declaration. Attributes: event token reference, attending status (boolean), optional name, creation/update timestamp. The server-side identity key for deduplication is the combination of event token and a device-bound identifier [NEEDS EXPANSION: deduplication mechanism to be defined during implementation].
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: A guest can submit an RSVP (attending with name, or not attending without name) from the event page without an account.
|
||||
- **SC-002**: Submitting an RSVP from the same device twice results in exactly one server-side RSVP entry for that guest (no duplicates).
|
||||
- **SC-003**: After submitting an RSVP, the local event overview (US-7) can display the event without a server request (event token, title, and date are in localStorage).
|
||||
- **SC-004**: The RSVP form is not shown on expired events, and direct server submissions for expired events are rejected.
|
||||
- **SC-005**: No name, IP address, or personal data beyond the submitted name is stored or logged by the server in connection with an RSVP.
|
||||
Reference in New Issue
Block a user