Files
calendars/openspec/changes/add-ical-subscription-export/specs/ical-subscription-export/spec.md

177 lines
6.8 KiB
Markdown
Raw Normal View History

## ADDED Requirements
### Requirement: Calendar Subscription Token Management
The system SHALL allow calendar owners to generate a private subscription token
for their calendars using CalDAV paths directly, enabling read-only access via
iCal URL from external calendar applications without requiring Django Calendar
model synchronization.
#### Scenario: Owner generates subscription token
- **GIVEN** a user owns a calendar with CalDAV path `/calendars/<email>/<uuid>/`
- **WHEN** the user requests a subscription token with that CalDAV path
- **THEN** the system verifies the user's email matches the path
- **AND** generates a unique UUID token stored with the CalDAV path
- **AND** returns the subscription URL in format `/ical/<token>.ics`
#### Scenario: Owner retrieves existing subscription token
- **GIVEN** a user owns a calendar with an existing subscription token
- **WHEN** the user requests the subscription token by CalDAV path
- **THEN** the system returns the existing token and URL
#### Scenario: Owner regenerates subscription token
- **GIVEN** a user owns a calendar with an existing subscription token
- **WHEN** the user deletes the token and creates a new one
- **THEN** the old token is invalidated
- **AND** a new unique token is generated
- **AND** the old subscription URL no longer works
#### Scenario: Owner revokes subscription token
- **GIVEN** a user owns a calendar with an existing subscription token
- **WHEN** the user requests to delete the token by CalDAV path
- **THEN** the system removes the token
- **AND** the subscription URL returns 404
#### Scenario: Non-owner cannot manage subscription token
- **GIVEN** a user attempts to create a token for a CalDAV path not containing their email
- **WHEN** the user sends a request with that CalDAV path
- **THEN** the system rejects the request with a 403 permission error
#### Scenario: One token per calendar path per owner
- **GIVEN** a user already has a subscription token for a CalDAV path
- **WHEN** the user requests to create another token for the same path
- **THEN** the system returns the existing token instead of creating a duplicate
---
### Requirement: Public iCal Export Endpoint
The system SHALL provide a public endpoint that serves calendar data in iCal
format when accessed with a valid subscription token, without requiring user
authentication, using the CalDAV path stored directly in the token.
#### Scenario: Valid token returns calendar data
- **GIVEN** a valid and active subscription token exists with a CalDAV path
- **WHEN** an HTTP GET request is made to `/ical/<token>.ics`
- **THEN** the system proxies to SabreDAV using the token's caldav_path and owner email
- **AND** returns the calendar events in iCal format
- **AND** the response Content-Type is `text/calendar`
- **AND** the response is RFC 5545 compliant
- **AND** no authentication headers are required
#### Scenario: Invalid token returns 404
- **GIVEN** a token that does not exist in the system
- **WHEN** an HTTP GET request is made to `/ical/<invalid-token>.ics`
- **THEN** the system returns HTTP 404 Not Found
#### Scenario: Deleted token returns 404
- **GIVEN** a subscription token that has been deleted
- **WHEN** an HTTP GET request is made to `/ical/<deleted-token>.ics`
- **THEN** the system returns HTTP 404 Not Found
#### Scenario: Access tracking
- **GIVEN** a valid subscription token
- **WHEN** the iCal endpoint is accessed successfully
- **THEN** the system updates the token's last accessed timestamp
#### Scenario: Security headers are set
- **GIVEN** a valid subscription URL
- **WHEN** the iCal endpoint returns a response
- **THEN** the response includes `Cache-Control: no-store, private`
- **AND** the response includes `Referrer-Policy: no-referrer`
#### Scenario: Compatible with external calendar apps
- **GIVEN** a valid subscription URL
- **WHEN** the URL is added to Apple Calendar as a subscription
- **THEN** Apple Calendar successfully subscribes and displays events
- **AND** events sync automatically on refresh
---
### Requirement: Subscription URL User Interface
The system SHALL provide a user interface for calendar owners to obtain and
manage subscription URLs using CalDAV paths extracted from calendar URLs.
#### Scenario: Access subscription URL from calendar menu
- **GIVEN** a user is viewing their calendars
- **WHEN** the user opens the context menu for a calendar they own
- **THEN** an option to get the subscription URL is available
#### Scenario: Subscription option hidden for non-owned calendars
- **GIVEN** a user has shared access to a calendar but is not the owner
- **WHEN** the user opens the context menu for that calendar
- **THEN** the subscription URL option is NOT displayed
#### Scenario: Display subscription URL modal
- **GIVEN** a user clicks the subscription URL option for their calendar
- **WHEN** the modal opens
- **THEN** the frontend extracts the CalDAV path from the calendar URL
- **AND** creates or retrieves the token using the CalDAV path
- **AND** the full subscription URL is displayed
- **AND** a "Copy to clipboard" button is available
- **AND** a warning about keeping the URL private is shown
- **AND** an option to regenerate the URL is available
#### Scenario: Copy URL to clipboard
- **GIVEN** the subscription URL modal is open
- **WHEN** the user clicks "Copy to clipboard"
- **THEN** the URL is copied to the system clipboard
- **AND** visual feedback confirms the copy was successful
#### Scenario: Regenerate token from modal
- **GIVEN** the subscription URL modal is open
- **WHEN** the user clicks to regenerate the URL
- **THEN** a confirmation dialog is shown
- **AND** upon confirmation, the old token is deleted
- **AND** a new token is generated
- **AND** the modal updates to show the new URL
#### Scenario: Error handling in modal
- **GIVEN** the subscription URL modal is open
- **WHEN** the initial token fetch returns 404 (no existing token)
- **THEN** the system automatically creates a new token
- **AND** no error message is displayed to the user
- **BUT** if token creation fails, an error message is displayed
---
### Requirement: Standalone Token Storage
The system SHALL store subscription tokens independently of the Django Calendar
model, using CalDAV paths directly to enable token management without requiring
CalDAV-to-Django synchronization.
#### Scenario: Token stores CalDAV path directly
- **GIVEN** a subscription token is created
- **THEN** the token record includes the full CalDAV path
- **AND** the token record includes the owner (user) reference
- **AND** the token record includes an optional calendar display name
- **AND** no foreign key to Django Calendar model is required
#### Scenario: Permission verification via path
- **GIVEN** a user requests a subscription token
- **WHEN** the system verifies permissions
- **THEN** it checks that the user's email appears in the CalDAV path
- **AND** does not require querying the CalDAV server