Job Management
Understanding the Job Model
In CoCore, a Job is the central unit of work in print production, similar to a JDF Job Ticket. However, unlike JDF's hierarchical node structure, CoCore uses a flatter, more flexible model that's easier to query and manage.
Job Hierarchy
Job (Overall print job)
├── Component (Physical print parts - cover, content, insert)
│ ├── ComponentMedia (Substrate specifications)
│ ├── ComponentLayout (Imposition details)
│ └── ComponentFileUsage (Content files)
├── Operation (Production steps)
│ └── Milestone (Key checkpoints)
└── JobProduct (Intermediate products during manufacturing)
└── Examples: printed signatures, folded sheets, incomplete book blocksJob States and Lifecycle
Job State Enum
Jobs progress through a defined state machine:
enum JobStateEnum {
DRAFT # Initial creation, not ready for production
PENDING # Ready for production, awaiting start
PROOFING # In the proofing process
PENDING_APPROVAL # Awaiting customer approval
APPROVED # Customer approved, ready for production
IN_PRODUCTION # Active production
COMPLETED # Production finished
SHIPPED # Delivered to customer
CANCELLED # Job cancelled
ON_HOLD # Temporarily paused
}State Transition Rules
Not all state transitions are allowed. The system enforces valid workflows:
DRAFT → PENDING → PROOFING → PENDING_APPROVAL → APPROVED → IN_PRODUCTION → COMPLETED → SHIPPED
↓ ↓ ↓ ↓ ↓ ↓
CANCELLED ON_HOLD CANCELLED CANCELLED CANCELLED CANCELLEDCreating Jobs
Basic Job Creation
Start with minimal required fields:
mutation CreateBasicJob {
createJob(input: {
name: "Business Cards - ACME Corp"
quantity: 1000
externalId: "ORD-2024-001" # Your system's reference
}) {
result {
id
jobNumber # Auto-generated unique identifier
name
state # Starts as DRAFT
createdAt
}
errors {
field
message
}
}
}Complete Job Creation
Create a job with full details:
mutation CreateCompleteJob {
createJob(input: {
# Basic Information
name: "Premium Brochures - Spring Campaign"
description: "Tri-fold brochures with spot UV coating"
externalId: "MIS-2024-0423"
# Quantities and Dates
quantity: 5000
dueDate: "2024-03-15T17:00:00Z"
requestedDeliveryDate: "2024-03-18T09:00:00Z"
# Priority and Classification
priority: 7 # 1-10 scale
rushOrder: false
# Customer Reference
customerId: "customer-abc-123"
# Production Instructions
productionNotes: "Use press #3 for color consistency with previous run"
specialInstructions: "Pack in boxes of 500, shrink-wrap each box"
# Initial State (optional, defaults to DRAFT)
state: PENDING
}) {
result {
id
jobNumber
name
state
priority
dueDate
customer {
id
name
contactName
}
}
errors {
field
message
code
}
}
}Creating Job with Components
Build the complete job structure in multiple steps:
# Step 1: Create the job
mutation Step1_CreateJob {
createJob(input: {
name: "Annual Report 2024"
quantity: 2000
customerId: "customer-xyz"
}) {
result {
id
jobNumber
}
}
}
# Step 2: Add components directly to the job
mutation Step2_CreateCoverComponent {
createComponent(input: {
jobId: "job-123" # Components belong directly to jobs
kind: COVER
name: "Annual Report Cover"
description: "4-page cover on heavy stock"
# Media specifications
media: {
name: "Premium Coated Cover"
type: PAPER
kind: SHEET
weight: { value: 300, unit: GSM }
width: { value: 8.5, unit: INCH }
height: { value: 11, unit: INCH }
stockType: COATED
coating: GLOSS
opacity: OPAQUE
}
# Layout specifications
layout: {
pages: 4
sides: TWO_SIDED_HEAD_TO_HEAD
closedDimensions: {
width: { value: 8.5, unit: INCH }
height: { value: 11, unit: INCH }
}
bleed: {
top: { value: 0.125, unit: INCH }
bottom: { value: 0.125, unit: INCH }
left: { value: 0.125, unit: INCH }
right: { value: 0.125, unit: INCH }
}
}
}) {
result {
id
kind
media { name, type }
layout { pages }
}
}
}
mutation Step3_CreateContentComponent {
createComponent(input: {
jobId: "job-123" # Components belong directly to jobs
kind: CONTENT
name: "Annual Report Interior"
description: "60 interior pages"
media: {
name: "Silk Text"
type: PAPER
kind: SHEET
weight: { value: 100, unit: GSM }
width: { value: 8.5, unit: INCH }
height: { value: 11, unit: INCH }
stockType: SILK
opacity: OPAQUE
}
layout: {
pages: 60
sides: TWO_SIDED_HEAD_TO_HEAD
closedDimensions: {
width: { value: 8.5, unit: INCH }
height: { value: 11, unit: INCH }
}
}
}) {
result {
id
kind
}
}
}
# Step 4: Create JobProducts for intermediate manufacturing products
mutation Step4_CreateJobProducts {
# Create a job product for printed sheets from the cover component
coverSheets: createJobProduct(input: {
jobId: "job-123"
componentId: "component-cover-456" # Links to the cover component
name: "Printed Cover Sheets"
metadata: "{\"quantity\": 500, \"sheetsPerSignature\": 4}"
}) {
result {
id
name
component { kind }
}
}
# Create a job product for printed and folded signatures
contentSignatures: createJobProduct(input: {
jobId: "job-123"
componentId: "component-content-789" # Links to the content component
name: "Folded Content Signatures"
metadata: "{\"quantity\": 125, \"pagesPerSignature\": 16}"
}) {
result {
id
name
component { kind }
}
}
# Create a job product for the assembled but unbound book block
bookBlock: createJobProduct(input: {
jobId: "job-123"
componentId: null # No specific component - represents assembled work
name: "Assembled Book Block (Unbound)"
metadata: "{\"quantity\": 2000, \"ready_for_binding\": true}"
}) {
result {
id
name
}
}
}Updating Jobs
Basic Updates
Update job properties:
mutation UpdateJobDetails {
updateJob(
id: "job-123"
input: {
name: "Business Cards - ACME Corp (Revised)"
priority: 9
rushOrder: true
dueDate: "2024-03-10T17:00:00Z"
productionNotes: "Customer requested earlier delivery"
}
) {
result {
id
name
priority
rushOrder
dueDate
updatedAt
}
errors {
field
message
}
}
}State Transitions
Change job state with validation:
mutation MoveToProduction {
transitionJobState(
id: "job-123"
state: IN_PRODUCTION
) {
result {
id
state
stateChangedAt
currentOperation {
name
state
}
}
errors {
message # e.g., "Cannot transition from DRAFT to IN_PRODUCTION"
}
}
}Bulk State Updates
Process multiple jobs:
mutation BulkApprove {
job1: transitionJobState(id: "job-1", state: APPROVED) {
result { id, state }
errors { message }
}
job2: transitionJobState(id: "job-2", state: APPROVED) {
result { id, state }
errors { message }
}
job3: transitionJobState(id: "job-3", state: APPROVED) {
result { id, state }
errors { message }
}
}Querying Jobs
Get Single Job with Full Details
query GetJobComplete {
getJob(id: "job-123") {
# Basic Information
id
jobNumber
externalId
name
description
state
# Quantities and Dates
quantity
quantityProduced
quantityShipped
createdAt
updatedAt
dueDate
completedAt
# Customer Information
customer {
id
name
contactName
email
phone
creditStatus
}
# Components
components {
results {
id
kind
name
description
media {
name
type
weight { value, unit }
}
layout {
pages
sides
}
componentFileUsages {
results {
id
fileName
fileType
fileSize
pageRange
}
}
}
}
# Job Products (intermediate manufacturing products)
jobProducts {
results {
id
name
metadata
component { # Which component these products came from
id
kind
name
}
# Products can be inputs/outputs of operations
operationInputs {
operation { name, state }
}
operationOutputs {
operation { name, state }
}
}
}
# Production Operations
operations(
sort: [{ field: SEQUENCE, order: ASC }]
) {
results {
id
name
state
sequence
startedAt
completedAt
device {
id
name
status
}
}
}
# Milestones
milestones {
results {
id
name
type
status
dueDate
completedAt
}
}
}
}Search and Filter Jobs
Find jobs matching specific criteria:
query SearchJobs {
listJobs(
filter: {
# Text search
name: { ilike: "%business card%" }
# State filtering
state: { in: [PENDING, IN_PRODUCTION, PROOFING] }
# Date ranges
createdAt: {
greaterThanOrEqual: "2024-01-01T00:00:00Z"
lessThan: "2024-02-01T00:00:00Z"
}
# Customer filtering
customer: {
creditStatus: { eq: APPROVED }
}
# Quantity ranges
quantity: {
greaterThanOrEqual: 1000
lessThanOrEqual: 10000
}
}
sort: [
{ field: PRIORITY, order: DESC }
{ field: DUE_DATE, order: ASC }
]
first: 20
) {
count
results {
id
jobNumber
name
state
priority
dueDate
customer { name }
}
endKeyset
}
}Get Jobs by External ID
Find jobs from your external system:
query GetJobByExternalId {
getJobByExternalId(externalId: "MIS-2024-0423") {
id
jobNumber
name
state
externalId
}
}Dashboard Queries
Get job statistics for dashboards:
query DashboardStats {
# Jobs due today
dueToday: listJobs(
filter: {
dueDate: {
greaterThanOrEqual: "2024-02-15T00:00:00Z"
lessThan: "2024-02-16T00:00:00Z"
}
state: { notIn: [COMPLETED, SHIPPED, CANCELLED] }
}
) {
count
results {
id
jobNumber
name
priority
customer { name }
}
}
# Rush orders
rushJobs: listJobs(
filter: {
rushOrder: { eq: true }
state: { in: [PENDING, IN_PRODUCTION] }
}
sort: [{ field: PRIORITY, order: DESC }]
) {
count
results {
id
jobNumber
name
dueDate
}
}
# Jobs awaiting approval
pendingApproval: listJobs(
filter: {
state: { eq: PENDING_APPROVAL }
}
sort: [{ field: CREATED_AT, order: ASC }]
) {
count
results {
id
jobNumber
name
customer { name, email }
proofUrl
}
}
}Managing Job Relationships
Linking Files to Components
mutation AttachFilesToComponent {
createComponentFileUsage(input: {
componentId: "component-789"
fileName: "annual_report_cover.pdf"
fileType: "application/pdf"
fileSize: 15728640 # bytes
pageRange: "1-4"
fileUrl: "https://storage.example.com/files/annual_report_cover.pdf"
purpose: PRINT_READY
colorSpace: CMYK
resolution: 300
}) {
result {
id
fileName
component {
id
kind
}
}
}
}Managing Job Operations
Create and sequence production operations:
mutation CreateProductionOperations {
# Prepress operation
op1: createOperation(input: {
jobId: "job-123"
name: "Prepress"
type: PREPRESS
sequence: 1
estimatedDuration: 30 # minutes
instructions: "Check files, create plates"
}) {
result { id, sequence }
}
# Printing operation
op2: createOperation(input: {
jobId: "job-123"
name: "Print Cover"
type: PRINTING
sequence: 2
deviceId: "device-press-1"
estimatedDuration: 120
instructions: "4-color process + spot UV"
}) {
result { id, sequence }
}
# Finishing operation
op3: createOperation(input: {
jobId: "job-123"
name: "Perfect Binding"
type: FINISHING
sequence: 3
deviceId: "device-binder-1"
estimatedDuration: 90
instructions: "Perfect bind with 3mm spine"
}) {
result { id, sequence }
}
}Job Subscriptions
Real-time updates for job changes:
subscription WatchJobUpdates {
jobUpdated(jobId: "job-123") {
id
state
updatedAt
quantityProduced
currentOperation {
name
state
percentComplete
}
}
}
subscription WatchJobStateChanges {
jobStateChanged(
filter: { customerId: { eq: "customer-abc" } }
) {
id
jobNumber
previousState
newState
changedAt
changedBy {
name
email
}
}
}Common Workflows
1. Quick Reorder
Clone an existing job:
mutation QuickReorder {
cloneJob(
sourceJobId: "job-original"
input: {
name: "Business Cards - Reorder March 2024"
quantity: 2000
dueDate: "2024-03-20T17:00:00Z"
}
) {
result {
id
jobNumber
name
# Components and settings copied from original
components {
count
}
}
}
}2. Gang Run Management
Group multiple jobs for efficient production:
mutation CreateGangRun {
createGangRun(input: {
name: "Business Cards Gang Run - Week 10"
jobIds: ["job-1", "job-2", "job-3", "job-4"]
deviceId: "device-press-2"
scheduledDate: "2024-03-11T08:00:00Z"
}) {
result {
id
jobs {
results {
id
jobNumber
customer { name }
quantity
}
}
totalSheets
estimatedRunTime
}
}
}3. Proof Approval Workflow
# Generate proof
mutation GenerateProof {
generateJobProof(jobId: "job-123") {
result {
id
proofUrl
generatedAt
}
}
}
# Send for approval
mutation SendForApproval {
transitionJobState(id: "job-123", state: PENDING_APPROVAL) {
result { state }
}
sendProofEmail(input: {
jobId: "job-123"
recipientEmail: "customer@example.com"
message: "Please review and approve your proof"
}) {
result { sentAt }
}
}
# Record approval
mutation RecordApproval {
approveJob(input: {
jobId: "job-123"
approverEmail: "customer@example.com"
comments: "Looks great, please proceed"
}) {
result {
id
state # Now APPROVED
approvalDetails {
approvedBy
approvedAt
comments
}
}
}
}Best Practices
1. Use External IDs
Always set externalId to maintain links to your MIS/ERP system:
externalId: "YOUR-SYSTEM-ID-12345"2. Set Realistic Priorities
Use the 1-10 priority scale consistently:
- 1-3: Low priority, flexible deadlines
- 4-6: Normal production
- 7-9: High priority, tight deadlines
- 10: Emergency/rush jobs
3. Include Production Notes
Add clear instructions for operators:
productionNotes: "Match color to sample #4523. Use fresh ink batch."
specialInstructions: "Call customer before shipping: 555-0100"4. Track Component Relationships
Understand the correct hierarchy:
Job → Component (design/specification) → ComponentFileUsage (artwork/content)
↘ JobProduct (physical items during production - sheets, signatures, blocks)Components define WHAT to print (specifications), while JobProducts track the physical items created during manufacturing.
5. Monitor State Transitions
Subscribe to state changes for critical jobs to ensure smooth workflow.
Next Steps
- Components and Media - Deep dive into component management
- Orders and Commerce - Connecting jobs to customer orders