Technology Transfer API
API reference for the Technology Transfer module — project management, phases, tasks, batches, CPP/CQA parameters, knowledge sessions, risks, and regulatory readiness.
Technology Transfer API
The Technology Transfer API provides full CRUD operations for managing clinical-to-commercial technology transfers. All procedures require organization-level authentication (orgProcedure) and enforce tenant isolation through organizationId.
There are two routers:
techTransfer.*— Base transfer model with steps (legacy)techTransferProjects.*— Extended TT model with phases, tasks, batches, parameters, knowledge sessions, risks, and regulatory checklists (39 procedures)
This reference documents the extended techTransferProjects router.
Project CRUD
techTransferProjects.createProject
Create a new technology transfer project.
POST /api/trpc/techTransferProjects.createProject
Input Schema:
{
name: string; // 1-200 chars, required
productName: string; // 1-200 chars, required
molecule?: string; // max 200 chars
dosageForm?: string; // max 200 chars
therapeuticArea?: string; // max 200 chars
sendingSiteId: string; // required
sendingSiteName: string; // 1-200 chars, required
sendingSiteCountry?: string; // max 100 chars
receivingSiteId: string; // required
receivingSiteName: string; // 1-200 chars, required
receivingSiteCountry?: string; // max 100 chars
description?: string; // max 2000 chars
projectManagerId?: string; // user ID
sendingSiteLeadId?: string; // user ID
receivingSiteLeadId?: string; // user ID
targetCompletionDate?: string; // ISO 8601
regulatorySubmissionDate?: string; // ISO 8601
}
Response: The created ttProject record.
Example:
{
"json": {
"name": "Aspirin 500mg Transfer — Berlin to Dublin",
"productName": "Aspirin 500mg Tablets",
"molecule": "Acetylsalicylic acid",
"dosageForm": "Solid oral",
"therapeuticArea": "Pain management",
"sendingSiteId": "site_berlin_01",
"sendingSiteName": "Berlin Manufacturing",
"sendingSiteCountry": "Germany",
"receivingSiteId": "site_dublin_01",
"receivingSiteName": "Dublin Production",
"receivingSiteCountry": "Ireland",
"targetCompletionDate": "2027-06-30T00:00:00.000Z"
}
}
techTransferProjects.listProjects
Paginated list of TT projects with filters.
POST /api/trpc/techTransferProjects.listProjects
Input Schema:
{
phase?: "planning" | "characterization" | "scale_up" | "ppq"
| "cleaning_validation" | "regulatory" | "complete" | "on_hold" | "cancelled";
status?: "draft" | "active" | "on_hold" | "complete" | "cancelled";
search?: string; // free-text search on name or productName
limit?: number; // 1-100, default 20
offset?: number; // default 0
}
Response:
{
items: TtProject[];
total: number;
}
techTransferProjects.getProject
Get a project by ID with child entity counts.
POST /api/trpc/techTransferProjects.getProject
Input: { id: string }
Response: Project record plus:
{
...project,
phaseCount: number;
taskCount: number;
batchCount: number;
parameterCount: number;
riskCount: number;
regulatoryItemCount: number;
}
techTransferProjects.updateProject
Partial update of project fields.
POST /api/trpc/techTransferProjects.updateProject
Input: { id: string } plus any project field as optional. Date fields accept ISO 8601 strings or null to clear.
Response: Updated project record.
techTransferProjects.deleteProject
Delete a TT project. All child entities (phases, tasks, batches, parameters, knowledge sessions, risks, regulatory items) are cascade-deleted.
POST /api/trpc/techTransferProjects.deleteProject
Input: { id: string }
Response: Deleted project record.
This is a destructive operation. All child data (phases, tasks, batches, parameters, sessions, risks, regulatory items) will be permanently deleted.
Phase CRUD
techTransferProjects.createPhase
Create a phase within a TT project.
POST /api/trpc/techTransferProjects.createPhase
Input Schema:
{
projectId: string; // required
name: string; // 1-200 chars, required
type: "characterization" | "analytical_transfer" | "scale_up"
| "engineering_batches" | "ppq" | "cleaning_validation"
| "packaging_validation" | "stability" | "regulatory"
| "knowledge_transfer" | "custom";
sortOrder: number; // integer >= 0
startDate?: string; // ISO 8601
endDate?: string; // ISO 8601
}
Response: Created phase record.
techTransferProjects.updatePhase
Update a phase. Automatically recalculates completionPct from child tasks.
POST /api/trpc/techTransferProjects.updatePhase
Input Schema:
{
id: string; // required
name?: string;
type?: string; // phase type enum
sortOrder?: number;
status?: "not_started" | "in_progress" | "complete" | "on_hold" | "skipped";
startDate?: string | null;
endDate?: string | null;
}
Response: Updated phase with recalculated completionPct.
techTransferProjects.listPhases
List all phases for a project, ordered by sortOrder.
POST /api/trpc/techTransferProjects.listPhases
Input: { projectId: string }
Response: TtPhase[]
techTransferProjects.reorderPhases
Bulk update phase sort order.
POST /api/trpc/techTransferProjects.reorderPhases
Input:
{
projectId: string;
orderedPhaseIds: string[]; // min 1 item
}
Each phase receives its array index as sortOrder.
Response: { success: true }
techTransferProjects.deletePhase
Delete a phase. Child tasks cascade-delete. Batches linked to this phase have their phaseId set to null.
POST /api/trpc/techTransferProjects.deletePhase
Input: { id: string }
Response: Deleted phase record.
Task CRUD
techTransferProjects.createTask
Create a task within a phase.
POST /api/trpc/techTransferProjects.createTask
Input Schema:
{
projectId: string; // required
phaseId: string; // required
title: string; // 1-500 chars, required
description?: string; // max 2000 chars
siteResponsibility: "sending" | "receiving" | "both" | "joint";
assigneeId?: string; // user ID
priority?: "critical" | "high" | "medium" | "low"; // default "medium"
dueDate?: string; // ISO 8601
predecessorTaskId?: string; // task dependency
requiresSignOff?: boolean; // default false
sortOrder?: number; // default 0
}
Response: Created task record.
techTransferProjects.updateTask
Partial update of a task. Automatically recalculates parent phase completionPct. When status is set to "complete", completedDate is auto-set.
POST /api/trpc/techTransferProjects.updateTask
Input Schema:
{
id: string; // required
title?: string;
description?: string | null;
siteResponsibility?: "sending" | "receiving" | "both" | "joint";
assigneeId?: string | null;
status?: "not_started" | "in_progress" | "blocked" | "complete" | "skipped";
priority?: "critical" | "high" | "medium" | "low";
dueDate?: string | null;
predecessorTaskId?: string | null;
requiresSignOff?: boolean;
sortOrder?: number;
signedOffBy?: string | null;
signedOffAt?: string | null;
}
Response: Updated task record.
techTransferProjects.listTasks
Paginated task list with filters.
POST /api/trpc/techTransferProjects.listTasks
Input Schema:
{
projectId: string; // required
phaseId?: string; // filter by phase
status?: "not_started" | "in_progress" | "blocked" | "complete" | "skipped";
siteResponsibility?: "sending" | "receiving" | "both" | "joint";
assigneeId?: string;
limit?: number; // 1-200, default 50
offset?: number; // default 0
}
Response: { items: TtTask[], total: number }
techTransferProjects.deleteTask
Delete a task. Clears predecessor references on dependent tasks. Recalculates parent phase completionPct.
POST /api/trpc/techTransferProjects.deleteTask
Input: { id: string }
Response: Deleted task record.
techTransferProjects.bulkUpdateTaskStatus
Batch update task statuses. Recalculates completionPct for all affected phases.
POST /api/trpc/techTransferProjects.bulkUpdateTaskStatus
Input Schema:
{
taskIds: string[]; // 1-200 task IDs
newStatus: "not_started" | "in_progress" | "blocked" | "complete" | "skipped";
}
Response: { updatedCount: number }
techTransferProjects.applyProjectTemplate
Populate a project with predefined phases and tasks based on dosage form.
POST /api/trpc/techTransferProjects.applyProjectTemplate
Input Schema:
{
projectId: string;
templateType: "solid_oral" | "injectable" | "biologic";
}
Response:
{
templateType: string;
phasesCreated: number;
tasksCreated: number;
}
The project must have zero existing phases. If phases already exist, the procedure throws a CONFLICT error.
Batch CRUD
techTransferProjects.createBatch
Create a batch campaign record.
POST /api/trpc/techTransferProjects.createBatch
Input Schema:
{
projectId: string; // required
phaseId?: string; // optional link to phase
batchNumber: string; // 1-100 chars, unique within project
batchType: "lab" | "engineering" | "ppq" | "validation" | "stability" | "commercial";
site: "sending" | "receiving" | "both" | "joint";
productionDate?: string; // ISO 8601
targetYield?: string; // numeric string (e.g., "95.5")
batchSize?: string;
batchSizeUnit?: string; // max 50 chars
notes?: string;
}
Response: Created batch record.
techTransferProjects.updateBatch
Partial update of a batch.
POST /api/trpc/techTransferProjects.updateBatch
Input Schema:
{
id: string; // required
batchNumber?: string;
batchType?: string; // batch type enum
site?: string; // site responsibility enum
productionDate?: string | null;
status?: "planned" | "in_progress" | "complete_pass" | "complete_fail"
| "under_review" | "voided";
yield?: string | null; // actual yield as decimal string
targetYield?: string | null;
deviationCount?: number; // integer >= 0
capaCount?: number; // integer >= 0
batchSize?: string | null;
batchSizeUnit?: string | null;
notes?: string | null;
phaseId?: string | null;
}
Response: Updated batch record.
techTransferProjects.deleteBatch
Delete a batch record.
POST /api/trpc/techTransferProjects.deleteBatch
Input: { id: string }
Response: Deleted batch record.
techTransferProjects.listBatches
Paginated batch list with filters.
POST /api/trpc/techTransferProjects.listBatches
Input Schema:
{
projectId: string; // required
batchType?: "lab" | "engineering" | "ppq" | "validation" | "stability" | "commercial";
status?: "planned" | "in_progress" | "complete_pass" | "complete_fail"
| "under_review" | "voided";
site?: "sending" | "receiving" | "both" | "joint";
limit?: number; // 1-100, default 20
offset?: number; // default 0
}
Response: { items: TtBatch[], total: number }
techTransferProjects.getBatchSummary
Aggregate batch statistics for a project.
POST /api/trpc/techTransferProjects.getBatchSummary
Input: { projectId: string }
Response:
{
totalBatches: number;
byType: Record<string, { total: number; pass: number; fail: number }>;
avgYield: number | null; // rounded to 2 decimal places
totalDeviations: number;
totalCapas: number;
trend: Array<{
month: string; // "YYYY-MM"
total: number;
pass: number;
fail: number;
}>;
}
techTransferProjects.linkDeviationToBatch
Associate a problem sheet (deviation) with a batch. Atomically increments the batch’s deviationCount.
POST /api/trpc/techTransferProjects.linkDeviationToBatch
Input:
{
batchId: string;
problemSheetId: string;
}
Response: Updated batch record.
Parameter CRUD
techTransferProjects.createParameter
Create a CPP or CQA parameter. Auto-computes the inSpec flag.
POST /api/trpc/techTransferProjects.createParameter
Input Schema:
{
projectId: string; // required
name: string; // 1-200 chars, required
parameterType: "cpp" | "cqa"; // required
unit?: string; // max 50 chars
targetValue?: string; // numeric string
parLow?: string; // PAR lower bound
parHigh?: string; // PAR upper bound
sourceSiteValue?: string; // observed at sending site
receivingSiteValue?: string; // observed at receiving site
specification?: string; // max 500 chars
notes?: string;
}
inSpec Computation: If receivingSiteValue, parLow, and parHigh are all provided, inSpec is true when parLow <= receivingSiteValue <= parHigh.
Response: Created parameter record.
techTransferProjects.updateParameter
Partial update with automatic inSpec recomputation.
POST /api/trpc/techTransferProjects.updateParameter
Input: { id: string } plus any parameter field as optional.
Response: Updated parameter record.
techTransferProjects.deleteParameter
Delete a CPP/CQA parameter.
POST /api/trpc/techTransferProjects.deleteParameter
Input: { id: string }
Response: Deleted parameter record.
techTransferProjects.listParameters
List parameters for a project with optional type filter.
POST /api/trpc/techTransferProjects.listParameters
Input:
{
projectId: string; // required
parameterType?: "cpp" | "cqa"; // filter by type
}
Response: TtParameter[] ordered by name ascending.
techTransferProjects.getParameterComparison
Side-by-side comparison of source vs. receiving site values.
POST /api/trpc/techTransferProjects.getParameterComparison
Input: { projectId: string }
Response:
{
parameters: Array<{
id: string;
name: string;
parameterType: "cpp" | "cqa";
unit: string | null;
targetValue: string | null;
parLow: string | null;
parHigh: string | null;
sourceSiteValue: string | null;
receivingSiteValue: string | null;
inSpec: boolean | null;
deviation: string | null; // receiving - source
deviationPct: number | null; // percentage deviation
specification: string | null;
}>;
summary: {
total: number;
inSpec: number;
outOfSpec: number;
pending: number;
compliancePct: number;
};
}
techTransferProjects.importParametersFromCsv
Bulk import parameters from parsed CSV data (up to 500 rows).
POST /api/trpc/techTransferProjects.importParametersFromCsv
Input Schema:
{
projectId: string;
csvData: Array<{
name: string; // 1-200 chars
parameterType: "cpp" | "cqa";
unit?: string; // max 50 chars
targetValue?: string;
parLow?: string;
parHigh?: string;
}>; // 1-500 items
}
Response: { importedCount: number }
Knowledge Session CRUD
techTransferProjects.createKnowledgeSession
Create a knowledge transfer session log.
POST /api/trpc/techTransferProjects.createKnowledgeSession
Input Schema:
{
projectId: string; // required
topic: string; // 1-300 chars, required
description?: string; // max 2000 chars
sessionDate: string; // ISO 8601, required
durationMinutes?: number; // integer >= 0
sendingParticipants?: Array<{
userId?: string;
name: string;
role: string;
}>;
receivingParticipants?: Array<{
userId?: string;
name: string;
role: string;
}>;
keyFindings?: string; // max 5000 chars
actionItems?: string; // max 5000 chars
}
Response: Created session record.
techTransferProjects.updateKnowledgeSession
Partial update of a knowledge session.
POST /api/trpc/techTransferProjects.updateKnowledgeSession
Input: { id: string } plus any session field as optional.
Response: Updated session record.
techTransferProjects.deleteKnowledgeSession
Delete a knowledge session. Blocked if both sites have signed off (returns FORBIDDEN).
POST /api/trpc/techTransferProjects.deleteKnowledgeSession
Input: { id: string }
Response: Deleted session record.
Sessions with dual sign-off (both sending and receiving confirmed) cannot be deleted. This is enforced atomically in the database query to prevent race conditions.
techTransferProjects.listKnowledgeSessions
Paginated session list, ordered by session date descending.
POST /api/trpc/techTransferProjects.listKnowledgeSessions
Input:
{
projectId: string; // required
limit?: number; // 1-100, default 20
offset?: number; // default 0
}
Response: { items: TtKnowledgeSession[], total: number }
techTransferProjects.signOffSession
Apply a dual site sign-off to a knowledge session.
POST /api/trpc/techTransferProjects.signOffSession
Input:
{
sessionId: string;
site: "sending" | "receiving";
}
The procedure sets:
signedOffSending/signedOffReceivingtotruesignedOffSendingBy/signedOffReceivingByto the current usersignedOffSendingAt/signedOffReceivingAtto the current timestamp
Throws CONFLICT if the specified site has already signed off.
Response: Updated session record.
Risk CRUD
techTransferProjects.createRisk
Create a risk with auto-computed riskScore = probability x impact.
POST /api/trpc/techTransferProjects.createRisk
Input Schema:
{
projectId: string; // required
title: string; // 1-300 chars, required
description?: string; // max 2000 chars
category: "scale_up" | "equipment_compatibility" | "analytical_method"
| "supply_chain" | "regulatory" | "personnel" | "timeline"
| "process_robustness" | "cleaning" | "stability" | "ip_knowledge" | "custom";
probability: number; // 1-5, required
impact: number; // 1-5, required
mitigation?: string; // max 2000 chars
contingency?: string; // max 2000 chars
ownerId?: string; // user ID
dueDate?: string; // ISO 8601
linkedBatchId?: string; // link to a batch
linkedTaskId?: string; // link to a task
}
Response: Created risk record with computed riskScore.
techTransferProjects.updateRisk
Partial update. Recomputes riskScore when probability or impact changes. Auto-sets closedDate when status transitions to "closed".
POST /api/trpc/techTransferProjects.updateRisk
Input: { id: string } plus any risk field as optional.
Response: Updated risk record.
techTransferProjects.deleteRisk
Delete a risk record.
POST /api/trpc/techTransferProjects.deleteRisk
Input: { id: string }
Response: Deleted risk record.
techTransferProjects.listRisks
Paginated risk list sorted by riskScore descending (highest risk first).
POST /api/trpc/techTransferProjects.listRisks
Input Schema:
{
projectId: string; // required
category?: string; // risk category enum
status?: "identified" | "mitigating" | "monitoring" | "closed" | "materialized";
minRiskScore?: number; // 1-25, filter risks >= this score
limit?: number; // 1-100, default 50
offset?: number; // default 0
}
Response: { items: TtRisk[], total: number }
techTransferProjects.getRiskMatrix
5x5 probability-impact matrix with per-cell risk lists.
POST /api/trpc/techTransferProjects.getRiskMatrix
Input: { projectId: string }
Response:
{
matrix: Array<{
probability: number; // 1-5
impact: number; // 1-5
count: number;
risks: Array<{
id: string;
title: string;
category: string;
status: string;
riskScore: number;
}>;
}>; // 25 cells (5x5)
summary: {
total: number;
critical: number; // riskScore >= 15
high: number; // riskScore 9-14
medium: number; // riskScore 4-8
low: number; // riskScore 1-3
avgScore: number;
};
}
Regulatory Checklist
techTransferProjects.createRegulatoryItem
Create a regulatory checklist item.
POST /api/trpc/techTransferProjects.createRegulatoryItem
Input Schema:
{
projectId: string; // required
section: "asmf" | "dmf" | "ctd_module_3" | "cep" | "gmp_certificate"
| "stability_data" | "batch_analysis" | "comparability_protocol"
| "site_master_file" | "cleaning_validation_report"
| "process_validation_report" | "analytical_method_validation" | "custom";
itemName: string; // 1-300 chars, required
description?: string; // max 2000 chars
responsibleSite: "sending" | "receiving" | "both" | "joint";
assigneeId?: string; // user ID
dueDate?: string; // ISO 8601
documentRef?: string; // max 500 chars
sortOrder: number; // integer >= 0, required
}
Response: Created regulatory item record.
techTransferProjects.updateRegulatoryItem
Partial update. Auto-sets completedDate when status transitions to "approved".
POST /api/trpc/techTransferProjects.updateRegulatoryItem
Input: { id: string } plus any regulatory item field as optional.
Response: Updated regulatory item record.
techTransferProjects.deleteRegulatoryItem
Delete a regulatory checklist item.
POST /api/trpc/techTransferProjects.deleteRegulatoryItem
Input: { id: string }
Response: Deleted regulatory item record.
techTransferProjects.listRegulatoryItems
List all regulatory items grouped by section.
POST /api/trpc/techTransferProjects.listRegulatoryItems
Input: { projectId: string }
Response:
{
items: TtRegulatoryChecklistItem[]; // flat list sorted by section + sortOrder
grouped: Record<string, TtRegulatoryChecklistItem[]>; // grouped by section
}
techTransferProjects.getRegulatoryReadiness
Per-section completion percentages.
POST /api/trpc/techTransferProjects.getRegulatoryReadiness
Input: { projectId: string }
Response:
{
sections: Array<{
section: string;
total: number;
complete: number;
completionPct: number; // 0-100
}>;
overall: {
total: number;
complete: number;
completionPct: number; // 0-100
};
}
Items with status "approved" or "not_applicable" count as complete.
techTransferProjects.applyRegulatoryTemplate
Populate the checklist with a predefined regulatory template.
POST /api/trpc/techTransferProjects.applyRegulatoryTemplate
Input:
{
projectId: string;
template: "eu" | "us" | "ich";
}
Response: { template: string, itemsCreated: number }
| Template | Focus | Items |
|---|---|---|
eu | EMA — ASMF, CEP, EEA GMP | ~22 |
us | FDA — DMF, FEI, SUPAC | ~20 |
ich | Harmonized Q-series (Q2-Q12) | ~21 |
The project must have zero existing regulatory items. If items already exist, the procedure throws a CONFLICT error.
Dashboard and Readiness
techTransferProjects.getDashboard
Comprehensive project dashboard with aggregated data from all child entities.
POST /api/trpc/techTransferProjects.getDashboard
Input: { projectId: string }
Response:
{
project: TtProject;
readinessScore: number; // 0-100
phaseProgress: Array<{
id: string;
name: string;
type: string;
status: string;
completionPct: number;
taskCount: number;
completedTaskCount: number;
}>;
taskSummary: {
total: number;
completed: number;
blocked: number;
overdue: number;
completionPct: number;
};
batchSummary: {
total: number;
passed: number;
failed: number;
avgYield: number | null;
totalDeviations: number;
passRate: number | null;
};
parameterSummary: {
total: number;
inSpec: number;
outOfSpec: number;
pending: number;
};
regulatoryReadiness: {
total: number;
complete: number;
completionPct: number;
};
knowledgeTransfer: {
totalSessions: number;
fullySignedOff: number;
coveragePct: number;
};
topRisks: Array<{ // top 5 by riskScore
id: string;
title: string;
category: string;
probability: number;
impact: number;
riskScore: number;
status: string;
}>;
upcomingMilestones: Array<{ // tasks due in next 30 days
id: string;
title: string;
phaseId: string;
dueDate: Date;
priority: string;
siteResponsibility: string;
status: string;
}>;
}
techTransferProjects.calculateReadinessScore
Compute and persist the composite weighted readiness score.
POST /api/trpc/techTransferProjects.calculateReadinessScore
Input: { projectId: string }
Response:
{
readinessScore: number; // 0-100
breakdown: {
taskCompletion: {
weight: 0.25;
rawPct: number;
weighted: number;
totalTasks: number;
completedTasks: number;
};
batchPassRate: {
weight: 0.25;
rawPct: number;
weighted: number;
totalCompleted: number;
passed: number;
};
deviationCount: {
weight: 0.15;
rawPct: number; // 100 - (deviations * 10), min 0
weighted: number;
totalDeviations: number;
};
openCapaCount: {
weight: 0.10;
rawPct: number; // 100 - (capas * 10), min 0
weighted: number;
totalCapas: number;
};
regulatoryCompleteness: {
weight: 0.15;
rawPct: number;
weighted: number;
total: number;
complete: number;
};
knowledgeTransferCoverage: {
weight: 0.10;
rawPct: number;
weighted: number;
totalSessions: number;
fullySignedOff: number;
};
};
}
Call this procedure after significant milestones (batch campaign completion, regulatory item approval, knowledge session sign-off) to keep the readiness score current.
Error Codes
All procedures may return these standard tRPC errors:
| Code | When |
|---|---|
NOT_FOUND | Project, phase, task, batch, parameter, session, risk, or regulatory item not found (or does not belong to current organization) |
CONFLICT | Template applied to project that already has phases/regulatory items; session sign-off already completed |
BAD_REQUEST | Unknown template type |
FORBIDDEN | Attempt to delete a knowledge session with dual sign-off |
UNAUTHORIZED | Missing or invalid authentication |
Was this page helpful?