Ever since we started bundling the app with webpack, there’s been less and less overlap between our ‘static’ directory (files belonging to the frontend app) and Django’s interpretation of the ‘static’ directory (files served directly to the web). Split the app out to its own ‘web’ directory outside of ‘static’, and remove all the custom collectstatic --ignore rules. This makes it much clearer what’s actually being served to the web, and what’s being bundled by webpack. It also shrinks the release tarball by 3%. Signed-off-by: Anders Kaseorg <anders@zulip.com>
		
			
				
	
	
	
		
			2.9 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Presence
This document explains the model for Zulip's presence.
In a chat tool like Zulip, users expect to see the “presence” status of other users: is the person I want to talk to currently online? If not, were they last online 5 minutes ago, or more like an hour ago, or a week? Presence helps set expectations for whether someone is likely to respond soon. To a user, this feature can seem like a simple thing that should be easy. But presence is actually one of the hardest scalability problems for a team chat tool like Zulip.
There's a lot of performance-related details in the backend and network protocol design that we won't get into here. The focus of this is what one needs to know to correctly implement a Zulip client's presence implementation (e.g. web app, mobile app, terminal client, or other tool that's intended to represent whether a user is online and using Zulip).
A client should report to the server every minute a POST request to
/users/me/presence, containing the current user's status. The
requests contains a few parameters. The most important is "status",
which had 2 valid values:
- "active" -- this means the user has interacted with the client recently.
 - "idle" -- the user has not interacted with the client recently. This is important for the case where a user left a Zulip tab open on their desktop at work and went home for the weekend.
 
The client receives in the response to that request a data set that, for each user, contains their status and timestamp that we last heard from that client. There are a few important details to understand about that data structure:
- It's really important that the timestamp is the last time we heard from the client. A client can only interpret the status to display about another user by doing a simple computation using the (status, timestamp) pair. E.g. a user who last used Zulip 1 week ago will have a timestamp of 1 week ago and a status of "active". Why? Because this correctly handles the race conditions. For example, if the threshold for displaying a user as "offline" was 5 minutes since the user was last online, the client can at any time accurately compute whether that user is offline (even if the last data from the server was 45 seconds ago, and the user was last online 4:30 before the client received that server data).
 - Users can disable their own presence updates in user settings
(
UserProfile.presence_enabledis the flag storing this user preference). - The 
status_from_timestampfunction inweb/src/presence.jsis useful sample code; theOFFLINE_THRESHOLD_SECScheck is critical to correct output. - We provide the data for e.g. whether the user was online on their desktop or the mobile app, but for a basic client, you will likely only want to parse the "aggregated" key, which shows the summary answer for "is this user online".