application tier

application-tickets

Forge tickets module — tickets state machine + messages/notes/worklogs + SLA scanner. Sprint 57: 4 services + worker extracted. ticket_attachments + routers deferred pending media pipeline refactor.

Forge tickets module — tickets state machine + messages/notes/worklogs + SLA scanner. Sprint 57: 4 services + worker extracted. ticket_attachments + routers deferred pending media pipeline refactor.

Tierapplication
Roleunclassified (baselined)
Pathcrates/application/tickets
Edition2024
Targetsapplication_tickets
Public items59 across 11 modules
Tests10

What it is for

application-tickets — Layer 3 module for ticketing.

Sprint 57 extracted the services (tickets, ticket_messages, ticket_notes, ticket_worklogs) plus the sla_scanner worker. Sprint 65 added the admin + customer routers under api.

B-009 Gate-0.5 investigation: unlike application-catalog/application-encounters/ application-reviews, there is no primitives-tickets domain crate for this module to wrap — no domain-tickets (or similarly named) crate exists anywhere in the workspace, and this crate's Cargo.toml depends only on infrastructure-jobs, infrastructure-cron (each already wired by their own application-jobs/forge-cron modules), and platform-dto (types only, no schema). The tickets / ticket_messages / ticket_notes / ticket_worklogs / ticket_attachments tables that services::* reads/writes were authored directly in application-engine's central platform set (crates/application/engine/migrations/ 074_tickets.sql through 078_ticket_attachments.sql) and were never extracted into a standalone library crate crate with its own migrations/ directory, so there is nothing this module can vendor via include_str!. migrations() staying empty is correct, not an oversight; a host mounting application-tickets standalone (outside application-engine) must supply those five tables itself — including the encounters table 074_tickets.sql's own encounter_id FK requires (see application-encounters, already wired).

Capabilities

TicketsModule

application-tickets — Layer 3 module for ticketing.

Item
pub struct TicketsModule
TicketsModule :: fn new() -> Self
TicketsModule :: fn name(& self) -> & 'static str
TicketsModule :: fn version(& self) -> & 'static str
TicketsModule :: fn migrations(& self) -> Vec <MigrationSet>
TicketsModule :: async fn migrate_pending(& self, _pool : & PgPool) -> Result <u32, MigrationError>

api (other)

Ticketing REST routers — Sprint 65: extracted from rust-cms-engine.

Item
fn admin_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,
fn public_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,

api::tickets_admin (other)

Tickets admin REST endpoints (Sprint 43 — Gate 1.5 Q2).

Item
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,

api::tickets_customer (other)

Customer-facing tickets REST endpoints (Sprint 43).

Item
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,

services::ticket_attachments (other)

Ticket attachments service (Sprint 43).

Item
async fn attach_asset(pool : & PgPool, input : AttachAssetInput,) -> Result <TicketAttachment, TicketError>
async fn soft_delete_attachment(pool : & PgPool, id : Uuid) -> Result <(), TicketError>

AttachAssetInput

Ticket attachments service (Sprint 43).

Item
pub struct AttachAssetInput

TicketAttachment

Ticket attachments service (Sprint 43).

Item
pub struct TicketAttachment
async fn list_attachments_for_ticket(pool : & PgPool, ticket_id : Uuid, filter : VisibilityFilter,) -> Result <Vec <TicketAttachment>, TicketError>

services::ticket_messages (other)

Ticket reply thread service (Sprint 43).

Item
async fn list_messages_for_ticket(pool : & PgPool, ticket_id : Uuid, filter : VisibilityFilter,) -> Result <Vec <TicketMessage>, TicketError>
async fn create_message(pool : & PgPool, input : CreateMessageInput,) -> Result <TicketMessage, TicketError>
async fn soft_delete_message(pool : & PgPool, id : Uuid) -> Result <(), TicketError>

CreateMessageInput

Ticket reply thread service (Sprint 43).

Item
pub struct CreateMessageInput

TicketMessage

Ticket reply thread service (Sprint 43).

Item
pub struct TicketMessage
async fn get_message(pool : & PgPool, id : Uuid) -> Result <TicketMessage, TicketError>

VisibilityFilter

Ticket reply thread service (Sprint 43).

Item
pub enum VisibilityFilter

services::ticket_notes (other)

Internal ticket annotation service (Sprint 43). Staff-only.

Item
async fn create_note(pool : & PgPool, input : CreateNoteInput) -> Result <TicketNote, TicketError>
async fn soft_delete_note(pool : & PgPool, id : Uuid) -> Result <(), TicketError>

CreateNoteInput

Internal ticket annotation service (Sprint 43). Staff-only.

Item
pub struct CreateNoteInput

TicketNote

Internal ticket annotation service (Sprint 43). Staff-only.

Item
pub struct TicketNote
async fn list_notes_for_ticket(pool : & PgPool, ticket_id : Uuid,) -> Result <Vec <TicketNote>, TicketError>
async fn record_transition(pool : & PgPool, ticket_id : Uuid, actor_party_id : Option <Uuid>, from_status : & str, to_status : & str,) -> Result <TicketNote, TicketError>

services::ticket_worklogs (other)

Ticket worklog service — time tracking + timer sessions (Sprint 43).

Item
async fn create_worklog(pool : & PgPool, input : CreateWorklogInput,) -> Result <TicketWorklog, TicketError>
async fn soft_delete_worklog(pool : & PgPool, id : Uuid) -> Result <(), TicketError>
async fn cancel_timer(pool : & PgPool, staff_party_id : Uuid) -> Result <(), TicketError>

CreateWorklogInput

Ticket worklog service — time tracking + timer sessions (Sprint 43).

Item
pub struct CreateWorklogInput

TicketWorklog

Ticket worklog service — time tracking + timer sessions (Sprint 43).

Item
pub struct TicketWorklog
async fn list_worklogs_for_ticket(pool : & PgPool, ticket_id : Uuid,) -> Result <Vec <TicketWorklog>, TicketError>
async fn start_timer(pool : & PgPool, ticket_id : Uuid, staff_party_id : Uuid, description : Option <String>,) -> Result <TicketWorklog, TicketError>
async fn stop_timer(pool : & PgPool, staff_party_id : Uuid) -> Result <TicketWorklog, TicketError>
async fn active_timer(pool : & PgPool, staff_party_id : Uuid,) -> Result <Option <TicketWorklog>, TicketError>

WorklogSummary

Ticket worklog service — time tracking + timer sessions (Sprint 43).

Item
pub struct WorklogSummary
async fn worklog_summary(pool : & PgPool, ticket_id : Uuid,) -> Result <WorklogSummary, TicketError>

CreateTicketInput

Tickets service — support ticketing library crate (Sprint 43).

Item
pub struct CreateTicketInput

ListTicketsFilter

Tickets service — support ticketing library crate (Sprint 43).

Item
pub struct ListTicketsFilter

Ticket

Tickets service — support ticketing library crate (Sprint 43).

Item
pub struct Ticket
async fn create_ticket(pool : & PgPool, input : CreateTicketInput) -> Result <Ticket, TicketError>
async fn get_ticket(pool : & PgPool, id : Uuid) -> Result <Ticket, TicketError>
async fn list_tickets(pool : & PgPool, filter : ListTicketsFilter,) -> Result <Vec <Ticket>, TicketError>
async fn update_ticket(pool : & PgPool, id : Uuid, input : UpdateTicketInput,) -> Result <Ticket, TicketError>
async fn soft_delete_ticket(pool : & PgPool, id : Uuid) -> Result <(), TicketError>
async fn assign_ticket(pool : & PgPool, id : Uuid, assignee_party_id : Option <Uuid>,) -> Result <Ticket, TicketError>
async fn transition_ticket(pool : & PgPool, id : Uuid, transition : TicketTransition,) -> Result <Ticket, TicketError>

TicketError

Tickets service — support ticketing library crate (Sprint 43).

Item
pub enum TicketError
async fn maybe_set_first_response(pool : & PgPool, id : Uuid) -> Result <(), TicketError>
async fn scan_sla_breaches(pool : & PgPool) -> Result <Vec <Uuid>, TicketError>

TicketTransition

Tickets service — support ticketing library crate (Sprint 43).

Item
pub enum TicketTransition
TicketTransition :: fn target(& self) -> & 'static str

UpdateTicketInput

Tickets service — support ticketing library crate (Sprint 43).

Item
pub struct UpdateTicketInput

workers::sla_scanner (other)

SLA scanner worker (Sprint 46; migrated to a real schedule in Sprint 2.4 US-2.4.12).

Item
pub const SLA_SCAN_JOB_TYPE: & str
pub const DEFAULT_SLA_CRON: & str
async fn run_sla_scanner_worker(pool : PgPool, tenant_id : Uuid, cron_expr : & str, shutdown : CancellationToken,)

SlaScanPayload

SLA scanner worker (Sprint 46; migrated to a real schedule in Sprint 2.4 US-2.4.12).

Item
pub struct SlaScanPayload

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

application_tickets

flowchart TD
  n_application_tickets["application_tickets"]
  n_application_tickets --> n_api["api"]
  n_api --> n_api__tickets_admin["tickets_admin"]
  n_api --> n_api__tickets_customer["tickets_customer"]
  n_application_tickets --> n_services["services"]
  n_services --> n_services__ticket_attachments["ticket_attachments"]
  n_services --> n_services__ticket_messages["ticket_messages"]
  n_services --> n_services__ticket_notes["ticket_notes"]
  n_services --> n_services__ticket_worklogs["ticket_worklogs"]
  n_services --> n_services__tickets["tickets"]
  n_application_tickets --> n_workers["workers"]
  n_workers --> n_workers__sla_scanner["sla_scanner"]

Public surface

`crate root`

ItemWhat it is
pub struct TicketsModuleTickets module — Layer 3 wrapper.
TicketsModule :: fn new() -> Self
TicketsModule :: fn name(& self) -> & 'static str
TicketsModule :: fn version(& self) -> & 'static str
TicketsModule :: fn migrations(& self) -> Vec <MigrationSet>
TicketsModule :: async fn migrate_pending(& self, _pool : & PgPool) -> Result <u32, MigrationError>

`api`

ItemWhat it is
fn admin_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,Staff-facing ticketing routes (tickets_admin).
fn public_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,Customer-facing ticketing routes (tickets_customer).

`api::tickets_admin`

ItemWhat it is
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,

`api::tickets_customer`

ItemWhat it is
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>,

`services::ticket_attachments`

ItemWhat it is
pub struct TicketAttachment
pub struct AttachAssetInput
async fn list_attachments_for_ticket(pool : & PgPool, ticket_id : Uuid, filter : VisibilityFilter,) -> Result <Vec <TicketAttachment>, TicketError>
async fn attach_asset(pool : & PgPool, input : AttachAssetInput,) -> Result <TicketAttachment, TicketError>
async fn soft_delete_attachment(pool : & PgPool, id : Uuid) -> Result <(), TicketError>

`services::ticket_messages`

ItemWhat it is
pub struct TicketMessage
pub enum VisibilityFilterVisibility filter passed to listing functions.
pub struct CreateMessageInput
async fn list_messages_for_ticket(pool : & PgPool, ticket_id : Uuid, filter : VisibilityFilter,) -> Result <Vec <TicketMessage>, TicketError>List messages on a ticket
async fn create_message(pool : & PgPool, input : CreateMessageInput,) -> Result <TicketMessage, TicketError>Create a message
async fn get_message(pool : & PgPool, id : Uuid) -> Result <TicketMessage, TicketError>
async fn soft_delete_message(pool : & PgPool, id : Uuid) -> Result <(), TicketError>

`services::ticket_notes`

ItemWhat it is
pub struct TicketNote
pub struct CreateNoteInput
async fn list_notes_for_ticket(pool : & PgPool, ticket_id : Uuid,) -> Result <Vec <TicketNote>, TicketError>
async fn create_note(pool : & PgPool, input : CreateNoteInput) -> Result <TicketNote, TicketError>
async fn record_transition(pool : & PgPool, ticket_id : Uuid, actor_party_id : Option <Uuid>, from_status : & str, to_status : & str,) -> Result <TicketNote, TicketError>Convenience: write a system-typed note recording a status transition
async fn soft_delete_note(pool : & PgPool, id : Uuid) -> Result <(), TicketError>

`services::ticket_worklogs`

ItemWhat it is
pub struct TicketWorklog
pub struct CreateWorklogInput
pub struct WorklogSummary
async fn list_worklogs_for_ticket(pool : & PgPool, ticket_id : Uuid,) -> Result <Vec <TicketWorklog>, TicketError>
async fn create_worklog(pool : & PgPool, input : CreateWorklogInput,) -> Result <TicketWorklog, TicketError>
async fn soft_delete_worklog(pool : & PgPool, id : Uuid) -> Result <(), TicketError>
async fn worklog_summary(pool : & PgPool, ticket_id : Uuid,) -> Result <WorklogSummary, TicketError>
async fn start_timer(pool : & PgPool, ticket_id : Uuid, staff_party_id : Uuid, description : Option <String>,) -> Result <TicketWorklog, TicketError>Start a timer for (staff_party_id) on a ticket
async fn stop_timer(pool : & PgPool, staff_party_id : Uuid) -> Result <TicketWorklog, TicketError>Stop the active timer for (staff_party_id) — computes minutes from started_at and writes ended_at=NOW().
async fn cancel_timer(pool : & PgPool, staff_party_id : Uuid) -> Result <(), TicketError>Cancel the active timer for (staff_party_id) — soft-deletes the row instead of stopping it (no minutes recorded).
async fn active_timer(pool : & PgPool, staff_party_id : Uuid,) -> Result <Option <TicketWorklog>, TicketError>Returns the active timer for a staff member, if any.

`services::tickets`

ItemWhat it is
pub enum TicketError
pub struct Ticket
pub enum TicketTransitionState-machine transitions on a ticket
TicketTransition :: fn target(& self) -> & 'static strReturns the target status as the DB-canonical string.
pub struct CreateTicketInput
pub struct UpdateTicketInput
pub struct ListTicketsFilter
async fn create_ticket(pool : & PgPool, input : CreateTicketInput) -> Result <Ticket, TicketError>Create a ticket
async fn get_ticket(pool : & PgPool, id : Uuid) -> Result <Ticket, TicketError>
async fn list_tickets(pool : & PgPool, filter : ListTicketsFilter,) -> Result <Vec <Ticket>, TicketError>
async fn update_ticket(pool : & PgPool, id : Uuid, input : UpdateTicketInput,) -> Result <Ticket, TicketError>
async fn soft_delete_ticket(pool : & PgPool, id : Uuid) -> Result <(), TicketError>
async fn assign_ticket(pool : & PgPool, id : Uuid, assignee_party_id : Option <Uuid>,) -> Result <Ticket, TicketError>
async fn transition_ticket(pool : & PgPool, id : Uuid, transition : TicketTransition,) -> Result <Ticket, TicketError>Execute a state-machine transition
async fn maybe_set_first_response(pool : & PgPool, id : Uuid) -> Result <(), TicketError>Update first_response_at on the FIRST staff message (idempotent — only sets if NULL)
async fn scan_sla_breaches(pool : & PgPool) -> Result <Vec <Uuid>, TicketError>Nightly SLA scanner — flip sla_breached=true on any ticket that passed sla_due_at without resolution

`workers::sla_scanner`

ItemWhat it is
pub const SLA_SCAN_JOB_TYPE: & strJob type enqueued for each scheduled scan (also the cron schedule id).
pub const DEFAULT_SLA_CRON: & strDefault cron cadence: every 5 minutes, on the wall-clock boundary.
pub struct SlaScanPayloadPayload for an SLA-scan job (currently empty; reserved for future per-tenant scoping or filter knobs).
async fn run_sla_scanner_worker(pool : PgPool, tenant_id : Uuid, cron_expr : & str, shutdown : CancellationToken,)Run the SLA scanner until shutdown fires: a infrastructure-cron schedule emits sla_scan beats and a Worker runs each scan

No pub use re-exports: every item above is declared in this crate.

Boundary

Reaches into infrastructure, platform.

Shares tier application with 120 other crates: application-agreements, application-ai, application-analytics, application-approvals, application-assessments, application-audit-log, application-auth, application-billing, … (120 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)application
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/application/tickets
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_application["application"] --> n_infrastructure["infrastructure"]
  n_application["application"] --> n_platform["platform"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`application-core`applicationnoalways
`application-notifications`applicationnoalways
`infrastructure-cron`infrastructurenoalways
`infrastructure-jobs`infrastructurenoalways
`platform-dto`platformnoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
async-trait^0.1noalways
axum^0.7multipartnoalways
chrono^0.4serdenoalways
chrono-tz^0.10noalways
serde^1derivenoalways
serde_json^1noalways
sqlx^0.8runtime-tokio, postgres, chrono, uuid, jsonnoalways
thiserror^2noalways
tokio^1fullnoalways
tokio-util^0.7rtnoalways
tracing^0.1noalways
uuid^1v4, v7, serde, jsnoalways

Development. None.

Build. None.

Depended on by. Nothing in this workspace.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  SELF["application-tickets"]
  SELF -->|runtime| n_application_core["application-core"]
  SELF -->|runtime| n_application_notifications["application-notifications"]
  SELF -->|runtime| n_infrastructure_cron["infrastructure-cron"]
  SELF -->|runtime| n_infrastructure_jobs["infrastructure-jobs"]
  SELF -->|runtime| n_platform_dto["platform-dto"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
libapplication_tickets`src/lib.rs`

Error model

Error typeNamed by
TicketErroractive_timer, assign_ticket, attach_asset, cancel_timer, create_message, create_note, … (28 total)

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimeyes
database accessyes
network I/Oyes
unsafe codenone detected
environment variablesyes

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

VariableRead in
CARGO_PKG_VERSIONsrc/lib.rs

No workspace crate depends on this one.

Verification

KindCount
Unit tests10
Integration tests0
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
crate root100
api200
api::tickets_admin100
api::tickets_customer100
services::ticket_attachments500
services::ticket_messages700
services::ticket_notes600
services::ticket_worklogs1100
services::tickets1500
workers::sla_scanner400

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc2159
Public modules with a //! block1111
pie showData
    title Public items with rustdoc
    "Documented" : 21
    "No rustdoc detected" : 38

Metrics

MetricValue
Rust source files12
Source lines2017
Code lines1589
Public API items59
Public modules11
Tests10
Examples0
Cargo features0
Direct runtime dependencies17
Workspace reverse dependencies0
pie showData
    title Public API by kind
    "constant" : 2
    "enum" : 3
    "function" : 33
    "method" : 6
    "struct" : 15
pie showData
    title Rust source composition
    "Code" : 1589
    "Blank or comment" : 428

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All application · Manual