NexGate Messaging — Product Requirements & Feature Flows NexGate / QBIT SPARK | Version 1.0 What the messaging platform does — rules, flows, permissions, scenarios Table of Contents Document Purpose User Identity & Discovery Contact Sync Inbox Model Messaging Permissions Call Permissions 1:1 Messaging Flows Group Chat Flows Commerce DM Flows Offer Session Flows Shareable Content Message Interactions Voice & Video Call Flows Group Call Flows Offline & Notification Flows Privacy & Safety Shop Inbox & Staff Access Notification Settings Edge Cases & Scenarios 1. Document Purpose This document defines WHAT NexGate messaging does — the rules, user flows, permissions, and scenarios for every messaging feature. It is the product reference document. It does not describe HOW features are built technically. For technical architecture see: Doc 3: Phase 2 Production Architecture Doc 5: Private Chat & Calls Deep Dive Audience: Product, mobile developers, QA, design. 2. User Identity & Discovery Identity on NexGate Every NexGate user has: @username unique, chosen at registration shown publicly on VP Feed used for messaging: @kibuti Display name full name shown in conversations can differ from username Phone number used for registration + auth NOT shown publicly by default discoverable only with user permission NexGate ID internal UUID never shown to users How Users Find Each Other Discovery mechanism Requires contact sync? ────────────────────────────────────────────────────── VP Feed follow ❌ No VP Shop (buyer/seller) ❌ No Username search (@kibuti) ❌ No QR code scan ❌ No Shareable profile link ❌ No Group chat membership ❌ No Phone number search ❌ No (type manually) Contact sync (phonebook) ✅ Yes (optional) NexGate has multiple discovery paths. Contact sync is one option — not the only one. Discoverability Settings Two independent settings: "Sync my contacts" Find NexGate users in my phonebook Default: OFF (user must opt in) "Let others find me via phone number" If someone has my number → can find me Default: ON (can turn off) These are INDEPENDENT: I can sync contacts without being findable I can be findable without syncing contacts 3. Contact Sync Rules ✅ Optional — never mandatory ✅ Can be enabled/disabled anytime ✅ Can delete synced data anytime from settings ✅ Only finds users who have discoverability ON ❌ Not required to use messaging ❌ Not required for commerce DMs ❌ Contacts data never shared with third parties ❌ Non-NexGate contacts never stored on server Privacy-Preserving Implementation How it works when user accepts: Step 1: Phone numbers hashed ON DEVICE sha256(+255712345678) → hash Actual numbers never leave the device Step 2: Hashes uploaded to NexGate server Not real phone numbers Server cannot reverse hashes Step 3: Server matches hashes Against registered users who have "Let others find me via phone number" = ON Returns: which hashes are NexGate users Step 4: App shows matched users "3 of your contacts are on NexGate" [Connect] buttons shown Non-NexGate contacts: Their hashes deleted from server immediately Never stored Never tracked First Launch Prompt Shown once at first launch after onboarding: ┌──────────────────────────────────────────────┐ │ 📱 Pata Marafiki Wako NexGate │ │ │ │ Ruhusu NexGate kutumia contacts zako │ │ kupata marafiki wanaotumia NexGate tayari │ │ │ │ ✓ Contacts zako hazitashirikiwa na mtu │ │ ✓ Unaweza kufuta ruhusa wakati wowote │ │ ✓ Nambari za simu zinabadilishwa kuwa │ │ msimbo kabla ya kupakiwa │ │ │ │ [Ruhusu Contacts] [Sasa Hivi Sio] │ └──────────────────────────────────────────────┘ If declined: App works fully ✅ Remind once after 7 days Never prompt again after second decline Always accessible in Settings Sync Scenarios Scenario 1 — User accepts sync: Hashes uploaded Matched users shown User can message/follow matched users Sync runs again when contacts change Scenario 2 — User declines sync: App works fully Can still find people via username/QR/VP Feed No contacts uploaded Scenario 3 — User accepts then disables: Settings → Privacy → Contact Sync → OFF All hash data deleted from server Matched contacts remain as connections (connections not removed — only future sync stops) Scenario 4 — User wants to delete contact data: Settings → Privacy → Delete Contacts Data All hashes deleted from server immediately Confirmation shown: "Contacts data imefutwa" Scenario 5 — Contact not on NexGate: Their hash deleted from server User sees option: "Invite Juma to NexGate" Tap → share NexGate invite link via SMS/WhatsApp 4. Inbox Model Two Separate Inboxes Every NexGate user has TWO completely separate inboxes: Personal Inbox: 1:1 DMs with other users (personal) Group chats (personal) Friend conversations Private — only the account owner sees this NEVER accessible to shop staff Shop Inbox (one per shop owned): All customer conversations for that shop Commerce DMs with buyers Shared with authorized shop staff Completely separate from personal inbox Customer sees shop identity — not personal name Inbox Tabs User with 2 shops sees: ┌─────────────────────────────────────────────┐ │ 💬 Inbox │ │ │ │ [Personal ●3] [TechStore ●12] [ClothingHub]│ │ │ │ Personal tab: │ │ Regular DMs + group chats │ │ Private — owner only │ │ │ │ TechStore tab: │ │ Customer commerce conversations │ │ Shared with assigned staff │ │ │ │ ClothingHub tab: │ │ Separate shop conversations │ │ Different staff assigned │ └─────────────────────────────────────────────┘ Staff member (Amina assigned to TechStore): ┌─────────────────────────────────────────────┐ │ [Personal] [TechStore ●12] │ │ │ │ ClothingHub: NOT visible (no access) │ │ Owner personal: NEVER visible │ └─────────────────────────────────────────────┘ Conversation Types Type Owner Participants ──────────────────────────────────────────────────── DM USER 2 users GROUP USER 3-500 users COMMERCE SHOP 1 shop + 1 buyer BROADCAST USER or SHOP 1 sender + N followers 5. Messaging Permissions Who Can Message Who Relationship Can message? How ──────────────────────────────────────────────────────────── Saved contacts (phone) ✅ Always Direct Mutual followers (VP Feed) ✅ Always Direct Commerce relationship ✅ Always Direct (shop inbox) Group chat members ✅ Always Via group only Strangers (no relationship) ⚠️ Request Message request first Blocked users ❌ Never Blocked Message Request System Stranger (no relationship) wants to message you: They can send ONE message request: ┌─────────────────────────────────────────┐ │ 📩 Maombi ya Ujumbe │ │ │ │ Juma Mwangi anataka kukutumia ujumbe │ │ @juma_mwangi · 245 wafuasi │ │ │ │ "Habari, nilikuona kwenye VP Shop..." │ │ │ │ [Kubali] [Kataa] [Zuia] │ └─────────────────────────────────────────┘ If Kubali (Accept): Full conversation opens Juma can now message freely Can call after conversation established If Kataa (Decline): Juma cannot send another request One attempt only per account Juma sees: "Ujumbe haukukubaliwa" If Zuia (Block): Juma blocked immediately Cannot contact again in any way Juma sees: nothing (as if you don't exist) If Ignored (no response): Request stays in request folder Juma cannot send more messages No call attempt allowed Request expires after 30 days Message Request Limits Per account per day: Max 10 message requests sent Prevents spam Per account to same person: 1 request only (ever) If declined → cannot request again Request folder: Separate from main inbox User checks it voluntarily No notification for low-priority requesters (unless they have mutual connections) 6. Call Permissions Permission Tiers Tier Voice call Video call ──────────────────────────────────────────────────────── Saved contacts ✅ ✅ Mutual followers ✅ ✅ Commerce relationship ✅ (shop) ✅ (shop) Active conversation partner ✅ ✅ (message request accepted) Group chat member ✅ (group) ✅ (group) Strangers ❌ ❌ Blocked users ❌ ❌ Commerce Call Rules Buyer can call: The SHOP JID — not the owner personally techstore@shops.nexgate.com Any available staff answers as TechStore Seller (shop) can call: Buyers they have active commerce DM with Call goes from shop JID to buyer Buyer sees "TechStore" calling — not a personal name Protecting personal contact: Owner's personal phone/JID never revealed Commerce calls always through shop identity Staff cannot reveal personal number to customers Anti-Harassment Call Rules Call rate limiting: Max 3 unanswered calls to same person in 24 hours 4th attempt → blocked for 24 hours automatically Resets daily Silence unknown callers: Setting: "Pumzisha simu kutoka kwa wasio contacts" Calls from non-contacts ring silently Notification appears after — not during First call warning: First EVER call from this person: ┌───────────────────────────────────────┐ │ 📞 Simu ya kwanza kutoka │ │ Juma Mwangi (@juma_mwangi) │ │ │ │ [Jibu] [Kataa] [Zuia] │ └───────────────────────────────────────┘ Quick block during call: Report button visible during call One tap → ends call + reports + blocks Privacy Settings for Calls Who can call me: ○ Mutual followers + contacts (default) ○ My contacts only ○ Nobody User can change anytime in Settings → Privacy → Calls Call Permission Check Flow Kibuti tries to call Juma: │ Spring Boot permission check: Is Juma blocked by Kibuti? ❌ → reject immediately Is Kibuti blocked by Juma? ❌ → reject immediately Are they saved contacts? ✅ → allow Are they mutual followers? ✅ → allow Active commerce relationship? ✅ → allow Active accepted conversation? ✅ → allow Does Juma's privacy setting allow? ✅ → allow None of above → ❌ reject │ If rejected: App shows: "Huwezi kupiga simu mtu huyu" No Jingle stanza sent No TURN credentials issued If allowed: TURN credentials generated Jingle session-initiate sent via Ejabberd Juma's device rings 7. 1:1 Messaging Flows Send Text Message Happy path: User types message Taps send Message shows: pending ⏳ Server receives → single tick ✓ Recipient receives → double tick ✓✓ Recipient reads → blue tick ✓✓ Offline path: User taps send Single tick ✓ (server received) Recipient offline → queued FCM push fires to recipient device Recipient comes online → message delivered Double tick ✓✓ appears Send Voice Note User holds mic button: "Kibuti anarekodia..." shown to recipient (if online) Recording in progress Timer shown: 0:01, 0:02... User releases: Voice note sent Waveform shown in thread Duration shown: 0:15 User swipes up while holding: Lock mode — records without holding Release sends User swipes left while holding: Cancel recording — nothing sent Limits: Basic users: max 2 minutes Pro users: max 15 minutes File size: max 16MB Send Media Images: Max 10 images per message Formats: JPG, PNG, WebP, HEIC Max 16MB per image Auto-compressed for EA networks Videos: Max 1 video per message Max 2 minutes (short video) Max 64MB Auto-transcoded to HLS by File Thunder Files/Documents: Max 100MB per file Formats: PDF, DOCX, XLSX, ZIP, etc ClamAV scanned before delivery Available for 30 days then archived 8. Group Chat Flows Create Group User creates group: Tap new group Add members (min 2, max 500) Set group name (required) Set group photo (optional) Tap create Group created: Members notified: "Kibuti amekuongeza kwenye kikundi" All members see welcome message Creator is automatically OWNER Group Roles & Permissions Role Add members Remove Send msg Delete msg Change info ────────────────────────────────────────────────────────────────── OWNER ✅ ✅ ✅ Any msg ✅ ✅ ADMIN ✅ ✅ ✅ Any msg ✅ ✅ MEMBER ❌ ❌ ✅ Own only ✅ ❌ Group Size Limits Free group: max 50 members Pro group: max 500 members At 500 members: Consider using Broadcast Channel instead Broadcast = one way (better for large audiences) Group = two way (better for community) Leave / Remove Member leaves: "Juma ameacha kikundi" shown in thread No longer receives messages Admin removes member: "Amina ameondolewa na Kibuti" shown Member notified: "Umeondolewa" Deleted group (owner only): All members removed All messages deleted (for everyone) Cannot be undone 9. Commerce DM Flows Flow 1 — Buyer Initiates from Product Page Step 1: Buyer on product page Sees: [Chat na Muuzaji] button Tap button Step 2: Conversation opens New DM opens OR existing conversation if already had one Conversation type: COMMERCE Conversation owner: SHOP (not personal) Product card auto-appears: ┌──────────────────────────────────────┐ │ 📦 Samsung A15 │ │ TZS 450,000 │ │ Inapatikana: Vipande 12 │ │ TechStore │ │ [Jibu] [Angalia Bidhaa] │ └──────────────────────────────────────┘ NOTE: Price in card is frozen at this moment Public price changes later → does NOT affect this card Step 3: Negotiation Buyer and seller exchange text messages Normal conversation — no restrictions on text Step 4: Agreement reached Seller taps attach (+) → From My Shop Selects product Sets custom price for THIS buyer ONLY Public product price: unchanged ✅ Sends price offer card Step 5: Buyer receives offer ┌──────────────────────────────────────┐ │ 💰 Bei Maalum Kwako │ │ Samsung A15 │ │ ~~TZS 450,000~~ │ │ TZS 400,000 (-TZS 50,000) │ │ Inaisha: dakika 28 │ │ Idadi: [─ 1 +] │ │ [Kataa] [Endelea Kulipa →] │ └──────────────────────────────────────┘ Step 6: Buyer taps "Endelea Kulipa" Redirected to checkout flow (OUTSIDE inbox) Checkout at custom offer price Quantity confirmed in checkout Step 7: Order placed Confirmation message appears in same thread: ┌──────────────────────────────────────┐ │ ✅ Agizo Limethibitishwa │ │ Ord #ORD-XYZ-789 │ │ Samsung A15 × 1 │ │ TZS 400,000 imelipwa │ │ [Fuatilia Agizo] │ └──────────────────────────────────────┘ Flow 2 — Seller Attaches from Inside Any Chat Step 1: Seller inside any DM conversation Taps attach (+) button Menu appears: 📷 Picha 🎵 Sauti 📄 Faili 🏪 Kutoka Dukani ← this one 📅 Tukio 👥 Ununuzi wa Pamoja Step 2: Seller taps "Kutoka Dukani" Their shop product list opens Seller browses and selects product Sets custom price (optional) Sets quantity limit (optional) Adds note (optional): "Bei hii ni leo tu" Taps Send Step 3: Buyer receives offer card Same offer card UI as Flow 1 Same checkout redirect Same order confirmation in thread Commerce DM Rules ✅ Buyer can initiate from any product page ✅ Seller can attach from inside any conversation ✅ Custom price is private to this buyer only ✅ Public product price never changes ✅ Checkout always happens outside inbox ✅ Order confirmation appears in thread ✅ Multiple offers allowed in one conversation ❌ Buyer cannot request specific price (only negotiate via text) ❌ Offer cannot be edited after sending (send new one instead) ❌ Offer cannot be forwarded to other conversations ❌ Order confirmation cannot be deleted or edited 10. Offer Session Flows Offer Lifecycle PENDING → offer sent, waiting for buyer response │ ├──▶ DECLINED buyer tapped "Kataa" │ seller notified │ seller can send new offer │ ├──▶ EXPIRED timer ran out │ both parties notified in thread │ seller can send new offer │ ▼ ACCEPTED → buyer tapped "Endelea Kulipa" │ buyer enters checkout ▼ CHECKOUT → buyer in payment flow │ ├──▶ ABANDONED buyer left checkout without paying │ offer returns to PENDING? NO │ offer marked ABANDONED │ seller must send new offer │ ▼ COMPLETED → order placed successfully │ cannot be reversed here (order system handles) ▼ CANCELLED → order cancelled (handled by order system) offer marked CANCELLED Multiple Offers — Same Conversation Seller can send multiple offers: Each is independent session Previous offers remain in thread with their status Thread shows history: ┌──────────────────────────────────────┐ │ 💰 Bei Maalum: TZS 430,000 │ │ ❌ Ilikataliwa │ └──────────────────────────────────────┘ ┌──────────────────────────────────────┐ │ 💰 Bei Maalum: TZS 410,000 │ │ ⏰ Imeisha muda │ └──────────────────────────────────────┘ ┌──────────────────────────────────────┐ │ 💰 Bei Maalum: TZS 400,000 │ │ ✅ Imekubaliwa │ └──────────────────────────────────────┘ Offer Expiry Scenarios Scenario 1 — Expires while buyer is reading: Offer card shows live countdown timer Timer hits 0:00 Card updates: "Imeisha muda" Proceed button disabled automatically Buyer sees: [Omba Bei Mpya] button Scenario 2 — Expires while buyer in checkout: Buyer was on checkout page when offer expired Checkout validates offer at payment time If expired: payment rejected Buyer returned to conversation "Bei yako imeisha muda. Omba bei mpya" Scenario 3 — Seller sends same price again: Allowed — new offer session created New 30-minute timer Both offers visible in thread (old + new) Scenario 4 — Buyer tries to use expired offer link: Deep link from notification opens expired offer Shows: "Bei hii imeisha muda" [Rudi kwa Mazungumzo] button Price Security Rules ✅ Offer price stored server-side only ✅ Checkout validates price from server (not client) ✅ Client cannot manipulate price ✅ Offer is single-use (cannot complete twice) ✅ Offer belongs to specific buyer (others cannot use) ❌ Seller cannot change price after offer sent (must send new offer) ❌ Buyer cannot change price ❌ Public product price never affected 11. Shareable Content What Can Be Shared Into Any DM or Group Content Who can share Restrictions ──────────────────────────────────────────────────────────── Text message Anyone None Voice note Anyone Max 2 min (basic) Image/Video Anyone Size limits Product card Anyone Shows public price Custom price offer Seller only Private — NOT forwardable Event card Anyone None Bei ya pamoja card Anyone None VP Feed post Anyone None VP Live stream Anyone None Audio Space Anyone None File/Document Anyone Max 100MB Forwarding Rules Forward chain tracking: chain 1: "↪ Imetumwa kutoka Juma Mwangi" chain 2-4: "↪ Imetumwa" chain 5+: "↪ Imetumwa mara nyingi" (misinformation warning — different icon) Multi-forward limit: Max 5 conversations per forward action Prevents spam broadcasting Cannot forward: Custom price offers (private deal) Order confirmations (private record) Payment confirmations (private record) System messages 12. Message Interactions Editing Messages Rules: ✅ Only original sender can edit ✅ Text messages only (not media captions yet) ✅ Within 15 minutes of sending ✅ Shows "Imehaririwa" label after edit ✅ Original send time stays the same ✅ Works in group chats (sender edits their own) ❌ Commerce cards cannot be edited (immutable) ❌ System messages cannot be edited ❌ Voice notes cannot be edited ❌ After 15 minutes: edit option disappears UI: Long press message → [Hariri] option (within 15 min) After edit: message updates in place "Imehaririwa" label appears below message Position in thread unchanged (no jump to bottom) Deleting Messages Delete for Me: ✅ Any message, any time, no limit ✅ Only removed from your view ✅ Recipient still sees it ✅ Works on any message type Delete for Everyone: ✅ Only original sender ✅ Within 15 minutes of sending ✅ Removed from all screens ✅ Shows: "Ujumbe huu umefutwa" ✅ Works in group chats ❌ Commerce cards: NOT allowed ❌ System messages: NOT allowed ❌ After 15 minutes: option disappears Nothing is ever permanently deleted: Soft delete only For legal compliance + dispute resolution Admin can view deleted messages for support cases Users cannot recover deleted messages Reactions Rules: ✅ Any message can be reacted to ✅ One reaction per user per message ✅ Change reaction: send new emoji (replaces old) ✅ Remove reaction: tap same emoji again ✅ Works on commerce cards (reactions don't modify content) ❌ System messages: no reactions Available emojis at launch: ❤️ 👍 😂 😮 😢 🙏 Expand to full emoji keyboard: Phase 3 Group reaction display: 1 type: "👍 3" 2 types: "👍 3 ❤️ 2" 3+ types: "👍 3 ❤️ 2 +2 zaidi" Tap reaction to see who reacted: Bottom sheet opens List of names per emoji Replying to Messages Rules: ✅ Anyone in conversation can reply to any message ✅ Reply shows quoted original above new message ✅ Tap quote → scrolls to original ✅ Works in group chats ✅ Works on any message type ❌ Cannot reply to deleted messages (shows: "Ujumbe umefutwa") UI: Swipe right on message → reply mode OR long press → [Jibu] option Quote appears in input field Send normally Forwarding Rules: ✅ Anyone can forward allowed content ✅ Max 5 conversations per forward action ✅ Forward chain tracked and shown ✅ Original sender name shown (chain 1 only) ✅ Media: references original file (no re-upload) ❌ Custom price offers: not forwardable ❌ Order/payment records: not forwardable ❌ System messages: not forwardable UI: Long press message → [Tuma] option Conversation picker opens Select up to 5 conversations Tap send 13. Voice & Video Call Flows Initiating a Call Kibuti taps call button on Juma's profile or conversation: │ Permission check: Relationship exists? ✅ Juma's privacy allows? ✅ Kibuti not blocked? ✅ │ TURN credentials generated (server) │ Juma's phone rings: ┌──────────────────────────────────────┐ │ │ │ 📞 Simu Inayoingia │ │ │ │ [Kibuti Mwangi] │ │ @kibuti │ │ │ │ [❌ Kataa] [✅ Jibu] │ │ │ └──────────────────────────────────────┘ Works even if: App is closed (FCM HIGH wakes it) Screen is locked (full screen notification) App is in background During a Call — Controls Voice call controls: 🔇 Mute/unmute microphone 🔊 Speaker on/off 📷 Enable camera (upgrade to video) ❌ End call Video call controls: 🔇 Mute/unmute microphone 📷 Camera on/off 🔄 Switch camera (front/rear) 🖥️ Share screen 🔊 Speaker on/off ❌ End call Switching Audio ↔ Video Voice → Video: Kibuti taps camera button during voice call Juma sees: "Kibuti anataka kuongeza video" Auto-accepted (based on Juma's settings) OR Juma taps Accept Video starts — same call session continues Audio uninterrupted during upgrade Video → Audio (manual): Kibuti taps camera OFF Video stops immediately for both Audio continues No renegotiation needed Video → Audio (automatic): Network degrades below video threshold Video disabled automatically Banner shown: "Video imezimwa — mtandao dhaifu" Audio continues Video resumes when network improves Screen Sharing Start screen share: Tap screen share icon during video call System permission dialog appears (Android/iOS) "Ruhusu NexGate kunasa skrini yako?" User accepts Screen share starts Other party sees your screen During screen share: Your camera: small PiP (picture in picture) Their view: your screen (large) + your face (small) Your view: normal call view + "Unaonyesha skrini" banner Stop screen share: Tap stop button Returns to normal video call Call Quality Indicators Signal bars shown during call: ████ Excellent (WiFi / 4G strong) ███░ Good (4G) ██░░ Fair (3G) — may show quality banner █░░░ Poor (2G) — video disabled, audio only ░░░░ Very poor — "Mtandao dhaifu sana" banner Quality banner examples: "Ubora wa sauti umepungua kwa sababu ya mtandao" "Video imezimwa — data ndogo" "Unaunganika tena..." Call End Scenarios Normal end: One party taps end Other party sees call ended Duration shown in conversation: "Simu ya dakika 4:32" Declined: Juma taps Kataa Kibuti sees: "Simu ilikataliwa" Missed call notification NOT sent (was declined) No answer (timeout 45 seconds): Kibuti sees: "Hakujibu" Juma sees: "Simu iliyokosekana kutoka Kibuti" notification Network failure: Both lose connection App attempts reconnect (10 seconds) If reconnect fails: Call marked as FAILED "Simu ilikatizwa" shown to both Kibuti can redial 14. Group Call Flows Starting a Group Call From a group chat: Tap call icon in group header Choose: Voice only OR Video All group members receive incoming call notification Members who join → enter call Members who don't → miss it (missed call shown) From a 1:1 conversation: Not supported directly Must create group first OR use "Add person" button during active 1:1 call Add person to active 1:1 call: During call → tap "Ongeza Mtu" Pick from allowed contacts They receive group call invitation They join → 1:1 becomes group call Group Call Limits Voice only group call: Max 8 participants (comfortable for 3G) Up to 12 possible but discouraged on EA networks Video group call: Max 4 video feeds shown simultaneously 5th person onwards: audio only tile shown Active speaker highlighted (larger tile) Tap any tile to pin/feature them Layout options: Grid view: all tiles equal size Speaker view: active speaker large, others small Auto: switches based on who is talking Group Call Permission Rules Within a group chat: Any member can start group call ✅ Any member can join ✅ No extra permission check needed (group membership = call permission) Adding someone outside the group: Same call permission check as 1:1 Must have relationship (contact/follower/commerce) If no relationship → cannot add 15. Offline & Notification Flows Message Notification Levels Level When FCM SMS after ────────────────────────────────────────────────────────────── CRITICAL Order placed/paid/failed ✅ 0 min Delivery update Payment confirmation IMPORTANT Commerce DM from buyer ✅ 10 min Custom price offer received Bei ya pamoja threshold reached Call missed (commerce context) NORMAL Regular DM ✅ Never Group message Reaction Follow notification Offline Message Delivery User offline — message sent to them: │ ├── FCM HIGH priority push fired immediately │ (all message levels) │ ├── CRITICAL: Textfy SMS sent simultaneously │ ├── IMPORTANT: Textfy SMS after 10 min │ (if FCM not acknowledged) │ └── Message queued in RabbitMQ User comes back online: │ ├── WS connects → presence registered ├── Queued messages drained (priority order) │ CRITICAL first → IMPORTANT → NORMAL │ └── Catch-up banner shown: "Umekosa: maagizo 2, ujumbe 8" [Angalia Maagizo] [Ona Ujumbe] Textfy SMS Templates Order placed (to seller): "NexGate: Agizo jipya kutoka [Buyer]! TZS [amount]. Kagua: nexgate.app/orders/[id]" Payment received: "NexGate: Malipo ya TZS [amount] yamepokelewa kutoka [Buyer]. nexgate.app/wallet" Commerce DM (to seller): "NexGate: [Buyer] anakuuliza kuhusu [Product]. Jibu: nexgate.app/chat/[id]" Bei ya pamoja: "NexGate: Watu [n]/[target] wamejiunga! nexgate.app/group-buy/[id]" All SMS: Swahili first ✅ Deep link included ✅ Shop name shown (not staff name) ✅ 16. Privacy & Safety Privacy Settings Matrix Setting Options Default ──────────────────────────────────────────────────────────────── Who can message me Everyone / Followers Followers + Contacts / Contacts + Contacts / Nobody Who can call me Followers+Contacts / Contacts Contacts / Nobody only Last seen Everyone / Contacts / Contacts Nobody Profile picture Everyone / Contacts / Everyone Nobody Be found by phone number On / Off On Contact sync On / Off Off Read receipts (blue ticks) On / Off On (off = others see delivered but not read) Block System User A blocks User B: User B cannot: ❌ See User A's profile ❌ Send messages to User A ❌ Call User A ❌ See User A in search ❌ See User A's VP Feed posts ❌ See User A's online status User B sees: Profile: "Mtumiaji huyu hayupo" Messages: appear sent but never delivered User A can: ✅ Unblock anytime from Settings ✅ See User B's profile still (A blocked B — not reverse) Group chats: If in same group: messages visible but cannot DM or call each other directly Admin can remove either from group Report System Report options: Spam Harassment / Vitisho Inappropriate content Fake account Scam / Udanganyifu Other Report flow: Long press message → [Ripoti] OR profile → [...] → [Ripoti] Choose reason Optional: add description Submit After report: User not notified they were reported Report goes to NexGate moderation queue Automatic temporary restrictions may apply for high-volume reporters Block on report: "Ripoti na Zuia" option available Blocks immediately + sends report Safety for Women — Specific Features This is important for EA platform trust: Silence unknown callers: ON by default for new accounts Calls from non-contacts ring silently User sees missed call — no disruption Call rate limiting: 3 unanswered calls per day to same person Automatic block after 4th attempt Quick block during call: One tap visible during any call Ends + reports + blocks in single action Message request system: Strangers cannot freely DM Must send request first User controls who enters their inbox Default privacy settings: New accounts: strict defaults Users open up if they choose Better to protect by default 17. Shop Inbox & Staff Access Shop Tiers Basic shop (free): Owner manages inbox alone No staff assignment One active stream at a time Standard features Pro shop (paid): Staff roles unlocked Multiple staff in inbox Advanced analytics Priority support Audit logs Staff Roles Role Inbox Products Analytics Settings Staff mgmt ────────────────────────────────────────────────────────────────── OWNER ✅ ✅ ✅ ✅ ✅ MANAGER ✅ ✅ ✅ ❌ ❌ SUPPORT_AGENT ✅ ❌ ❌ ❌ ❌ READ_ONLY 👁️ view ❌ ❌ ❌ ❌ Staff Identity Rules Staff responds to customer: Customer sees: "TechStore" (shop name) Customer NEVER sees: "Amina" (staff name) Staff identity is internal only Audit log (internal): Which staff member responded Timestamp Visible to OWNER and MANAGER only Not visible to customers Staff cannot: ❌ Reveal personal phone number to customers ❌ Switch conversation to personal DM ❌ Access owner's personal inbox ❌ Access other shops they're not assigned to Multiple Shops — Inbox Separation Owner with 3 shops: Each shop = separate inbox tab Each shop = separate conversation records Each shop = separate staff assignments Staff for Shop A cannot see Shop B Owner sees all (as owner of all) Commerce DM routing: Buyer messages about Product A (TechStore product) → Goes to TechStore inbox → NOT to ClothingHub inbox → NOT to owner's personal inbox Correctly routed by product ownership 18. Notification Settings Per-Conversation Settings Each conversation has: Notifications: ○ All messages ○ Mentions only (groups) ○ Muted (until: 8 hours / 1 week / forever) Media auto-download: ○ WiFi only ○ WiFi + Mobile data ○ Never Global Notification Settings Message notifications: On / Off Call notifications: On / Off Reaction notifications: On / Off Group notifications: On / Off Commerce notifications: On / Off (cannot turn off CRITICAL) Sound: Default / Custom / Silent Vibration: On / Off In-app preview: Show / Hide content CRITICAL Notifications — Always On These cannot be turned off by user: Order placed (seller receives) Payment confirmed (buyer receives) Payment failed (buyer receives) Order cancelled (both receive) Reason: Financial events User could miss critical money information Platform liability without guaranteed delivery Textfy SMS fallback ensures they always arrive 19. Edge Cases & Scenarios Messaging Edge Cases User deletes their account: Their messages remain visible in conversations Name shows: "Mtumiaji aliyefuta akaunti" Profile picture: default avatar Cannot be messaged or called User changes username: All conversations update automatically Old username links still work (redirect) No broken references Very long message (>4000 chars): Truncated in thread: first 200 chars + "...Soma zaidi" Tap to expand full message Not split into multiple messages Same message sent twice (duplicate): Detected by temp_id Only one stored in DB User sees single message (not duplicate) Message sent to blocked user: Appears sent (single tick) Never delivered (stays at single tick) User not informed of block Commerce Edge Cases Product goes out of stock while offer pending: Offer still valid (was frozen at send time) Checkout validates stock at payment time If out of stock at payment: Payment rejected "Bidhaa hii imeisha" Buyer returned to conversation Seller notified to resend offer or cancel Product price changes while offer pending: Offer price locked at creation ✅ Public price change does NOT affect offer Buyer pays the offer price always Seller deletes product while offer pending: Offer still valid (snapshot frozen) Checkout validates product existence If product deleted at payment: Payment rejected "Bidhaa hii haipatikani tena" Two buyers get offers for last item: Both offers exist simultaneously First to complete checkout gets the item Second buyer's payment rejected: "Bidhaa hii imeisha" Standard e-commerce race condition handling Seller sends offer to wrong person: Cannot retract offer Offer expires naturally Seller can contact NexGate support if urgent Buyer in checkout when offer expires: Payment attempt fails "Bei yako imeisha muda" Must request new offer from seller Call Edge Cases Call drops mid-conversation: WebRTC detects loss Auto-reconnect attempted (10 seconds) If reconnect success: call continues If reconnect fails: call ended Both see: "Simu ilikatizwa" Kibuti can redial immediately Both call each other simultaneously: Race condition — both see "Simu inayoingia" System picks one (first to reach server) Other cancelled automatically One call established Call during active call: Second call: goes to missed calls Busy signal not sent (no UX for this) After first call: notification of missed call Phone runs out of battery during call: WebRTC detects disconnect Same as network drop Other party sees: "Simu ilikatizwa" Someone calls during Do Not Disturb (DND): DND on device: depends on device DND rules NexGate mute: call goes to missed calls silently CRITICAL commerce calls: bypass mute (configurable) Group Chat Edge Cases Owner leaves group: Must transfer ownership first OR system auto-assigns to oldest admin OR if no admins: oldest member becomes owner Last person leaves group: Group archived automatically Messages preserved for 30 days Then permanently deleted Adding member who blocked you: Cannot add blocked users to groups System rejects silently No error shown (privacy) Member blocked in group: They stay in group (cannot remove via block) Cannot DM each other Can both still see group messages Admin can remove either from group Summary NexGate messaging is built for East African social commerce — where every conversation can become a transaction, and every transaction has a conversation behind it. The permission system is designed to be safe by default: contacts and mutual followers can communicate freely, strangers go through message requests, and calls require an established relationship. Commerce contexts create natural communication permissions — buyers and sellers can always reach each other through shop identities that protect personal privacy. Contact sync is optional, privacy-preserving (hashed on device), and exists alongside multiple other discovery mechanisms. NexGate does not need contact sync to function — it is one convenience feature among many. Commerce offer sessions are the unique heart of NexGate messaging — a formal negotiated deal between a specific buyer and seller, with a locked price, expiry timer, and full lifecycle tracking. The public product price is never affected. Checkout always happens outside the inbox. Everything is immutable for legal and dispute reasons. The safety system protects users (especially women) through strict defaults, rate limiting, quick block options, and a message request system that gives users control over who enters their inbox. NexGate Messaging — Product Requirements & Feature Flows v1.0 QBIT SPARK | Rules · Flows · Permissions · Scenarios · Edge Cases