Files
clientsflow/frontend/graphql/schema.graphql
Ruslan Bakiev 5492e0d05c feat: unread message tracking with blue dot indicator
Add ContactThreadRead model to track when users last viewed each contact thread.
Contacts with messages newer than the last read time show a blue dot in the sidebar.
Opening a thread automatically marks it as read via markThreadRead mutation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 20:25:32 +07:00

279 lines
5.3 KiB
GraphQL

type Query {
me: MePayload!
chatMessages: [PilotMessage!]!
chatConversations: [Conversation!]!
contacts: [Contact!]!
communications: [CommItem!]!
contactInboxes: [ContactInbox!]!
calendar(dateRange: CalendarDateRange): [CalendarEvent!]!
deals: [Deal!]!
feed: [FeedCard!]!
pins: [CommPin!]!
documents: [WorkspaceDocument!]!
getClientTimeline(contactId: ID!, limit: Int): [ClientTimelineItem!]!
}
type Mutation {
login(phone: String!, password: String!): MutationResult!
logout: MutationResult!
createChatConversation(title: String): Conversation!
selectChatConversation(id: ID!): MutationResult!
archiveChatConversation(id: ID!): MutationResult!
sendPilotMessage(text: String!): MutationResult!
confirmLatestChangeSet: MutationResult!
rollbackLatestChangeSet: MutationResult!
rollbackChangeSetItems(changeSetId: ID!, itemIds: [ID!]!): MutationResult!
logPilotNote(text: String!): MutationResult!
toggleContactPin(contact: String!, text: String!): PinToggleResult!
createCalendarEvent(input: CreateCalendarEventInput!): CalendarEvent!
archiveCalendarEvent(input: ArchiveCalendarEventInput!): CalendarEvent!
createCommunication(input: CreateCommunicationInput!): MutationWithIdResult!
createWorkspaceDocument(input: CreateWorkspaceDocumentInput!): WorkspaceDocument!
deleteWorkspaceDocument(id: ID!): MutationWithIdResult!
updateCommunicationTranscript(id: ID!, transcript: [String!]!): MutationWithIdResult!
updateFeedDecision(id: ID!, decision: String!, decisionNote: String): MutationWithIdResult!
setContactInboxHidden(inboxId: ID!, hidden: Boolean!): MutationResult!
markThreadRead(contactId: ID!): MutationResult!
}
type MutationResult {
ok: Boolean!
}
type MutationWithIdResult {
ok: Boolean!
id: ID!
}
type PinToggleResult {
ok: Boolean!
pinned: Boolean!
}
input CalendarDateRange {
from: String
to: String
}
input CreateCalendarEventInput {
title: String!
start: String!
end: String
contact: String
note: String
archived: Boolean
archiveNote: String
}
input ArchiveCalendarEventInput {
id: ID!
archiveNote: String
}
input CreateCommunicationInput {
contact: String!
channel: String
kind: String
direction: String
text: String
audioUrl: String
at: String
durationSec: Int
transcript: [String!]
}
input CreateWorkspaceDocumentInput {
title: String!
owner: String
scope: String!
summary: String!
body: String
}
type MePayload {
user: MeUser!
team: MeTeam!
conversation: Conversation!
}
type MeUser {
id: ID!
phone: String!
name: String!
}
type MeTeam {
id: ID!
name: String!
}
type Conversation {
id: ID!
title: String!
createdAt: String!
updatedAt: String!
lastMessageAt: String
lastMessageText: String
}
type PilotMessage {
id: ID!
role: String!
text: String!
messageKind: String
requestId: String
eventType: String
phase: String
transient: Boolean
thinking: [String!]!
tools: [String!]!
toolRuns: [PilotToolRun!]!
changeSetId: String
changeStatus: String
changeSummary: String
changeItems: [PilotChangeItem!]!
createdAt: String!
}
type PilotChangeItem {
id: ID!
entity: String!
entityId: String
action: String!
title: String!
before: String!
after: String!
rolledBack: Boolean!
}
type PilotToolRun {
name: String!
status: String!
input: String!
output: String!
at: String!
}
type ClientTimelineItem {
id: ID!
contactId: String!
contentType: String!
contentId: String!
datetime: String!
message: CommItem
calendarEvent: CalendarEvent
recommendation: FeedCard
document: WorkspaceDocument
}
type Contact {
id: ID!
name: String!
avatar: String!
channels: [String!]!
lastContactAt: String!
lastMessageText: String!
lastMessageChannel: String!
hasUnread: Boolean!
description: String!
}
type CommItem {
id: ID!
at: String!
contactId: String!
contact: String!
contactInboxId: String!
sourceExternalId: String!
sourceTitle: String!
channel: String!
kind: String!
direction: String!
text: String!
audioUrl: String!
duration: String!
waveform: [Float!]!
transcript: [String!]!
deliveryStatus: String
}
type ContactInbox {
id: ID!
contactId: String!
contactName: String!
channel: String!
sourceExternalId: String!
title: String!
isHidden: Boolean!
lastMessageAt: String!
updatedAt: String!
}
type CalendarEvent {
id: ID!
title: String!
start: String!
end: String!
contact: String!
note: String!
isArchived: Boolean!
createdAt: String!
archiveNote: String!
archivedAt: String!
}
type Deal {
id: ID!
contact: String!
title: String!
stage: String!
amount: String!
nextStep: String!
summary: String!
currentStepId: String!
steps: [DealStep!]!
}
type DealStep {
id: ID!
title: String!
description: String!
status: String!
dueAt: String!
order: Int!
completedAt: String!
}
type FeedCard {
id: ID!
at: String!
contact: String!
text: String!
proposal: FeedProposal!
decision: String!
decisionNote: String!
}
type FeedProposal {
title: String!
details: [String!]!
key: String!
}
type CommPin {
id: ID!
contact: String!
text: String!
}
type WorkspaceDocument {
id: ID!
title: String!
type: String!
owner: String!
scope: String!
updatedAt: String!
summary: String!
body: String!
}