erp-clinicas-backend-v2/src/modules/imaging/entities/dicom-instance.entity.ts
Adrian Flores Cortes 56ded676ae [CL-009] feat: Implement imaging module for radiology studies
Add complete imaging module with:
- Entities: ImagingStudy (catalog), ImagingOrder (workflow), DicomInstance (DICOM tracking)
- Services: Study management, Order workflow (ordered->scheduled->performed->reported), DICOM file management
- Controller: REST endpoints for studies, orders, and DICOM instances
- Features: Multi-tenant support, study types (xray, ct, mri, ultrasound, mammography, pet, nuclear),
  order scheduling, radiologist assignment, critical findings flagging, DICOM viewer URLs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 19:55:56 -06:00

122 lines
3.4 KiB
TypeScript

import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
Index,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { ImagingOrder } from './imaging-order.entity';
export type DicomInstanceStatus = 'received' | 'processing' | 'available' | 'archived' | 'error';
export interface DicomMetadata {
manufacturer?: string;
stationName?: string;
institutionName?: string;
acquisitionDate?: string;
acquisitionTime?: string;
bodyPartExamined?: string;
patientPosition?: string;
sliceThickness?: number;
pixelSpacing?: number[];
windowCenter?: number;
windowWidth?: number;
rows?: number;
columns?: number;
bitsAllocated?: number;
photometricInterpretation?: string;
}
@Entity({ name: 'dicom_instances', schema: 'clinica' })
export class DicomInstance {
@PrimaryGeneratedColumn('uuid')
id: string;
@Index()
@Column({ name: 'tenant_id', type: 'uuid' })
tenantId: string;
@Index()
@Column({ name: 'imaging_order_id', type: 'uuid' })
imagingOrderId: string;
@ManyToOne(() => ImagingOrder, (order) => order.dicomInstances)
@JoinColumn({ name: 'imaging_order_id' })
imagingOrder: ImagingOrder;
@Index()
@Column({ name: 'study_instance_uid', type: 'varchar', length: 128 })
studyInstanceUID: string;
@Index()
@Column({ name: 'series_instance_uid', type: 'varchar', length: 128 })
seriesInstanceUID: string;
@Index()
@Column({ name: 'sop_instance_uid', type: 'varchar', length: 128 })
sopInstanceUID: string;
@Column({ name: 'sop_class_uid', type: 'varchar', length: 128 })
sopClassUID: string;
@Column({ name: 'series_number', type: 'int', nullable: true })
seriesNumber?: number;
@Column({ name: 'instance_number', type: 'int', nullable: true })
instanceNumber?: number;
@Column({ name: 'series_description', type: 'varchar', length: 200, nullable: true })
seriesDescription?: string;
@Column({ type: 'enum', enum: ['received', 'processing', 'available', 'archived', 'error'], default: 'received' })
status: DicomInstanceStatus;
@Column({ name: 'modality', type: 'varchar', length: 16, nullable: true })
modality?: string;
@Column({ name: 'transfer_syntax_uid', type: 'varchar', length: 128, nullable: true })
transferSyntaxUID?: string;
@Column({ name: 'file_path', type: 'varchar', length: 500, nullable: true })
filePath?: string;
@Column({ name: 'file_size', type: 'bigint', nullable: true })
fileSize?: number;
@Column({ name: 'storage_path', type: 'varchar', length: 500, nullable: true })
storagePath?: string;
@Column({ type: 'jsonb', nullable: true })
metadata?: DicomMetadata;
@Column({ name: 'viewer_url', type: 'varchar', length: 500, nullable: true })
viewerUrl?: string;
@Column({ name: 'thumbnail_url', type: 'varchar', length: 500, nullable: true })
thumbnailUrl?: string;
@Column({ name: 'wado_url', type: 'varchar', length: 500, nullable: true })
wadoUrl?: string;
@Column({ name: 'received_at', type: 'timestamptz', default: () => 'NOW()' })
receivedAt: Date;
@Column({ name: 'processed_at', type: 'timestamptz', nullable: true })
processedAt?: Date;
@Column({ name: 'archived_at', type: 'timestamptz', nullable: true })
archivedAt?: Date;
@Column({ name: 'error_message', type: 'text', nullable: true })
errorMessage?: string;
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
updatedAt: Date;
}