diff options
author | Calvin Morrison <calvin@pobox.com> | 2025-09-03 21:15:36 -0400 |
---|---|---|
committer | Calvin Morrison <calvin@pobox.com> | 2025-09-03 21:15:36 -0400 |
commit | 49fa5aa2a127bdf8924d02bf77e5086b39c7a447 (patch) | |
tree | 61d86a7705dacc9fddccc29fa79d075d83ab8059 /draft-jchat-00.txt |
Diffstat (limited to 'draft-jchat-00.txt')
-rw-r--r-- | draft-jchat-00.txt | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/draft-jchat-00.txt b/draft-jchat-00.txt new file mode 100644 index 0000000..d044940 --- /dev/null +++ b/draft-jchat-00.txt @@ -0,0 +1,745 @@ +Internet Engineering Task Force (IETF) C. Smith +Internet-Draft Fastmail +Intended status: Standards Track August 15, 2025 +Expires: February 16, 2026 + + + The JSON Chat Application Protocol (JCHAT) + draft-jchat-00 + +Abstract + + This document specifies a protocol for real-time chat messaging + built on top of the JSON Meta Application Protocol (JMAP) [RFC8620]. + JCHAT provides a standardized way to exchange chat messages, + manage conversations, handle user presence, and synchronize chat + state across multiple devices efficiently. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on February 16, 2026. + +Copyright Notice + + Copyright (c) 2025 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 3 + 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. JCHAT Capability . . . . . . . . . . . . . . . . . . . . . . 4 + 3. Data Types . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 3.1. Conversation . . . . . . . . . . . . . . . . . . . . . . 5 + 3.2. Message . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 3.3. Participant . . . . . . . . . . . . . . . . . . . . . . . 10 + 3.4. Presence . . . . . . . . . . . . . . . . . . . . . . . . 11 + 4. Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 4.1. Conversation Methods . . . . . . . . . . . . . . . . . . . 12 + 4.1.1. Conversation/get . . . . . . . . . . . . . . . . . . . 12 + 4.1.2. Conversation/set . . . . . . . . . . . . . . . . . . . 13 + 4.1.3. Conversation/changes . . . . . . . . . . . . . . . . . 15 + 4.1.4. Conversation/query . . . . . . . . . . . . . . . . . . 15 + 4.2. Message Methods . . . . . . . . . . . . . . . . . . . . . 17 + 4.2.1. Message/get . . . . . . . . . . . . . . . . . . . . . 17 + 4.2.2. Message/set . . . . . . . . . . . . . . . . . . . . . 18 + 4.2.3. Message/changes . . . . . . . . . . . . . . . . . . . 20 + 4.2.4. Message/query . . . . . . . . . . . . . . . . . . . . 20 + 4.3. Participant Methods . . . . . . . . . . . . . . . . . . . 22 + 4.3.1. Participant/get . . . . . . . . . . . . . . . . . . . 22 + 4.3.2. Participant/set . . . . . . . . . . . . . . . . . . . 23 + 4.3.3. Participant/changes . . . . . . . . . . . . . . . . . 24 + 4.4. Presence Methods . . . . . . . . . . . . . . . . . . . . . 25 + 4.4.1. Presence/get . . . . . . . . . . . . . . . . . . . . . 25 + 4.4.2. Presence/set . . . . . . . . . . . . . . . . . . . . . 26 + 5. Push Notifications . . . . . . . . . . . . . . . . . . . . . 27 + 6. Security Considerations . . . . . . . . . . . . . . . . . . . 28 + 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 29 + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 29 + 8.1. Normative References . . . . . . . . . . . . . . . . . . . 29 + 8.2. Informative References . . . . . . . . . . . . . . . . . . 30 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 30 + +1. Introduction + + Modern chat applications require real-time message delivery, + efficient synchronization across multiple devices, and robust + handling of conversations with multiple participants. The JSON + Meta Application Protocol (JMAP) [RFC8620] provides an excellent + foundation for building such applications with its efficient + delta synchronization, push notifications, and batched operations. + + JCHAT builds upon JMAP to provide: + + o Structured conversation management with metadata + o Real-time message delivery and synchronization + o Participant management and permissions + o User presence information + o Message threading and replies + o Rich message content including attachments + o Message delivery receipts and read status + + This specification defines the data model and methods for a + chat system that can scale from simple one-on-one messaging + to large group conversations while maintaining the efficiency + benefits of JMAP. + +1.1. Notational Conventions + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + The underlying format used for this specification is JSON. + Consequently, the terms "object" and "array" as well as the four + primitive types (strings, numbers, booleans, and null) are to be + interpreted as described in Section 1 of [RFC8259]. + + Type signatures follow the conventions established in [RFC8620]. + +1.2. Terminology + + Conversation: A container for messages between one or more + participants. Conversations have metadata such as a title, + creation time, and participant list. + + Message: A single communication within a conversation, containing + text content, metadata, and optionally attachments or replies + to other messages. + + Participant: A user who is a member of a conversation and can + send and receive messages within that conversation. + + Presence: Information about a user's current availability status + and activity. + +2. JCHAT Capability + + The JCHAT capability is identified by the URI: + + "urn:ietf:params:jmap:chat" + + This capability is advertised in the "capabilities" object of + the JMAP Session response. The value of this capability in the + capabilities object MUST be an object with the following properties: + + o maxConversationsPerAccount: "UnsignedInt|null" + The maximum number of conversations allowed per account. + If null, there is no limit. + + o maxParticipantsPerConversation: "UnsignedInt|null" + The maximum number of participants allowed in a single + conversation. If null, there is no limit. + + o maxMessageLength: "UnsignedInt|null" + The maximum length in UTF-8 octets of a message body. + If null, there is no limit. + + o supportedMessageTypes: "String[]" + A list of message content types supported by the server. + MUST include "text/plain". MAY include "text/html", + "text/markdown", and others. + + o maxAttachmentSize: "UnsignedInt|null" + The maximum size in octets of a single attachment. + If null, attachments are not supported. + +3. Data Types + +3.1. Conversation + + A *Conversation* object represents a chat conversation between + one or more participants. It has the following properties: + + o id: "Id" (immutable; server-set) + The id of the conversation. + + o title: "String|null" + A user-defined title for the conversation. If null, clients + SHOULD generate a title from participant names. + + o description: "String|null" + An optional description of the conversation purpose. + + o createdAt: "UTCDate" (immutable; server-set) + The date and time the conversation was created. + + o updatedAt: "UTCDate" (server-set) + The date and time the conversation was last modified. + + o isArchived: "Boolean" (default: false) + Whether this conversation has been archived by the user. + + o isMuted: "Boolean" (default: false) + Whether notifications for this conversation are muted. + + o participantIds: "Id[]" + The list of participant IDs who are members of this + conversation. The order MAY be significant for display purposes. + + o lastMessageId: "Id|null" (server-set) + The ID of the most recent message in this conversation. + null if the conversation has no messages. + + o lastMessageAt: "UTCDate|null" (server-set) + The timestamp of the most recent message in this conversation. + null if the conversation has no messages. + + o unreadCount: "UnsignedInt" (server-set) + The number of unread messages in this conversation for + this user. + + o messageCount: "UnsignedInt" (server-set) + The total number of messages in this conversation. + + o metadata: "String[String]|null" + Application-specific metadata as key-value pairs. + +3.2. Message + + A *Message* object represents a single message within a conversation. + It has the following properties: + + o id: "Id" (immutable; server-set) + The id of the message. + + o conversationId: "Id" (immutable) + The id of the conversation this message belongs to. + + o senderId: "Id" (immutable) + The id of the participant who sent this message. + + o sentAt: "UTCDate" (immutable; server-set) + The date and time the message was sent. + + o receivedAt: "UTCDate" (immutable; server-set) + The date and time the message was received by the server. + + o editedAt: "UTCDate|null" (server-set) + The date and time the message was last edited. null if + never edited. + + o body: "String" + The main content of the message. + + o bodyType: "String" (default: "text/plain") + The MIME type of the message body. Servers MUST support + "text/plain". MAY support "text/html", "text/markdown". + + o attachments: "Attachment[]|null" + A list of file attachments associated with this message. + null if no attachments. + + o replyToMessageId: "Id|null" + The id of the message this message is replying to. + null if not a reply. + + o isSystemMessage: "Boolean" (immutable; default: false) + Whether this is a system-generated message (e.g., user + joined/left conversation). + + o isDeleted: "Boolean" (default: false) + Whether this message has been marked as deleted. + + o reactions: "Reaction[]|null" (server-set) + A list of emoji reactions to this message. null if no reactions. + + o deliveryStatus: "DeliveryStatus" (server-set) + The delivery status of this message. + + o readBy: "MessageRead[]" (server-set) + A list of participants who have read this message. + + o metadata: "String[String]|null" + Application-specific metadata as key-value pairs. + + An *Attachment* object has the following properties: + + o blobId: "Id" + The blob id of the attachment data. + + o name: "String" + The filename of the attachment. + + o type: "String" + The MIME type of the attachment. + + o size: "UnsignedInt" + The size of the attachment in octets. + + A *Reaction* object has the following properties: + + o emoji: "String" + The Unicode emoji character(s) for the reaction. + + o participantIds: "Id[]" + The list of participant IDs who added this reaction. + + A *DeliveryStatus* is a string with one of the following values: + + o "sending": The message is being sent to the server. + o "sent": The message has been accepted by the server. + o "delivered": The message has been delivered to all online + participants. + o "failed": The message failed to send. + + A *MessageRead* object has the following properties: + + o participantId: "Id" + The id of the participant who read the message. + + o readAt: "UTCDate" + When the participant read the message. + +3.3. Participant + + A *Participant* object represents a user's membership in a + conversation. It has the following properties: + + o id: "Id" (immutable; server-set) + The id of the participant record. + + o conversationId: "Id" (immutable) + The id of the conversation. + + o userId: "Id" (immutable) + The id of the user account. + + o displayName: "String" + The display name for this participant in this conversation. + + o avatarBlobId: "Id|null" + The blob id of the participant's avatar image. null if + no custom avatar. + + o role: "String" (default: "member") + The participant's role in the conversation. Possible values: + "owner", "admin", "member", "observer". + + o joinedAt: "UTCDate" (immutable; server-set) + When the participant joined the conversation. + + o lastActiveAt: "UTCDate|null" (server-set) + When the participant was last active in this conversation. + null if never active. + + o isActive: "Boolean" (server-set) + Whether the participant is currently an active member + of the conversation. + + o permissions: "String[]" + The list of permissions this participant has in the + conversation. Possible values: "send", "edit", "delete", + "invite", "remove", "manage". + + o metadata: "String[String]|null" + Application-specific metadata as key-value pairs. + +3.4. Presence + + A *Presence* object represents a user's current availability + status. It has the following properties: + + o userId: "Id" (immutable) + The id of the user account. + + o status: "String" + The user's current status. Possible values: "online", + "away", "busy", "offline". + + o statusMessage: "String|null" + An optional custom status message. + + o lastSeenAt: "UTCDate|null" (server-set) + When the user was last seen online. null if currently online + or privacy settings prevent sharing. + + o updatedAt: "UTCDate" (server-set) + When the presence information was last updated. + +4. Methods + +4.1. Conversation Methods + +4.1.1. Conversation/get + + Standard "/get" method as described in [RFC8620], Section 5.1. + + The following additional properties are supported in the response: + + Additional errors: + + None specific to this method. + +4.1.2. Conversation/set + + Standard "/set" method as described in [RFC8620], Section 5.3. + + When creating a new conversation, the following properties are + required in the create object: + + o participantIds: Must include at least the creating user. + + The following properties MUST NOT be included when creating + a conversation: + + o id, createdAt, updatedAt, lastMessageId, lastMessageAt, + unreadCount, messageCount + + When updating a conversation, the following properties are + immutable and MUST NOT be changed: + + o id, createdAt + + Additional SetErrors: + + o "invalidParticipants": The participantIds list is invalid + (empty, contains non-existent users, etc.). + + o "maxParticipantsExceeded": The conversation would exceed + the maximum number of participants allowed. + + o "insufficientPermissions": The user does not have permission + to perform the requested action on this conversation. + +4.1.3. Conversation/changes + + Standard "/changes" method as described in [RFC8620], Section 5.2. + +4.1.4. Conversation/query + + Standard "/query" method as described in [RFC8620], Section 5.5. + + Supported filter conditions: + + o hasParticipant: "Id" + Matches conversations where the specified user is a participant. + + o isArchived: "Boolean" + Matches conversations with the specified archived status. + + o after: "UTCDate" + Matches conversations with lastMessageAt after this date. + + o before: "UTCDate" + Matches conversations with lastMessageAt before this date. + + o hasUnread: "Boolean" + If true, matches conversations with unreadCount > 0. + If false, matches conversations with unreadCount = 0. + + Supported sort options: + + o "lastMessageAt": Sort by the timestamp of the last message. + o "createdAt": Sort by conversation creation time. + o "title": Sort by conversation title (case-insensitive). + o "unreadCount": Sort by number of unread messages. + + Default sort is "lastMessageAt desc". + +4.2. Message Methods + +4.2.1. Message/get + + Standard "/get" method as described in [RFC8620], Section 5.1. + + Additional errors: + + None specific to this method. + +4.2.2. Message/set + + Standard "/set" method as described in [RFC8620], Section 5.3. + + When creating a new message, the following properties are + required in the create object: + + o conversationId: Must reference an existing conversation. + o body: The message content. + + The following properties MUST NOT be included when creating + a message: + + o id, sentAt, receivedAt, editedAt, reactions, deliveryStatus, + readBy + + The following properties are set by the server when creating: + + o senderId: Set to the authenticated user's participant ID + in the specified conversation. + + When updating a message, the following properties are + immutable and MUST NOT be changed: + + o id, conversationId, senderId, sentAt, receivedAt, + isSystemMessage + + Only the message sender can edit these properties: + + o body, bodyType, attachments + + The server MUST set editedAt when any editable property + is modified. + + Message deletion is handled by setting isDeleted to true. + Servers MAY permanently delete message content after a + retention period. + + Additional SetErrors: + + o "conversationNotFound": The specified conversationId + does not exist. + + o "notParticipant": The user is not a participant in + the specified conversation. + + o "messageNotFound": The message to update does not exist. + + o "cannotEditMessage": The user does not have permission + to edit this message (not the sender, message too old, etc.). + + o "invalidReplyTo": The replyToMessageId references a + non-existent message or a message in a different conversation. + + o "messageTooLarge": The message body exceeds maxMessageLength. + +4.2.3. Message/changes + + Standard "/changes" method as described in [RFC8620], Section 5.2. + +4.2.4. Message/query + + Standard "/query" method as described in [RFC8620], Section 5.5. + + Supported filter conditions: + + o inConversation: "Id" + Matches messages in the specified conversation. + + o from: "Id" + Matches messages sent by the specified participant. + + o after: "UTCDate" + Matches messages sent after this date. + + o before: "UTCDate" + Matches messages sent before this date. + + o hasAttachment: "Boolean" + If true, matches messages with attachments. + + o text: "String" + Matches messages containing this text in the body + (case-insensitive substring search). + + o isUnread: "Boolean" + If true, matches unread messages for this user. + + o replyTo: "Id" + Matches messages that are replies to the specified message. + + Supported sort options: + + o "sentAt": Sort by message timestamp. + o "receivedAt": Sort by server receive timestamp. + + Default sort is "sentAt asc". + +4.3. Participant Methods + +4.3.1. Participant/get + + Standard "/get" method as described in [RFC8620], Section 5.1. + +4.3.2. Participant/set + + Standard "/set" method as described in [RFC8620], Section 5.3. + + When creating a new participant, the following properties are + required in the create object: + + o conversationId: Must reference an existing conversation. + o userId: Must reference an existing user account. + + The following properties MUST NOT be included when creating + a participant: + + o id, joinedAt, lastActiveAt, isActive + + When updating a participant, the following properties are + immutable and MUST NOT be changed: + + o id, conversationId, userId, joinedAt + + Only conversation owners/admins can modify: + + o role, permissions + + Additional SetErrors: + + o "conversationNotFound": The specified conversationId + does not exist. + + o "userNotFound": The specified userId does not exist. + + o "alreadyParticipant": The user is already a participant + in this conversation. + + o "cannotModifyParticipant": The user does not have + permission to modify participants in this conversation. + + o "cannotRemoveSelf": The user cannot remove themselves + from the conversation (use conversation archiving instead). + +4.3.3. Participant/changes + + Standard "/changes" method as described in [RFC8620], Section 5.2. + +4.4. Presence Methods + +4.4.1. Presence/get + + Standard "/get" method as described in [RFC8620], Section 5.1. + + Users can only retrieve presence information for users they + share conversations with, unless broader permissions are granted. + + Additional errors: + + o "cannotAccessPresence": The user does not have permission + to view presence information for the requested users. + +4.4.2. Presence/set + + Standard "/set" method as described in [RFC8620], Section 5.3. + + Users can only update their own presence information. + + The following properties are immutable and MUST NOT be changed: + + o userId, lastSeenAt, updatedAt + + Additional SetErrors: + + o "cannotSetOthersPresence": Attempted to set presence + for a user other than the authenticated user. + +5. Push Notifications + + JCHAT extends JMAP push notifications to provide real-time + updates for chat events. The following state changes trigger + push notifications: + + o New messages in conversations the user participates in + o Changes to conversation metadata + o Participant additions/removals + o Presence updates for users the client is interested in + + Push subscription setup follows the standard JMAP push model + described in [RFC8620], Section 7. + + The push notification payload includes the standard JMAP + StateChange object with the following chat-specific type + changes: + + o "Conversation": Conversation state changes + o "Message": Message state changes + o "Participant": Participant state changes + o "Presence": Presence state changes + + Clients SHOULD subscribe to push notifications for responsive + chat experience and battery efficiency on mobile devices. + +6. Security Considerations + + JCHAT inherits the security model of JMAP [RFC8620] and adds + the following chat-specific considerations: + + o Message Privacy: Messages are only accessible to conversation + participants. Servers MUST enforce participant membership + when processing requests. + + o Participant Management: Only users with appropriate permissions + can add/remove participants or modify conversation settings. + + o Presence Privacy: Presence information should only be shared + with users who share conversations or have explicit permission. + + o Message Retention: Servers SHOULD provide configurable message + retention policies and honor deletion requests. + + o Content Filtering: Servers MAY implement content filtering + for spam, abuse, or regulatory compliance. + + o Rate Limiting: Servers SHOULD implement rate limiting for + message sending to prevent abuse. + +7. IANA Considerations + + This document registers the JMAP Capability for chat as follows: + + Capability Name: urn:ietf:params:jmap:chat + Specification document: This document + Intended use: COMMON + Change controller: IETF + Security and privacy considerations: See Section 6 + +8. References + +8.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + <https://www.rfc-editor.org/info/rfc2119>. + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, + DOI 10.17487/RFC8174, May 2017, + <https://www.rfc-editor.org/info/rfc8174>. + + [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) + Data Interchange Format", STD 90, RFC 8259, + DOI 10.17487/RFC8259, December 2017, + <https://www.rfc-editor.org/info/rfc8259>. + + [RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application + Protocol (JMAP)", RFC 8620, DOI 10.17487/RFC8620, + July 2019, <https://www.rfc-editor.org/info/rfc8620>. + +8.2. Informative References + + [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., + "JavaScript Object Notation (JSON) Pointer", RFC 6901, + DOI 10.17487/RFC6901, April 2013, + <https://www.rfc-editor.org/info/rfc6901>. + +Author's Address + + Calvin Smith + Fastmail + + Email: calvin@fastmail.com |