Add RSVP creation endpoint with typed tokens and attendee count
Introduce typed token value objects (EventToken, OrganizerToken,
RsvpToken) and refactor all existing Event code to use them.
Add POST /events/{token}/rsvps endpoint that persists an RSVP and
returns an rsvpToken. Populate attendeeCount in GET /events/{token}
from a real count query instead of hardcoded 0.
Includes: OpenAPI spec, Liquibase migration (rsvps table with
ON DELETE CASCADE), domain model, hexagonal ports/adapters,
service layer, and full test coverage (unit + integration).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
|
||||
|
||||
<changeSet id="003-create-rsvps-table" author="fete">
|
||||
<createTable tableName="rsvps">
|
||||
<column name="id" type="bigserial" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="rsvp_token" type="uuid">
|
||||
<constraints nullable="false" unique="true"/>
|
||||
</column>
|
||||
<column name="event_id" type="bigint">
|
||||
<constraints nullable="false"
|
||||
foreignKeyName="fk_rsvps_event_id"
|
||||
references="events(id)"
|
||||
deleteCascade="true"/>
|
||||
</column>
|
||||
<column name="name" type="varchar(100)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<createIndex tableName="rsvps" indexName="idx_rsvps_event_id">
|
||||
<column name="event_id"/>
|
||||
</createIndex>
|
||||
|
||||
<createIndex tableName="rsvps" indexName="idx_rsvps_rsvp_token">
|
||||
<column name="rsvp_token"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -8,5 +8,6 @@
|
||||
<include file="db/changelog/000-baseline.xml"/>
|
||||
<include file="db/changelog/001-create-events-table.xml"/>
|
||||
<include file="db/changelog/002-add-timezone-column.xml"/>
|
||||
<include file="db/changelog/003-create-rsvps-table.xml"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
||||
@@ -37,6 +37,52 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ValidationProblemDetail"
|
||||
|
||||
/events/{token}/rsvps:
|
||||
post:
|
||||
operationId: createRsvp
|
||||
summary: Submit an RSVP for an event
|
||||
tags:
|
||||
- events
|
||||
parameters:
|
||||
- name: token
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Public event token
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateRsvpRequest"
|
||||
responses:
|
||||
"201":
|
||||
description: RSVP created successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateRsvpResponse"
|
||||
"400":
|
||||
description: Validation failed (e.g. blank name)
|
||||
content:
|
||||
application/problem+json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ValidationProblemDetail"
|
||||
"404":
|
||||
description: Event not found
|
||||
content:
|
||||
application/problem+json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProblemDetail"
|
||||
"409":
|
||||
description: Event has expired — RSVPs no longer accepted
|
||||
content:
|
||||
application/problem+json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProblemDetail"
|
||||
|
||||
/events/{token}:
|
||||
get:
|
||||
operationId: getEvent
|
||||
@@ -182,6 +228,34 @@ components:
|
||||
description: Whether the event's expiry date has passed
|
||||
example: false
|
||||
|
||||
CreateRsvpRequest:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 100
|
||||
description: Guest's display name
|
||||
example: "Max Mustermann"
|
||||
|
||||
CreateRsvpResponse:
|
||||
type: object
|
||||
required:
|
||||
- rsvpToken
|
||||
- name
|
||||
properties:
|
||||
rsvpToken:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Token identifying this RSVP (store client-side for future updates)
|
||||
example: "d4e5f6a7-b8c9-0123-4567-890abcdef012"
|
||||
name:
|
||||
type: string
|
||||
description: Guest's display name as stored
|
||||
example: "Max Mustermann"
|
||||
|
||||
ProblemDetail:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in New Issue
Block a user