Communications Centre
Communications Centre
The Communications Centre provides a structured outbound messaging system for block managers to send and track communications to leaseholders. All communications are logged with a full audit trail covering who sent what, to whom, and when.
Communication Types
| Type | Description |
|---|---|
circular | General information sent to all leaseholders in a block |
notice | Formal notices (e.g. Section 20 consultation, insurance renewal) |
demand_letter | Service charge demands, ground rent demands, arrears letters |
agm_notice | Annual General Meeting invitations and agendas |
Lifecycle
Communications follow a one-way status progression:
draft → scheduled → sent
↓
failed
- draft — Created but not yet sent. Can be edited or deleted.
- scheduled — Has a future
scheduledAttimestamp. Can still be edited. - sent — Marked as sent with a
sentAttimestamp. Immutable — cannot be edited or deleted. - failed — Delivery failed before sending completed.
Audit trail: Once a communication is marked as
sent, it becomes a permanent record. The platform enforces this — theupdateanddeleteprocedures will reject any request targeting a sent communication.
Scoping
Each communication can be scoped to:
- A block — for block-wide circulars sent to all units
- A specific unit — for individual notices to a single leaseholder
- Neither — for organisation-level drafts
The block or unit must belong to the calling organisation; the API validates this on creation.
Delivery Channels
The channel field records how the communication was sent. Supported values include email, post, portal, or any custom string up to 50 characters. Defaults to email.
Recipient Tracking
Recipients are added to a communication using the addRecipients procedure. Each recipient maps to a leaseholder unit.
At the time of adding, the system snapshots:
recipientName— the leaseholder's name at that momentrecipientEmail— the leaseholder's email at that moment
This snapshot is preserved even if the leaseholder's details change later, ensuring the audit record is accurate.
Delivery Status
Each recipient record tracks an independent delivery status:
| Status | Meaning |
|---|---|
pending | Added but not yet delivered |
delivered | Successfully delivered; deliveredAt timestamp recorded |
bounced | Delivery attempted but bounced |
failed | Delivery failed; failureReason field populated |
opened | Recipient opened/read the communication; openedAt timestamp recorded |
API Reference
All procedures are on the communication tRPC router.
communication.list
Paginated list of communications for the organisation.
Access: Org member
Filters:
blockId— scope to a specific blockunitId— scope to a specific unitcommunicationType— filter by typestatus— filter by lifecycle status
communication.getById
Fetch a single communication by ID. Returns the communication record plus a recipientCount.
Access: Org member
communication.create
Create a new communication as a draft.
Access: Admin
Input:
{
communicationType: "circular" | "notice" | "demand_letter" | "agm_notice";
subject: string; // max 500 chars
bodyHtml?: string; // HTML content for email/PDF rendering
blockId?: string; // must belong to org
unitId?: string; // must belong to org
channel?: string; // default: "email"
scheduledAt?: string; // ISO datetime — sets status to "scheduled"
notes?: string; // internal reference notes
}
If scheduledAt is provided, the communication is created with status scheduled; otherwise it is draft.
communication.update
Edit a draft or scheduled communication. Sent communications cannot be edited.
Access: Admin
Editable fields: subject, bodyHtml, channel, scheduledAt, notes
Setting
scheduledAttonullmoves the status back todraft. Setting it to a datetime moves it toscheduled.
communication.markSent
Transition a communication to sent status. Records sentAt timestamp. The communication becomes immutable after this call.
Access: Admin
communication.delete
Delete a draft or scheduled communication. Also removes all associated recipient records.
Access: Admin
Sent communications cannot be deleted — they are part of the audit trail.
communication.addRecipients
Bulk-add leaseholder units as recipients. Snapshots name and email from each unit at the time of the call.
Access: Admin
Input:
{
communicationId: string;
unitIds: string[]; // at least 1
}
Unit IDs that do not belong to the organisation are silently skipped. If none are valid, the call returns a BAD_REQUEST error.
Cannot add recipients to a sent communication.
communication.listRecipients
Paginated list of recipients for a given communication.
Access: Org member
Filters: deliveryStatus
communication.updateRecipientStatus
Update the delivery status of a single recipient record. Automatically records deliveredAt or openedAt timestamps where applicable.
Access: Admin
Input:
{
id: string;
deliveryStatus: "pending" | "delivered" | "bounced" | "failed" | "opened";
failureReason?: string; // populated when status is "bounced" or "failed"
}