Contacts & Invites – End‑to‑End Specification
1. Terminology
| Term | Meaning |
|---|---|
| Customer | A fully‑registered Mind Your Now user (MYNCustomer) |
| Contact | A verified relationship between two customers (Contact.verified = true) |
| Prospect | Row in Prospect table – represents an out‑bound email invite that is not yet a verified contact |
Customer ──(0..N)── Prospect // pending outbound invites
Customer ──(0..N)── Contact // verified connections
2. User‑Facing Flow
2.1 Inviting by Email
- Enter email → press Invite.
- UI shows spinner → then one of the outcomes below.
- Typeahead Suggestions: While typing an email, show live suggestions from MYN internal contacts, Google contacts, and Outlook/Office365 contacts.
| Outcome | HTTP Response | UI Behaviour |
|---|---|---|
| Email is new (not yet an MYN account) | 201 CREATED { prospectId } | Add row under Pending Invites. |
| Email belongs to an existing MYN user not already contact | 200 OK { contactId } | Instantly add to Your Contacts. |
| Email already a contact | 409 CONFLICT { code:"ALREADY_CONTACT" } | Show toast: Already a contact. |
| Email previously invited (duplicate prospect) | 409 CONFLICT { code:"ALREADY_INVITED" } | Show toast: Invitation already sent. |
| Any validation / format error | 400 BAD_REQUEST | Inline error under input. |
| Server failure | 500 | Toast: Could not send invite. Try later. |
2.2 Accepting an Invite (Recipient Side)
| Step | Actor | Action |
|---|---|---|
| 1 | Prospect clicks link in email | Opens Sign‑Up / Login page with inviteToken. |
| 2 | Backend validates token → creates/links account | Removes row from Prospect, creates Contact both directions, sets verified=true. |
| 3 | Sender’s Pending Invites list auto‑refreshes (WS push). | Moves person from Pending to Contacts. |
2.2b Viewing & Managing Received Invites
| Outcome | HTTP Response | UI Behaviour |
|---|---|---|
| Invites received pending acceptance | 200 OK [PendingInviteResponse[id, inviterEmail]] | Shown under Invites Received with Accept/Reject buttons. |
| Accept invite | POST /api/contacts/incoming/{id}/accept → 200 OK { code:"CONTACT_CREATED" } | Moves the entry to Your Contacts. |
| Reject invite | DELETE /api/contacts/incoming/{id} → 204 NO_CONTENT | Removes the entry from Invites Received. |
2.3 Cancelling a Pending Invite
- Sender clicks Cancel on a prospect row.
DELETE /api/contacts/pending/{prospectId}.- Backend deletes prospect if
customerWhoInvitedEmailmatches caller. - UI instantly removes the row.
3. REST API Contract
| Verb | Path | Body / Params | Success (2xx) | Error Codes |
|---|---|---|---|---|
GET | /api/contacts | – | 200 [ContactResponse] | 500 |
GET | /api/contacts/pending | – | 200 [Prospect] | 500 |
POST | /api/contacts | { "email": string } | See Outcomes above | 400, 409, 500 |
DELETE | /api/contacts/pending/{id} | – | 200 | 404, 403, 500 |
GET | /api/contacts/search?query=... | – | 200 [ContactResponse] | 500 |
GET | /api/contacts/external/google?query=... | – | 200 [ExternalContactDto] | 401, 500 |
GET | /api/contacts/external/microsoft?query=... | – | 200 [ExternalContactDto] | 401, 500 |
GET | /api/contacts/incoming | – | 200 [PendingInviteResponse] | 500 |
POST | /api/contacts/incoming/{id}/accept | – | 200 InviteResult | 400, 401, 500 |
DELETE | /api/contacts/incoming/{id} | – | 204 | 400, 401, 500 |
// ContactResponse (DTO)
{
id: number;
name: string; // username or email
email: string;
}
// Prospect (DTO)
{
id: number;
email: string;
}
4. UI Component Contract (Frontend)
| Component | Source | Props / State highlights |
|---|---|---|
ContactsPage | src/components/contacts/ContactsPage.tsx | contacts, pending, inviteContact(email) |
TaskShareDialog | Uses searchContacts for suggestions | – |
Error‑Handling Rules (Frontend)
if (status === 201) addToPending();
else if (status === 200) addToContacts();
else if (status === 409 && data.code==='ALREADY_CONTACT') toast('Already a contact');
else if (status === 409 && data.code==='ALREADY_INVITED') toast('Invite already sent');
else toast('Error sending invite');
5. Backend Service Rules
- Service:
ContactService.inviteContact. - Steps:
findByEmail→ if returns customer ⇒ create Contact (bidirectional) if not exists.- Else check
Prospectduplicate. - If new prospect → save + send email.
- Throws:
CustomerAlreadyAContact→ map to409 ALREADY_CONTACT.CustomerEmailAlreadyExists→ map to200/201(see above logic).
6. Real‑Time Updates
- WebSocket topic
/contacts/{customerId}pushes events:invite_sent,invite_cancelled,invite_accepted,contact_removed.
- Front‑end subscribes via
useContactsWShook to update state without polling.
7. Future Enhancements
- Bulk Invites – CSV upload → multiple prospects.
- Invite link –
https://mindyournow.com/invite/<token>for socials. - Rate limiting – one invite/email/day to prevent spam.
- In‑app notification when an existing user becomes a contact (no email needed).
8. External Contacts Integration
Objective: Seamlessly import and invite external contacts from Google and Microsoft.
8.1 OAuth & Permissions
- Google People API:
https://www.googleapis.com/auth/contacts.readonly - Microsoft Graph API:
Contacts.Read(and optionallyContacts.ReadWrite)
8.2 Backend Implementation
- Extend
OAuthControllerto request & store contact scopes for Google & Microsoft. - Implement
ExternalContactsServicewith methods:List<ContactDto> fetchGoogleContacts(MYNCustomer customer, String query)List<ContactDto> fetchMicrosoftContacts(MYNCustomer customer, String query)
- Expose new endpoints:
GET /api/contacts/external/google?query=...GET /api/contacts/external/microsoft?query=...
- Cache per‑user results & enforce rate limits.
8.3 Frontend Integration
- In
ContactsPage, add a typeahead search box that queries:- Internal
GET /api/contacts/search?query= - External
GET /api/contacts/external/{source}?query=
- Internal
- Merge & display suggestions with source icons (Google, Microsoft, MYN).
- Debounce input (300ms) and support pagination/loading more.
8.4 UI/UX Considerations
- Add an “Import from” dropdown to switch between sources.
- Show contact avatars where available.
- Allow multi‑select and bulk invite actions.
8.5 Security & Privacy
- Encrypt external tokens at rest.
- Provide a Settings > Integrations panel to view/revoke access.
- Comply with Google & Microsoft data handling policies.
8.6 Milestones & Timeline
- Configure OAuth scopes & backend service hooks (1 week)
- Build external contacts service & endpoints (2 weeks)
- Integrate frontend typeahead & UI components (1 week)
- QA, privacy review & rollout (1 week)