Business Analysis
Product Requirements Document
Requirements with IDs and status, user stories, and acceptance criteria.
Source: support-system: requirements derived from the implemented system
Support System: Product Requirements Document
Retrospective. These requirements were derived from the built system, not gathered before it. Each requirement carries a status taken from the code: Implemented, Partial, or Not implemented. None has been validated with a customer. Behaviour is specified in detail in the lifecycle specification.
1. Goals and non-goals
Goals
- G1. Give agents one workspace for tickets from every channel.
- G2. Make ticket state, SLA measurement, and assignment rules explicit and inspectable.
- G3. Give supervisors live visibility and control over routing and SLA.
- G4. Keep each workspace's data isolated from every other's.
- G5. Let teams automate first contact with a visual bot builder.
- G6. Expose a documented, safe API for integration.
Non-goals
- AI-generated replies, suggestions, or classification.
- Billing, plans, or usage metering.
- A customer portal with sign-in.
- A hosted, production deployment.
- Single sign-on.
2. Users
Agent, supervisor, workspace administrator, integrator, and customer. See the personas.
3. Requirements
Ticketing (TKT)
| ID | Requirement | Status |
|---|---|---|
| TKT-01 | A ticket has one of six statuses, and only the defined transitions are allowed. | Implemented |
| TKT-02 | Priorities are low, normal, high, urgent. Types are question, incident, problem, task, request. | Implemented |
| TKT-03 | Closed tickets cannot be changed, reassigned, merged, or replied to publicly. | Implemented |
| TKT-04 | A customer reply to a closed ticket creates a linked follow-up ticket. | Implemented |
| TKT-05 | A customer reply reopens pending and solved tickets. It does not change on-hold tickets. | Implemented |
| TKT-06 | Agents can send public replies and internal notes. Notes never affect SLA or status. | Implemented |
| TKT-07 | A reply can set the ticket status in the same operation. | Implemented |
| TKT-08 | Solved tickets close automatically after a configurable period (default 72 hours). | Implemented |
| TKT-09 | Tickets can be merged and linked. Merging closed tickets is rejected. | Implemented |
| TKT-10 | Bulk actions apply to many tickets and report per-ticket results. | Implemented |
| TKT-11 | Concurrent edits are detected through a version check. | Implemented |
| TKT-12 | Every change is written to the ticket's event history. | Implemented |
| TKT-13 | Agents see when another agent is replying to the same ticket. | Implemented |
SLA (SLA)
| ID | Requirement | Status |
|---|---|---|
| SLA-01 | Policies are ordered, and the first active policy whose condition matches applies. | Implemented |
| SLA-02 | Targets are set per priority for first response, next response, and resolution. | Implemented |
| SLA-03 | Targets are measured in business minutes on a calendar with timezone and holidays. | Implemented |
| SLA-04 | Pending and on-hold pause the clocks, and resume moves due dates by the business time paused. | Implemented |
| SLA-05 | A warning fires 15 minutes before a first-response or resolution due time. | Implemented |
| SLA-06 | Breaches are recorded and published as events for escalation. | Implemented |
| SLA-07 | The warning lead time is configurable. | Not implemented (fixed at 15 minutes) |
| SLA-08 | A report of how long tickets spent paused. | Not implemented |
Routing (RTE)
| ID | Requirement | Status |
|---|---|---|
| RTE-01 | Queues use round-robin, least-loaded, or manual assignment. | Implemented |
| RTE-02 | Agents are matched by skill, language, capacity, shift, and presence. | Implemented |
| RTE-03 | A returning customer can be routed to their previous agent, subject to eligibility checks. | Implemented |
| RTE-04 | Every assignment stores a method and a reason. A ticket that cannot be assigned stores why. | Implemented |
| RTE-05 | Queued tickets are retried by priority and age, and can overflow to another queue after a delay. | Implemented |
| RTE-06 | Untouched, auto-assigned tickets can be rebalanced from busy to idle agents. | Implemented |
| RTE-07 | Tickets are released from offline, away, or busy agents according to policy. | Implemented |
| RTE-08 | Policy comes from defaults, workspace, and queue layers, validated on save. | Implemented |
| RTE-09 | Presence has reason codes. | Implemented |
| RTE-10 | Routing suggestions for supervisors based on historic load. | Not implemented |
Channels (CHN)
| ID | Requirement | Status |
|---|---|---|
| CHN-01 | Website chat through an embeddable widget. | Implemented |
| CHN-02 | Email over IMAP and SMTP, or a raw MIME webhook. | Implemented |
| CHN-03 | WhatsApp Cloud API, including the 24-hour window and templates. | Implemented |
| CHN-04 | SMS through Twilio. | Implemented |
| CHN-05 | Voice and CTI call events with click-to-dial. | Implemented |
| CHN-06 | A signed generic API channel. | Implemented |
| CHN-07 | Each channel can start in a bot flow and land in a queue. | Implemented |
| CHN-08 | Attachments stored in object storage. | Not implemented (local disk only) |
Bot flows (BOT)
| ID | Requirement | Status |
|---|---|---|
| BOT-01 | A visual node editor with typed connections. | Implemented |
| BOT-02 | A test simulator that runs a flow without side effects. | Implemented |
| BOT-03 | Versioned publishing with rollback, and import and export. | Implemented |
| BOT-04 | A runtime that executes nodes for messaging, input, logic, data, and support actions. | Implemented |
| BOT-05 | HTTP request nodes are protected against server-side request forgery. | Implemented |
| BOT-06 | Hand a conversation to an agent with a note, priority, and tags. | Implemented |
Access and security (SEC)
| ID | Requirement | Status |
|---|---|---|
| SEC-01 | Roles are built from a permission catalog, and every route declares the permission it needs. | Implemented |
| SEC-02 | API keys and OAuth clients are limited to catalog permissions. | Implemented |
| SEC-03 | Workspace data is isolated by tenant filters and database row-level security. | Implemented |
| SEC-04 | Sessions use httpOnly cookies, CSRF protection, and rotating refresh tokens with reuse detection. | Implemented |
| SEC-05 | Two-factor authentication with TOTP and recovery codes. | Implemented |
| SEC-06 | An append-only audit log of administrative changes. | Implemented |
| SEC-07 | Single sign-on. | Not implemented |
| SEC-08 | Security properties verified by isolated automated tests. | Partial (smoke test only) |
Operations and integration (OPS)
| ID | Requirement | Status |
|---|---|---|
| OPS-01 | A live wallboard for queues and agents. | Implemented |
| OPS-02 | Analytics for response and resolution times, CSAT, one-touch resolution, backlog, and agent activity, with CSV export. | Implemented |
| OPS-03 | CSAT surveys and a knowledge base with a public help centre. | Implemented |
| OPS-04 | A REST API with idempotency keys, ETags, and external-ID upserts. | Implemented |
| OPS-05 | Signed webhooks with retries, a delivery log, and redelivery. | Implemented |
| OPS-06 | An OpenAPI document covering every public route. | Partial |
| OPS-07 | Continuous integration running all test suites. | Not implemented |
4. User stories and acceptance criteria
Ticket lifecycle
US-01. As an agent, I want a customer's reply on a pending ticket to bring it back to open, so I see that the customer answered.
- Given a ticket is
pending, when the customer replies, then the message is added and the ticket moves toopen. - And the paused SLA clocks resume, with due dates moved forward by the business time spent paused.
US-02. As an agent, I want a customer's reply on an on-hold ticket not to change its status, so a ticket waiting on a third party is not pulled back into my queue.
- Given a ticket is
on_hold, when the customer replies, then the message is added and the status stayson_hold.
US-03. As a supervisor, I want closed tickets to stay closed, so my resolution numbers stay true.
- Given a ticket is
closed, when an agent tries to reply publicly, edit, reassign, or merge it, then the action is rejected with a conflict error. - And internal notes are still accepted.
US-04. As a customer, I want my message after a ticket closed not to be lost.
- Given a ticket is
closed, when the customer writes on the same conversation, then a new ticket is created with the subject prefixedFollow-up:. - And the new ticket is linked to the closed one with the kind
follow_up.
US-05. As an agent, I want to send a reply and set the status in one step, so the two cannot get out of step.
- Given an open ticket, when I send a reply with the status
pending, then the message and the status change are saved together or not at all.
US-06. As an agent, I want a solved ticket to reopen if the customer says it is not fixed.
- Given a ticket is
solved, when the customer replies, then it moves toopen. - And
reopen_countincreases by one and areopenedevent is recorded.
SLA
US-07. As a supervisor, I want SLA time not to count while we wait for the customer.
- Given a ticket moves to
pendingoron_hold, then the clocks pause. - And given it later leaves those statuses, then each due date moves forward by the business time spent paused.
US-08. As a supervisor, I want a warning before a breach, so I can act.
- Given a ticket has a first-response or resolution due time within 15 minutes and has not been warned, then a warning event is recorded once.
US-09. As a supervisor, I want a breach recorded and escalated.
- Given a ticket passes a due time while not paused, then a breach is recorded once and a breach event is published for automations.
Routing
US-10. As a customer, I want to reach the agent who helped me before.
- Given sticky routing is on and I was answered by an agent within the lookback window, when a new ticket arrives, then it is assigned to that agent if the agent is active, online, in the team, in shift, skilled, and speaks my language.
- And the assignment reason is
sticky. - And if the agent is not eligible, the ticket is routed normally and the reason for skipping is recorded.
US-11. As a supervisor, I want to know why a ticket was not assigned.
- Given no agent can take a ticket, then it is queued with one of
no_online_agent,no_qualified_agent,all_agents_at_capacity,no_agent_in_shift, ormanual_queue. - And the reason is visible on the ticket.
US-12. As a supervisor, I want work spread when one agent is overloaded.
- Given rebalancing is on, when an agent has tickets nobody has opened for longer than the minimum wait, then the oldest movable tickets are moved to a qualified agent with room while the load gap exceeds the stop gap.
- And a ticket an agent starts working during the move stays with that agent.
US-13. As a supervisor, I want a queue to differ from the workspace default.
- Given a queue override sets only the lookback window, then every other value comes from the workspace policy.
- And an override with an unknown key or an out-of-range value is rejected when saved.
US-14. As an administrator, I want tickets of a deactivated agent to return to the queue.
- Given I deactivate a user, then all of their open tickets return to routing.
Access
US-15. As an administrator, I want to give an integration only the access it needs.
- Given an API key is scoped to a set of permissions, then a request outside that set is rejected.
US-16. As an administrator, I want one workspace never to see another's data.
- Given a query omits its tenant filter, then row-level security still returns no rows from other workspaces.
5. Open questions
- Should a customer reply to an on-hold ticket notify the assignee without changing status?
- Should warning lead time be configurable per policy?
- Should pending have a maximum duration before the ticket is solved automatically?
6. Out of scope for this document
Pricing, packaging, support contracts, and anything that requires a customer.