Fuscorrespondence API Detailed Design
Design Documents
Last updated August 2, 2025
Fuscorrespondence API Detailed Design
Overview
The Fuscorrespondence API powers a digital "slow mail" app, enabling authenticated users to create, send, and receive virtual letters with delivery delays based on rea## Error States
- 401: Unauthenticated (invalid/missing JWT token)
- 403: Forbidden (trying to access another user's resources)
- 404: Resource not found (letter, mailbox, or FuscAddress not found)
- 422: Validation error (invalid FuscAddress when sending)
- 400: Bad request (malformed input or missing required fields)
- 500: Internal server error
Implementation Status
✅ Completed Features:
- User mailbox creation and management
- Draft letter creation and auto-save
- Letter sending with distance-based delivery delays
- FuscAddress validation
- Letter status tracking and automatic transitions
- JWT authentication middleware
- Frontend React application with all major pages
🚧 Pending Features:
- Delete draft functionality (API endpoint and frontend integration)
- Enhanced error handling and user feedback
- Comprehensive testing suitence calculations. All endpoints are authenticated via Fuscauth using JWT tokens.
Base URL: https://6nnj8no7u0.execute-api.us-east-1.amazonaws.com/dev/fuscorrespondence
Stack Summary
- Framework: Node.js + Express + TypeScript + Serverless Framework
- Deployment: AWS Lambda with API Gateway
- Database: DynamoDB (using existing monotable structure)
- Authentication: JWT Bearer tokens
- Endpoint Areas:
- Mailbox management
- Letter composition and management
- Letter sending and delivery
- Address validation
Endpoints
Authentication
All endpoints require an Authorization: Bearer <token> header. Tokens are obtained through the Fuscauth service.
Mailbox
Create/Update Mailbox
- POST
/mailbox - Body:json
{ "location": { "latitude": 37.421, "longitude": -122.084 }, // user current location "fuscaddress": "123 Mockingbird Lane, Springfield" } - Logical outline
- Validates parameters
- gets user’s mailbox from db (if any)
- if mailbox exists
- updates location and fuscaddress in object
- else
- creates uuid
- creates mailbox object
- saves object to db
- Returns:
- 200 + new/updated mailbox record
- 400 if location or fuscaddress parameters missing
Get My Mailbox
- GET
/mailbox - Logical outline
- get user’s mailbox from db
- returns object
- Returns: 200 + mailbox object
Letter Endpoints
Create Draft
- POST
/letters - Body:json
{ "content": "<html/markdown for styled letter>", "status": "Draft" } - Logical outline
- Creates letter object in draft state
- Creates uuid for letter
- Populates content and uuid
- Saves object to DB
- Returns: 201 + letter record with created uuid
Update Draft
- PATCH
/letters/{letterId} - Body:
json
{
"content": "<html/markdown for styled letter>"
}- Returns 201 + success message (no updated content)
Send Letter
- POST
/letters/{letterId}/send - Body:json
{ "recipientFuscaddress": "456 Oak Avenue, Shelbyville" } - Logical outline:
- Validates recipient FuscAddress exists in the system
- Calculates delivery delay based on real GPS distance between sender and recipient
- Uses Haversine Formula to calculate distance between GPS coordinates
- Delivery time calculation:
deliveryTime = 1 hour + (distance_km / 100) hours - Minimum delivery time: 1 hour (even for same location)
- Updates letter record: status changes to
InTransit, setssentDateanddeliveryDate - Letter status will automatically update to
Deliveredwhen delivery time is reached
- Returns:
- 200 + updated letter with delivery ETA
- 404 if recipient postal address does not exist
List My Letters
- GET
/letters?status={Draft|InTransit|Delivered|Read}&sent={true|false} - Query Parameters:
status: Filter by letter status (optional, defaults to all)sent:truefor sent letters,falsefor received letters (optional, defaults to all)
- Returns: Array of letters (content included for full letter objects)
Get Letter
- GET
/letters/{letterId} - Returns: Complete letter object with full content
Address Validation
Validate Address
- POST
/address/validate - Body:json
{ "fuscaddress": "456 Oak Avenue, Shelbyville" } - Returns
- 200 + { valid: true/false }
- 400 if fuscaddress parameter missing
Database
Entities
| Entity | Description |
|---|---|
| Mailbox | Stores Fuscaddress information for a user |
| Letter | The actual message send between users |
Mailbox
json
{
"pk": "USER#<userId>",
"sk": "MAILBOX#<mailboxId>",
"fuscaddress": "string",
"location": {"latitude": float, "longitude": float},
"createdAt": timestamp,
"updatedAt": timestamp
}| Field | Description |
|---|---|
| PK | string containing the user id that owns that mailbox |
| SK | string containing the system generated mailbox id |
| Fuscaddress | String with the visible name of the address |
| Location | Lat/Long value of user’s location at the time the mailbox was created |
Letter
json
{
"pk": "LETTER#<letterId>",
"sk": "LETTER#<letterId>",
"senderUserId": "string",
"senderMailboxId": "<mailboxId>",
"recipientMailboxId": "<mailboxId>",
"status": "Draft|InTransit|Delivered|Read",
"content": "string",
"recipientName": "string (optional)",
"senderName": "string (optional)",
"sentDate": "ISO timestamp",
"deliveryDate": "ISO timestamp",
"createdAt": "ISO timestamp",
"updatedAt": "ISO timestamp"
}| Field | Description |
|---|---|
| pk/sk | Both use LETTER#{letterId} for the letter entity |
| senderUserId | User ID of the letter sender |
| senderMailboxId/recipientMailboxId | Mailbox IDs for sender and recipient |
| status | Current letter status with automatic transitions |
| content | Letter content (plain text) |
| recipientName | How the sender addresses the recipient (optional) |
| senderName | How the sender signs their letter (optional) |
| sentDate | When letter was sent (status changed to InTransit) |
| deliveryDate | Calculated delivery time based on distance |
Key Logic / Edge Cases
- Address Validation: FuscAddress must exist exactly as stored in a mailbox
- Delivery Delay Calculation:
- Uses Haversine formula for GPS distance calculation
- Formula:
deliveryTime = 1 hour + (distance_km / 100) hours - Minimum delivery time: 1 hour (even for same location)
- Status Transitions: Automatic updates based on delivery time calculations
Draft→InTransit(when sent)InTransit→Delivered(when delivery time reached)Delivered→Read(when recipient opens letter)
- Draft auto-save: Frontend auto-saves drafts every 3 seconds using PATCH
- Letter Access: Recipients can only read letters after delivery time
Error States
- 401: Unauthenticated (invalid/missing token)
- 403: Not your resource (trying to access another user’s letter)
- 404: Letter or mailbox not found
- 422: Invalid address (sending letter to non-existent address)
- 400: Bad request (malformed input)