# Sharing Context This document describes the dashboard sharing system, which allows NOWATCH users to share their wellness data with friends, family, or caregivers, and to organize shared dashboards through groups. ## Overview The sharing system consists of two main components: 1. **Sharing** (`/sharing` endpoints): Managing outgoing and incoming dashboard shares through invitations and requests 2. **Shared** (`/shared` endpoints): Viewing and organizing dashboards that have been shared with you ## Sharing Flow There are two ways users can establish a sharing relationship: ### 1. Invitation Flow (Push Model) When a user wants to share their dashboard with someone else: 1. **User A** sends an invitation to **User B** via `POST /sharing/invite` 2. **User B** receives an email notification 3. **User B** can either: - Accept the invitation via `POST /sharing/invite/accept` - Reject the invitation via `POST /sharing/invite/reject` 4. If accepted, **User B** can now view **User A's** dashboard ### 2. Request Flow (Pull Model) When a user wants to view someone else's dashboard: 1. **User A** sends a request to **User B** via `POST /sharing/request` 2. **User B** receives a notification 3. **User B** can either: - Accept the request via `POST /sharing/request/accept` - Reject the request via `POST /sharing/request/reject` 4. If accepted, **User A** can now view **User B's** dashboard ## Key Concepts ### Shared Since Date When sharing a dashboard, the owner can specify a `sharedSince` date. This limits the shared data to only records from that date onwards. This gives users control over their data privacy by: - Sharing only recent data - Excluding historical data they prefer to keep private - Updating the date range later via `POST /sharing/shared-since` ### Sharing Status All invitations and requests have one of three statuses: | Status | Description | | --- | --- | | `PENDING` | Awaiting response from the recipient | | `ACCEPTED` | The invitation/request has been accepted | | `REJECTED` | The invitation/request has been declined | ### Unidirectional Sharing Sharing is **unidirectional** by default. If User A shares their dashboard with User B, User B can see User A's data, but User A **cannot** see User B's data unless User B also shares their dashboard with User A. ## Shared Dashboards Organization Once you have access to other users' dashboards, you can organize them using the `/shared` endpoints. ### Groups Groups allow you to categorize and organize multiple shared dashboards: **Group Operations:** - Create groups with `POST /shared/groups` - Add users to groups with `POST /shared/groups/:groupId/members` - Remove users from groups with `DELETE /shared/groups/:groupId/members` - Rename groups with `PATCH /shared/groups/:groupId` - Delete groups with `DELETE /shared/groups/:groupId` **Important:** Deleting a group does **not** affect the underlying sharing relationships. It only removes the organizational structure. ### Custom Names, Icon Colors, and Profile Pictures You can personalize how shared dashboards appear to you: - Set a custom display name (e.g., "Mom", "Training Buddy") - Choose an icon color for quick visual identification - Upload a custom profile picture to replace the default avatar - Update these settings with `POST /shared/custom` - Upload a picture with `POST /shared/custom/profile-picture` These customizations are **private** and only affect your view—they don't change how the dashboard appears to others. ## Data Structures ### SharingEntity Represents an active sharing relationship where you're sharing your dashboard with someone. ```json { "fromId": "", "fromEmail": "you@example.com", "toId": "", "toEmail": "recipient@example.com", "sharedSince": "2024-01-01T00:00:00.000Z", "created": "2024-01-01T12:00:00.000Z", "lastUpdated": "2024-01-15T10:30:00.000Z" } ``` | Field | Type | Description | | --- | --- | --- | | `fromId` | String | Encrypted ID of the dashboard owner | | `fromEmail` | String | Email of the dashboard owner | | `toId` | String | Encrypted ID of the viewer | | `toEmail` | String | Email of the viewer | | `sharedSince` | Date | Start date for shared data | | `created` | Date | When the sharing relationship was created | | `lastUpdated` | Date | When the sharing relationship was last modified | ### SharedEntity Represents a dashboard that has been shared with you (extends SharingEntity). ```json { "fromId": "", "fromEmail": "owner@example.com", "toId": "", "toEmail": "you@example.com", "sharedSince": "2024-01-01T00:00:00.000Z", "created": "2024-01-01T12:00:00.000Z", "lastUpdated": "2024-01-15T10:30:00.000Z", "customName": "Mom", "iconColor": "#FF5733", "customProfilePicture": "sharing/user-id/other-id/timestamp_custom_profile.png", "groupIds": ["a1b2c3d4-e5f6-7890-1234-567890abcdef"], "lastSyncAt": "2024-01-20T08:45:00.000Z" } ``` | Field | Type | Description | | --- | --- | --- | | `customName` | String | Your custom display name for this dashboard | | `iconColor` | String | Your chosen color for the dashboard icon | | `customProfilePicture` | String | Path to the custom profile picture | | `groupIds` | String[] | IDs of groups this dashboard belongs to | | `lastSyncAt` | Date | Last time data was synced from mobile app | ### InviteEntity Represents an invitation to share a dashboard. ```json { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "fromEmail": "sender@example.com", "invitedEmail": "recipient@example.com", "status": "PENDING", "shareSince": "2024-01-01T00:00:00.000Z", "sentDate": "2024-01-15T12:00:00.000Z", "created": "2024-01-15T12:00:00.000Z", "lastUpdated": "2024-01-15T12:00:00.000Z" } ``` | Field | Type | Description | | --- | --- | --- | | `id` | String | Unique identifier for the invitation | | `fromEmail` | String | Email of the person sending the invite | | `invitedEmail` | String | Email of the person being invited | | `status` | Enum | PENDING, ACCEPTED, or REJECTED | | `shareSince` | Date | Proposed start date for shared data | | `sentDate` | Date | When the invitation was sent | | `created` | Date | When the invitation record was created | | `lastUpdated` | Date | When the invitation was last modified | ### SharingRequestEntity Represents a request to access someone's dashboard. ```json { "requestedEmail": "owner@example.com", "fromEmail": "requester@example.com", "status": "PENDING", "shareSince": "2024-01-01T00:00:00.000Z", "sentDate": "2024-01-15T12:00:00.000Z", "created": "2024-01-15T12:00:00.000Z", "lastUpdated": "2024-01-15T12:00:00.000Z" } ``` | Field | Type | Description | | --- | --- | --- | | `requestedEmail` | String | Email of the dashboard owner | | `fromEmail` | String | Email of the person requesting access | | `status` | Enum | PENDING, ACCEPTED, or REJECTED | | `shareSince` | Date | Requested start date for shared data | | `sentDate` | Date | When the request was sent | | `created` | Date | When the request record was created | | `lastUpdated` | Date | When the request was last modified | ### GroupEntity Represents a group for organizing shared dashboards. ```json { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "userId": "", "name": "Family", "created": "2024-01-01T12:00:00.000Z", "lastUpdated": "2024-01-10T15:30:00.000Z", "userIds": ["", ""] } ``` | Field | Type | Description | | --- | --- | --- | | `id` | String | Unique identifier for the group | | `userId` | String | Encrypted ID of the group owner | | `name` | String | Display name for the group | | `created` | Date | When the group was created | | `lastUpdated` | Date | When the group was last modified | | `userIds` | String[] | Encrypted IDs of users in this group | ### GroupPopulatedEntity Extends GroupEntity with full user information instead of just IDs. ```json { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "userId": "", "name": "Family", "created": "2024-01-01T12:00:00.000Z", "lastUpdated": "2024-01-10T15:30:00.000Z", "users": [ { "fromId": "", "fromEmail": "member1@example.com", "toId": "", "toEmail": "you@example.com", "sharedSince": "2024-01-01T00:00:00.000Z", "customName": "Mom", "iconColor": "#FF5733", "groupIds": ["a1b2c3d4-e5f6-7890-1234-567890abcdef"], "lastSyncAt": "2024-01-20T08:45:00.000Z", "created": "2024-01-01T12:00:00.000Z", "lastUpdated": "2024-01-15T10:30:00.000Z" } ] } ``` | Field | Type | Description | | --- | --- | --- | | `users` | SharedEntity[] | Full user objects instead of IDs | ## Common Use Cases ### Sharing Your Dashboard with a Family Member ``` 1. POST /sharing/invite Body: { "email": "family@example.com", "shareSince": "2024-01-01" } 2. Family member accepts: POST /sharing/invite/accept Body: { "email": "your@example.com" } 3. Check active shares: GET /sharing ``` ### Organizing Multiple Shared Dashboards ``` 1. Create a group: POST /shared/groups Body: { "name": "Training Partners" } 2. Add members: POST /shared/groups/{groupId}/members Body: { "userId": "" } 3. View organized dashboards: GET /shared/groups ``` ### Customizing a Shared Dashboard ``` POST /shared/custom Body: { "userId": "", "customName": "Training Buddy", "iconColor": "#4CAF50" } ``` ### Uploading a Custom Profile Picture ``` POST /shared/custom/profile-picture Content-Type: multipart/form-data Body: userId: file: ``` ### Requesting Access to Someone's Dashboard ``` 1. Send request: POST /sharing/request Body: { "email": "coach@example.com", "shareSince": "2024-01-01" } 2. Coach accepts: POST /sharing/request/accept Body: { "email": "your@example.com" } 3. View their dashboard: GET /shared ``` ### Stopping Dashboard Access **As the owner** (revoke someone's access): ``` DELETE /sharing Body: { "email": "person@example.com" } ``` **As the viewer** (stop viewing someone's dashboard): ``` DELETE /shared Body: { "userId": "" } ``` ## Privacy and Security ### User ID Encryption All user IDs are encrypted in API responses to protect user privacy. The encryption is one-way and consistent per user, allowing clients to: - Uniquely identify users - Make subsequent API calls - Maintain privacy of internal user IDs ### Data Access Control - Users can only share their own dashboard - Users can only view dashboards explicitly shared with them - The `sharedSince` date enforces temporal access control ### Email Notifications Email notifications are sent for: - New invitations received - New access requests received - Invitation/request acceptances (optional) Rejections do **not** trigger notifications