Nice-to-haves:
# Web sockets
## Update status
Route: /status/{userClientId}/update
## Receive notification
Route: /status/{userClientId}/notification
# REST
## Get status for user
Route: GET /status/{userClientId}
## Get statuses for multiple users
Route: GET /status/group/
DTO would have a list of all needed users (by unique identifier)
## Add user
Route: POST /users/register
## Verify user registration
Route: POST /users/{userClientId}/registration/verify
## Login user
Route: GET /users/{userClientId}/login
## Add friend
Route: POST /users/{userClientId}/friends/add
## Add friend
Route: POST /users/{userClientId}/friends/remove
The core system would have 5 specialized services, 3 REST services and 2 web socket services. 3 REST services would be: Status provider service, registration/login service and friend service.
2 web socket services would be: Status update service and notification service.
The data would be stored in one main DB which is the source of truth for all states of the system: existing user accounts, statuses for all users and friend relations.
From the main DB, multiple read replicas would exist by need (with always one at least), and these would be used for reading. This separation means some latency for user updates, but this seems acceptable.
Front for clients would be an API gateway that has the role of authenticating users, providing SSO, rate limiting, integrating with 3rd party identity providers.
Status update service would be the main service that performs live status updates for users. When a user state changes, this service would be used to provide updates to the main DB.
Status provider service would be the main service that provides statuses. The clients would request statuses by need with Request-Response model, the service would receive the requests, try to read out the needed users statuses from cache. If the cache does not exist, the service would access one of the read replicas and return statuses.
Registration/login service would be a REST service that provides manipulation to user accounts. User would use this to register, verify registration or login.
Friend service would be a REST service used for manipulating "friends", or rather user authorized to access other users status. It would have add friend, remove friend and confirm friend request.
Notification service would be a server-sent events service used to push notifications to clients, such as "you have a friend request".
Separation of databases by read and write would enable high availability of data for all users. The read replicas would be frequently updated in batch changes (each 1s or few at worst).
Between the client and the services would be an API gateway that can handle request limiting, control connection, provide necessary load balancing.
User flow:
User would be greeted by a login/registration screen and SSO options. After login is achieved, the system would establish a dual connection with the Status update service and the client-side activity detector would start tracking the users activity. The user status would be marked as "online".
Connection with the Status update service would be of limited short time. After this time passes, if the user is still active, the connection would be reopened or maintained and the user would be kept in the "online" status. If the connection is lost and the user is not active, the service would update the user state to "offline". If the user has an active connection, but the Activity detector sees the user is not active on the client side, it would send an update through the duplex connection and the user would be marked as "idle". If the user logs out or exist the application, the connection will send an update to status to "offline" before finishing logout/exit and the connection will drop.
Connection with the Notification service would be based on the user activity - each time the user is active and in "online" status, the connection would be up. If it times out but the user is active, the connection is reestablished. Once the user becomes inactive or logs out, the connections is dropped.
For viewing other users statuses, the users need to be friends and thus have authorization to view each others statuses.
When checking other users or groups of users, a request would be sent to the Status provider service, which would return an adequate response for this/those user/s.
If the user wants to create an account with the service or logs in using an existing account, adequate requests would be sent to the Registration/login service.
If the user wants to add a friend, client will send requests through the friend service and provide adequate responses. This will, after the read replica is synced, send to the user 2 which was added as a friend a "friend request" notification through the Notification service. Once the user 2 accepts or declines the friend request, the update would be sent through the friend service to the main DB. Once the replica is synced, the notification service will provided the notification about the accepted/declined friend request to the original user.
Main database - Main DB, would be the source of through. It would only be used for inserting or updating required data about users, like user accounts and related details, friend relations between users or current status. This would provide a secure and scalable way to the source of truth, since updates and inserts frequently require only row locks, which in term leaves other rows available. The database would also maintain relationships between entities, such as user friends.
The main database would have read replicas that can scale out by need - the more requests there are at a give time, to more read replicas can be provided.
The Activity detector would be tracking user activities such as mouse movement, keyboard strokes or utilizing the UI of the app. Depending on the type of client being used, the Activity detector could be a WebWorker for web apps or a background service for desktop apps. After non of the activities are detected in some time, the activity detector would call the Status update service and update the status for the user to "idle".
The friend relations would have three active parts: providing friend details through GET requests, adding the details through POST requests and receiving updates about new friend request or accepted/declined friend requests.