Files
CalendarApi/about/logic.md
Michilis 41f6ae916f first commit
Made-with: Cursor
2026-02-28 02:17:55 +00:00

502 lines
7.0 KiB
Markdown

# Calendar & Contacts API
## logic.md
This document defines the COMPLETE business logic layer of the Calendar & Contacts API.
It explains:
* Permission enforcement
* Ownership rules
* Validation rules
* Recurrence engine behavior
* Reminder processing
* Availability calculation
* Booking logic
* Transaction boundaries
* Audit requirements
* Edge case handling
This file MUST be treated as the authoritative source for backend logic.
---
## GLOBAL INVARIANTS
1. All timestamps stored in UTC.
2. All API timestamps are RFC3339 strings.
3. Ownership is ALWAYS derived from auth context.
4. Soft deletes are enforced everywhere.
5. No endpoint may leak data across users.
6. All mutations must write audit log entries.
---
1. AUTHENTICATION & CONTEXT
---
Every authenticated request must result in a RequestContext struct:
RequestContext:
* user_id (uuid)
* auth_method ("jwt" | "api_key")
* scopes (if api_key)
JWT auth:
* Validate signature
* Validate expiration
* Extract user_id
API key auth:
* Hash provided key
* Lookup in api_keys
* Ensure revoked_at is NULL
* Load scopes
If neither provided → AUTH_REQUIRED
If invalid → AUTH_INVALID
---
2. PERMISSION MODEL
---
Calendar roles:
* owner
* editor
* viewer
Permission matrix:
CALENDAR ACTIONS
* owner: full access
* editor: read calendar, CRUD events
* viewer: read-only
EVENT ACTIONS
* owner/editor: create/update/delete
* viewer: read
CONTACT ACTIONS
* Only owner of contacts can CRUD
BOOKING
* Only owner can create booking links
API KEY SCOPE ENFORCEMENT
Each endpoint maps to required scope.
Example:
* GET /calendars → calendars:read
* POST /events → events:write
* GET /contacts → contacts:read
If scope missing → FORBIDDEN
---
3. USER LOGIC
---
REGISTER
* Email lowercase
* Must be unique
* Password >=10 chars
* Hash with bcrypt cost >=12
* Create default calendar
* Return tokens
DELETE USER
* Soft delete user
* Soft delete calendars
* Soft delete events
* Soft delete contacts
* Revoke API keys
---
4. CALENDAR LOGIC
---
CREATE
* owner_id = authenticated user
* name required (1..80)
* color optional hex validation
LIST
Return calendars where:
* owner_id = user_id
OR
* calendar_members.user_id = user_id
Include role in response.
DELETE
* Only owner
* Soft delete calendar
* Soft delete all related events
SHARING
* Only owner can share
* Cannot share with self
* Upsert membership row
REMOVE MEMBER
* Only owner
* Cannot remove owner
---
5. EVENT LOGIC
---
CREATE EVENT
Validation:
* calendar exists
* user has editor or owner role
* title 1..140
* end_time > start_time
* timezone valid IANA
Time handling:
* Convert start_time to UTC
* Convert end_time to UTC
* Store original timezone string
Overlap rule:
* Overlap allowed by default
* Booking system enforces no-overlap
If recurrence_rule provided:
* Validate via rrule-go
* Store string
If reminders provided:
* Insert reminders
* Schedule jobs
UPDATE EVENT
* Same permission check
* Re-validate time constraints
* If recurrence changed → validate again
* Reschedule reminders
DELETE EVENT
* Soft delete
---
6. RECURRENCE ENGINE
---
Recurring events are NOT pre-expanded.
Storage:
* recurrence_rule string on master event
Expansion occurs ONLY during:
* GET /events
* GET /events/{id}/occurrences
Algorithm:
For each event in DB where:
* event.start_time <= range_end
If no recurrence_rule:
* Include if intersects range
If recurrence_rule present:
* Initialize rrule with DTSTART = event.start_time
* Generate occurrences within [range_start, range_end]
* For each occurrence:
* Check against exceptions
* Create virtual occurrence object
Occurrence response must include:
* is_occurrence = true
* occurrence_start_time
* occurrence_end_time
Exceptions table:
* event_id
* exception_date
* action ("skip")
If occurrence matches exception_date → skip
---
7. REMINDER PROCESSING
---
Reminder scheduling rule:
For each reminder (minutes_before):
trigger_time = event.start_time - minutes_before
If trigger_time > now:
* Enqueue Asynq job
Job payload:
* event_id
* reminder_id
* user_id
Worker logic:
* Load event
* If event.deleted_at != NULL → abort
* Send notification (webhook/email placeholder)
* Retry on failure with exponential backoff
On event update:
* Cancel old reminder jobs (if supported)
* Recompute schedule
---
8. CONTACT LOGIC
---
Contacts are strictly per-user.
CREATE
* Must have at least one identifying field
* email validated if present
SEARCH
* Case-insensitive match on:
* first_name
* last_name
* email
* company
DELETE
* Soft delete
---
9. AVAILABILITY LOGIC
---
Endpoint requires:
* calendar_id
* start
* end
Permission:
* viewer or higher
Busy condition:
An event is busy if:
(event.start_time < range_end)
AND
(event.end_time > range_start)
Recurring events:
* Expand occurrences
* Apply same intersection rule
Return busy blocks sorted by start.
---
10. BOOKING SYSTEM LOGIC
---
CREATE BOOKING LINK
* Only owner
* Generate secure random token
* Store configuration
PUBLIC AVAILABILITY
* No auth
* Load booking link
* Validate active
* Compute working-hour windows
* Subtract busy blocks
* Apply buffer_minutes before/after events
RESERVATION
* Begin DB transaction
* Re-check slot availability with overlap query
* If conflict → ROLLBACK + CONFLICT
* Insert event
* Commit
Overlap query inside transaction:
SELECT 1 FROM events
WHERE calendar_id = ?
AND deleted_at IS NULL
AND start_time < slot_end
AND end_time > slot_start
FOR UPDATE
This ensures race safety.
---
11. CURSOR PAGINATION
---
Cursor format:
base64url(last_sort_time|last_id)
Decoding:
* Split by pipe
* Use as tuple comparison
Events sorting:
ORDER BY start_time ASC, id ASC
Contacts sorting:
ORDER BY created_at ASC, id ASC
Limit enforcement:
* Default 50
* Max 200
---
12. AUDIT LOG LOGIC
---
Every mutation writes:
entity_type
entity_id
action
user_id
timestamp
Actions examples:
* CREATE_EVENT
* UPDATE_EVENT
* DELETE_EVENT
* SHARE_CALENDAR
* DELETE_CONTACT
Audit writes MUST NOT fail main transaction.
If audit insert fails:
* Log error
* Continue response
---
13. ERROR RULES
---
AUTH_REQUIRED → no credentials
AUTH_INVALID → invalid token
FORBIDDEN → permission denied
NOT_FOUND → entity not found or not accessible
VALIDATION_ERROR → invalid input
CONFLICT → overlap or duplicate
INTERNAL → unexpected error
Never expose internal DB errors directly.
---
14. TRANSACTION RULES
---
Transactions REQUIRED for:
* Booking reservation
* Event creation with reminders
* Event update affecting reminders
* Deleting calendar (cascade soft delete)
Service layer must manage transactions.
Repository layer must not auto-commit.
---
15. PERFORMANCE REQUIREMENTS
---
All list endpoints:
* Must use indexed columns
* Must use pagination
* Must avoid N+1 queries
Recurring expansion must be bounded by requested range.
Maximum recurrence expansion window allowed per request:
* 1 year (recommended safeguard)
If range exceeds safeguard → VALIDATION_ERROR
---
This is the authoritative backend logic specification.