# 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.
