chore: import DH V2 D5.6.4 production baseline

This commit is contained in:
DH V2
2026-09-05 10:12:35 -03:00
commit 82213e72f5
757 changed files with 84218 additions and 0 deletions
@@ -0,0 +1,51 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum AreaOrganizationRole {
OPERATOR='OPERATOR', TECHNICAL_OPERATOR='TECHNICAL_OPERATOR', CONCESSIONAIRE='CONCESSIONAIRE', PERMIT_HOLDER='PERMIT_HOLDER', PARTICIPANT='PARTICIPANT', OTHER='OTHER'
}
@Entity({ name: 'area_company_relations' })
@Index('idx_area_company_relations_area_id', ['areaId'])
@Index('idx_area_company_relations_company_id', ['companyId'])
@Index('idx_area_company_relations_valid_until', ['validUntil'])
export class AreaCompanyRelation extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'area_id', type: 'uuid' })
areaId!: string;
@Column({ name: 'company_id', type: 'uuid' })
companyId!: string;
@Column({ name:'relation_role', type:'enum', enum:AreaOrganizationRole, enumName:'area_organization_role', default:AreaOrganizationRole.OPERATOR })
relationRole!: AreaOrganizationRole;
@Column({ name:'participation_percent', type:'numeric', precision:7, scale:4, nullable:true })
participationPercent!: string|null;
@Column({ name:'legal_instrument', type:'varchar', length:240, nullable:true })
legalInstrument!: string|null;
@Column({ name:'source_document_id', type:'uuid', nullable:true })
sourceDocumentId!: string|null;
@Column({ name: 'valid_from', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
validFrom!: Date;
@Column({ name: 'valid_until', type: 'timestamptz', nullable: true })
validUntil!: Date | null;
@Column({ name: 'start_reason', type: 'text' })
startReason!: string;
@Column({ name: 'end_reason', type: 'text', nullable: true })
endReason!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'ended_by', type: 'uuid', nullable: true })
endedBy!: string | null;
}
@@ -0,0 +1,4 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; import { TimestampedEntity } from './timestamped.entity';
export enum AreaLegalRightOrganizationRole { HOLDER='HOLDER', PARTICIPANT='PARTICIPANT', OPERATOR='OPERATOR', OTHER='OTHER' }
@Entity({name:'area_legal_right_organizations'}) @Index('idx_area_legal_right_org_right_id',['rightId']) @Index('idx_area_legal_right_org_organization_id',['organizationId']) @Index('idx_area_legal_right_org_valid_until',['validUntil'])
export class AreaLegalRightOrganization extends TimestampedEntity { @PrimaryGeneratedColumn('uuid') id!:string; @Column({name:'right_id',type:'uuid'}) rightId!:string; @Column({name:'organization_id',type:'uuid'}) organizationId!:string; @Column({type:'enum',enum:AreaLegalRightOrganizationRole,enumName:'area_legal_right_organization_role'}) role!:AreaLegalRightOrganizationRole; @Column({name:'participation_percent',type:'numeric',precision:7,scale:4,nullable:true}) participationPercent!:string|null; @Column({name:'valid_from',type:'date',default:()=> 'CURRENT_DATE'}) validFrom!:string; @Column({name:'valid_until',type:'date',nullable:true}) validUntil!:string|null; @Column({type:'text',nullable:true}) notes!:string|null; @Column({name:'end_reason',type:'text',nullable:true}) endReason!:string|null; @Column({name:'created_by',type:'uuid',nullable:true}) createdBy!:string|null; @Column({name:'ended_by',type:'uuid',nullable:true}) endedBy!:string|null; }
@@ -0,0 +1,5 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; import { TimestampedEntity } from './timestamped.entity';
export enum AreaLegalRightType { EXPLOITATION_CONCESSION='EXPLOITATION_CONCESSION', EXPLORATION_PERMIT='EXPLORATION_PERMIT', TRANSPORT_CONCESSION='TRANSPORT_CONCESSION', OTHER='OTHER' }
export enum AreaLegalRightStatus { ACTIVE='ACTIVE', EXPIRED='EXPIRED', REVOKED='REVOKED', PENDING='PENDING' }
@Entity({name:'area_legal_rights'}) @Index('idx_area_legal_rights_area_id',['areaId']) @Index('idx_area_legal_rights_valid_until',['validUntil'])
export class AreaLegalRight extends TimestampedEntity { @PrimaryGeneratedColumn('uuid') id!:string; @Column({name:'area_id',type:'uuid'}) areaId!:string; @Column({name:'right_type',type:'enum',enum:AreaLegalRightType,enumName:'area_legal_right_type'}) rightType!:AreaLegalRightType; @Column({type:'varchar',length:260}) name!:string; @Column({name:'instrument_number',type:'varchar',length:180,nullable:true}) instrumentNumber!:string|null; @Column({name:'valid_from',type:'date',nullable:true}) validFrom!:string|null; @Column({name:'valid_until',type:'date',nullable:true}) validUntil!:string|null; @Column({type:'enum',enum:AreaLegalRightStatus,enumName:'area_legal_right_status',default:AreaLegalRightStatus.ACTIVE}) status!:AreaLegalRightStatus; @Column({name:'source_document_id',type:'uuid',nullable:true}) sourceDocumentId!:string|null; @Column({type:'text',nullable:true}) notes!:string|null; @Column({name:'created_by',type:'uuid',nullable:true}) createdBy!:string|null; @Column({name:'updated_by',type:'uuid',nullable:true}) updatedBy!:string|null; }
@@ -0,0 +1,51 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum AssetAttributeDataType {
TEXT = 'TEXT',
NUMBER = 'NUMBER',
BOOLEAN = 'BOOLEAN',
DATE = 'DATE',
DATETIME = 'DATETIME',
SELECT = 'SELECT',
}
@Entity({ name: 'asset_attribute_definitions' })
@Index('idx_asset_attribute_definitions_type', ['assetTypeId', 'sortOrder'])
@Index('idx_asset_attribute_definitions_active', ['isActive'])
export class AssetAttributeDefinition extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'asset_type_id', type: 'uuid' })
assetTypeId!: string;
@Column({ type: 'varchar', length: 80 })
code!: string;
@Column({ type: 'varchar', length: 160 })
name!: string;
@Column({
name: 'data_type',
type: 'enum',
enum: AssetAttributeDataType,
enumName: 'asset_attribute_data_type',
})
dataType!: AssetAttributeDataType;
@Column({ name: 'is_required', type: 'boolean', default: false })
isRequired!: boolean;
@Column({ name: 'is_active', type: 'boolean', default: true })
isActive!: boolean;
@Column({ type: 'varchar', length: 40, nullable: true })
unit!: string | null;
@Column({ type: 'jsonb', nullable: true })
options!: string[] | null;
@Column({ name: 'sort_order', type: 'integer', default: 0 })
sortOrder!: number;
}
@@ -0,0 +1,19 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity({ name: 'asset_attribute_values' })
export class AssetAttributeValue {
@PrimaryColumn({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@PrimaryColumn({ name: 'definition_id', type: 'uuid' })
definitionId!: string;
@Column({ type: 'jsonb' })
value!: unknown;
@Column({ name: 'updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
updatedAt!: Date;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,3 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; import { TimestampedEntity } from './timestamped.entity';
@Entity({name:'asset_external_identifiers'}) @Index('idx_asset_external_identifiers_asset_id',['assetId']) @Index('idx_asset_external_identifiers_namespace',['namespace'])
export class AssetExternalIdentifier extends TimestampedEntity { @PrimaryGeneratedColumn('uuid') id!:string; @Column({name:'asset_id',type:'uuid'}) assetId!:string; @Column({type:'varchar',length:80}) namespace!:string; @Column({type:'varchar',length:180}) value!:string; @Column({name:'valid_from',type:'timestamptz',default:()=> 'CURRENT_TIMESTAMP'}) validFrom!:Date; @Column({name:'valid_until',type:'timestamptz',nullable:true}) validUntil!:Date|null; @Column({name:'source_document_id',type:'uuid',nullable:true}) sourceDocumentId!:string|null; @Column({type:'text',nullable:true}) notes!:string|null; @Column({name:'end_reason',type:'text',nullable:true}) endReason!:string|null; @Column({name:'created_by',type:'uuid',nullable:true}) createdBy!:string|null; @Column({name:'ended_by',type:'uuid',nullable:true}) endedBy!:string|null; }
@@ -0,0 +1,58 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
export enum AssetGeometryType {
POINT = 'POINT',
LINESTRING = 'LINESTRING',
POLYGON = 'POLYGON',
}
export enum AssetGeometrySource {
WEB = 'WEB',
ANDROID = 'ANDROID',
IMPORT = 'IMPORT',
SURVEY = 'SURVEY',
}
@Entity({ name: 'asset_geometries' })
@Index('idx_asset_geometries_geometry', ['geometry'], { spatial: true })
@Index('idx_asset_geometries_type', ['geometryType'])
export class AssetGeometry {
@PrimaryColumn({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({
type: 'geometry',
spatialFeatureType: 'Geometry',
srid: 4326,
})
geometry!: { type: AssetGeometryType; coordinates: unknown };
@Column({ name: 'geometry_type', type: 'varchar', length: 20 })
geometryType!: AssetGeometryType;
@Column({
type: 'enum',
enum: AssetGeometrySource,
enumName: 'asset_geometry_source',
default: AssetGeometrySource.WEB,
})
source!: AssetGeometrySource;
@Column({ name: 'accuracy_m', type: 'numeric', precision: 12, scale: 3, nullable: true })
accuracyM!: string | null;
@Column({ name: 'captured_at', type: 'timestamptz', nullable: true })
capturedAt!: Date | null;
@Column({ name: 'device_label', type: 'varchar', length: 255, nullable: true })
deviceLabel!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
@Column({ name: 'updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
updatedAt!: Date;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,78 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum AssetMediaKind {
PHOTO = 'PHOTO',
DOCUMENT = 'DOCUMENT',
}
export enum AssetMediaSource {
WEB = 'WEB',
ANDROID = 'ANDROID',
IMPORT = 'IMPORT',
}
@Entity({ name: 'asset_media' })
@Index('idx_asset_media_asset_created', ['assetId', 'createdAt'])
@Index('idx_asset_media_sha256', ['sha256'])
@Index('idx_asset_media_active', ['assetId', 'deletedAt'])
export class AssetMedia {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ type: 'varchar', length: 20 })
kind!: AssetMediaKind;
@Column({ name: 'original_name', type: 'varchar', length: 255 })
originalName!: string;
@Column({ name: 'stored_name', type: 'varchar', length: 80 })
storedName!: string;
@Column({ name: 'mime_type', type: 'varchar', length: 100 })
mimeType!: string;
@Column({ name: 'size_bytes', type: 'bigint' })
sizeBytes!: string;
@Column({ type: 'char', length: 64 })
sha256!: string;
@Column({ type: 'varchar', length: 200, nullable: true })
title!: string | null;
@Column({ type: 'text', nullable: true })
description!: string | null;
@Column({ name: 'captured_at', type: 'timestamptz', nullable: true })
capturedAt!: Date | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
latitude!: string | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
longitude!: string | null;
@Column({ name: 'accuracy_m', type: 'numeric', precision: 12, scale: 3, nullable: true })
accuracyM!: string | null;
@Column({ type: 'varchar', length: 20 })
source!: AssetMediaSource;
@Column({ name: 'uploaded_by', type: 'uuid', nullable: true })
uploadedBy!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
@Column({ name: 'updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
updatedAt!: Date;
@Column({ name: 'deleted_at', type: 'timestamptz', nullable: true })
deletedAt!: Date | null;
@Column({ name: 'deleted_by', type: 'uuid', nullable: true })
deletedBy!: string | null;
}
@@ -0,0 +1,4 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; import { TimestampedEntity } from './timestamped.entity';
export enum AssetSourceDocumentRelationType { SOURCE='SOURCE', MENTIONS='MENTIONS', VALIDATES='VALIDATES', SUPERSEDES='SUPERSEDES', OTHER='OTHER' }
@Entity({name:'asset_source_documents'}) @Index('idx_asset_source_documents_asset_id',['assetId']) @Index('idx_asset_source_documents_document_id',['documentId'])
export class AssetSourceDocument extends TimestampedEntity { @PrimaryGeneratedColumn('uuid') id!:string; @Column({name:'asset_id',type:'uuid'}) assetId!:string; @Column({name:'document_id',type:'uuid'}) documentId!:string; @Column({name:'relation_type',type:'enum',enum:AssetSourceDocumentRelationType,enumName:'asset_source_document_relation_type',default:AssetSourceDocumentRelationType.SOURCE}) relationType!:AssetSourceDocumentRelationType; @Column({type:'text',nullable:true}) notes!:string|null; @Column({name:'created_by',type:'uuid',nullable:true}) createdBy!:string|null; }
@@ -0,0 +1,13 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity({ name: 'asset_type_parent_rules' })
export class AssetTypeParentRule {
@PrimaryColumn({ name: 'child_type_id', type: 'uuid' })
childTypeId!: string;
@PrimaryColumn({ name: 'parent_type_id', type: 'uuid' })
parentTypeId!: string;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,45 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum AssetTypeOperationalRole {
GENERIC = 'GENERIC',
AREA = 'AREA',
COMPANY = 'COMPANY',
}
@Entity({ name: 'asset_types' })
@Index('idx_asset_types_is_active', ['isActive'])
export class AssetType extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 80 })
code!: string;
@Column({ type: 'varchar', length: 160 })
name!: string;
@Column({ type: 'text', default: '' })
description!: string;
@Column({ name: 'can_be_root', type: 'boolean', default: false })
canBeRoot!: boolean;
@Column({ name: 'is_active', type: 'boolean', default: true })
isActive!: boolean;
@Column({
name: 'operational_role',
type: 'enum',
enum: AssetTypeOperationalRole,
enumName: 'asset_type_operational_role',
default: AssetTypeOperationalRole.GENERIC,
})
operationalRole!: AssetTypeOperationalRole;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,60 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum AssetVersionChangeType {
BASELINE = 'BASELINE',
CREATED = 'CREATED',
UPDATED = 'UPDATED',
CONTEXT_CHANGED = 'CONTEXT_CHANGED',
STATUS_CHANGED = 'STATUS_CHANGED',
OPERATIONAL_STATUS_CHANGED = 'OPERATIONAL_STATUS_CHANGED',
REGISTRY_UPDATED = 'REGISTRY_UPDATED',
GEOMETRY_UPDATED = 'GEOMETRY_UPDATED',
GEOMETRY_REMOVED = 'GEOMETRY_REMOVED',
MEDIA_UPLOADED = 'MEDIA_UPLOADED',
MEDIA_UPDATED = 'MEDIA_UPDATED',
MEDIA_REMOVED = 'MEDIA_REMOVED',
PROVENANCE_BASELINE = 'PROVENANCE_BASELINE',
PROVENANCE_UPDATED = 'PROVENANCE_UPDATED',
PROVENANCE_VERIFIED = 'PROVENANCE_VERIFIED',
}
@Entity({ name: 'asset_versions' })
@Index('idx_asset_versions_asset_number', ['assetId', 'versionNumber'], {
unique: true,
})
@Index('idx_asset_versions_occurred_at', ['occurredAt'])
@Index('idx_asset_versions_change_type', ['changeType'])
export class AssetVersion {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ name: 'version_number', type: 'integer' })
versionNumber!: number;
@Column({ name: 'change_type', type: 'varchar', length: 32 })
changeType!: AssetVersionChangeType;
@Column({ name: 'changed_fields', type: 'text', array: true, default: () => "'{}'" })
changedFields!: string[];
@Column({ type: 'jsonb' })
snapshot!: Record<string, unknown>;
@Column({ name: 'occurred_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
occurredAt!: Date;
@Column({ name: 'actor_user_id', type: 'uuid', nullable: true })
actorUserId!: string | null;
@Column({ name: 'actor_username', type: 'varchar', length: 80, nullable: true })
actorUsername!: string | null;
@Column({ type: 'varchar', length: 32 })
source!: string;
@Column({ name: 'request_id', type: 'varchar', length: 128, nullable: true })
requestId!: string | null;
}
@@ -0,0 +1,115 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum AssetInformationStatus {
DRAFT = 'DRAFT',
PENDING_SURVEY = 'PENDING_SURVEY',
SURVEYED = 'SURVEYED',
VALIDATED = 'VALIDATED',
OBSERVED = 'OBSERVED',
OUTDATED = 'OUTDATED',
INACTIVE = 'INACTIVE',
}
export enum AssetOperationalStatus {
UNKNOWN = 'UNKNOWN',
IN_SERVICE = 'IN_SERVICE',
TEMPORARILY_OUT_OF_SERVICE = 'TEMPORARILY_OUT_OF_SERVICE',
OUT_OF_SERVICE = 'OUT_OF_SERVICE',
DECOMMISSIONED = 'DECOMMISSIONED',
ABANDONED = 'ABANDONED',
}
export enum AssetDataOrigin {
MANUAL = 'MANUAL',
FIELD_SURVEY = 'FIELD_SURVEY',
PROVIDED_DOCUMENT = 'PROVIDED_DOCUMENT',
IMPORT = 'IMPORT',
SYSTEM = 'SYSTEM',
}
@Entity({ name: 'assets' })
@Index('idx_assets_type_id', ['assetTypeId'])
@Index('idx_assets_parent_id', ['parentId'])
@Index('idx_assets_operational_area_id', ['operationalAreaId'])
@Index('idx_assets_operator_company_id', ['operatorCompanyId'])
@Index('idx_assets_information_status', ['informationStatus'])
@Index('idx_assets_operational_status', ['operationalStatus'])
@Index('idx_assets_data_origin', ['dataOrigin'])
@Index('idx_assets_provenance_verified_at', ['provenanceVerifiedAt'])
export class Asset extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'asset_type_id', type: 'uuid' })
assetTypeId!: string;
@Column({ name: 'parent_id', type: 'uuid', nullable: true })
parentId!: string | null;
@Column({ name: 'operational_area_id', type: 'uuid', nullable: true })
operationalAreaId!: string | null;
@Column({ name: 'operator_company_id', type: 'uuid', nullable: true })
operatorCompanyId!: string | null;
@Column({ type: 'varchar', length: 120 })
code!: string;
@Column({ type: 'varchar', length: 200 })
name!: string;
@Column({ name: 'common_name', type: 'varchar', length: 200, nullable: true })
commonName!: string | null;
@Column({ type: 'text', nullable: true })
description!: string | null;
@Column({
name: 'information_status',
type: 'enum',
enum: AssetInformationStatus,
enumName: 'asset_information_status',
default: AssetInformationStatus.DRAFT,
})
informationStatus!: AssetInformationStatus;
@Column({ name: 'operational_status', type: 'enum', enum: AssetOperationalStatus, enumName: 'asset_operational_status', default: AssetOperationalStatus.UNKNOWN })
operationalStatus!: AssetOperationalStatus;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
@Column({ name: 'current_version', type: 'integer', default: 0 })
currentVersion!: number;
@Column({ name: 'data_origin', type: 'varchar', length: 32, default: AssetDataOrigin.MANUAL })
dataOrigin!: AssetDataOrigin;
@Column({ name: 'source_name', type: 'varchar', length: 160, nullable: true })
sourceName!: string | null;
@Column({ name: 'source_reference', type: 'varchar', length: 255, nullable: true })
sourceReference!: string | null;
@Column({ name: 'source_observed_at', type: 'timestamptz', nullable: true })
sourceObservedAt!: Date | null;
@Column({ name: 'source_notes', type: 'text', nullable: true })
sourceNotes!: string | null;
@Column({ name: 'provenance_verified_at', type: 'timestamptz', nullable: true })
provenanceVerifiedAt!: Date | null;
@Column({ name: 'provenance_verified_by', type: 'uuid', nullable: true })
provenanceVerifiedBy!: string | null;
@Column({ name: 'provenance_updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
provenanceUpdatedAt!: Date;
@Column({ name: 'provenance_updated_by', type: 'uuid', nullable: true })
provenanceUpdatedBy!: string | null;
}
@@ -0,0 +1,163 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum AuditSource {
WEB = 'WEB',
ANDROID = 'ANDROID',
SYSTEM = 'SYSTEM',
IMPORT = 'IMPORT',
}
export enum AuditAction {
AUTH_LOGIN_SUCCESS = 'AUTH_LOGIN_SUCCESS',
AUTH_LOGIN_FAILED = 'AUTH_LOGIN_FAILED',
AUTH_LOGOUT = 'AUTH_LOGOUT',
AUTH_REFRESH = 'AUTH_REFRESH',
AUTH_REFRESH_REUSE_DETECTED = 'AUTH_REFRESH_REUSE_DETECTED',
AUTH_PASSWORD_CHANGED = 'AUTH_PASSWORD_CHANGED',
SYSTEM_BOOTSTRAP_ADMIN_CREATED = 'SYSTEM_BOOTSTRAP_ADMIN_CREATED',
USER_CREATED = 'USER_CREATED',
USER_UPDATED = 'USER_UPDATED',
USER_PASSWORD_RESET = 'USER_PASSWORD_RESET',
USER_STATUS_CHANGED = 'USER_STATUS_CHANGED',
USER_ROLES_CHANGED = 'USER_ROLES_CHANGED',
ROLE_CREATED = 'ROLE_CREATED',
ROLE_UPDATED = 'ROLE_UPDATED',
ROLE_PERMISSIONS_CHANGED = 'ROLE_PERMISSIONS_CHANGED',
ASSET_TYPE_CREATED = 'ASSET_TYPE_CREATED',
ASSET_TYPE_UPDATED = 'ASSET_TYPE_UPDATED',
ASSET_MASTER_BOOTSTRAPPED = 'ASSET_MASTER_BOOTSTRAPPED',
ASSET_ATTRIBUTE_CREATED = 'ASSET_ATTRIBUTE_CREATED',
ASSET_ATTRIBUTE_UPDATED = 'ASSET_ATTRIBUTE_UPDATED',
ASSET_CREATED = 'ASSET_CREATED',
ASSET_FIELD_DISCOVERY_CREATED = 'ASSET_FIELD_DISCOVERY_CREATED',
ASSET_FIELD_DISCOVERY_APPROVED = 'ASSET_FIELD_DISCOVERY_APPROVED',
ASSET_FIELD_DISCOVERY_MATCHED = 'ASSET_FIELD_DISCOVERY_MATCHED',
ASSET_FIELD_DISCOVERY_REJECTED = 'ASSET_FIELD_DISCOVERY_REJECTED',
ASSET_UPDATED = 'ASSET_UPDATED',
ASSET_CONTEXT_CHANGED = 'ASSET_CONTEXT_CHANGED',
ASSET_INFORMATION_STATUS_CHANGED = 'ASSET_INFORMATION_STATUS_CHANGED',
ASSET_OPERATIONAL_STATUS_CHANGED = 'ASSET_OPERATIONAL_STATUS_CHANGED',
ASSET_REGISTRY_UPDATED = 'ASSET_REGISTRY_UPDATED',
ASSET_IMPORT_BATCH_ANALYZED = 'ASSET_IMPORT_BATCH_ANALYZED',
ASSET_IMPORT_BATCH_RECONCILED = 'ASSET_IMPORT_BATCH_RECONCILED',
ASSET_IMPORT_PLAN_GENERATED = 'ASSET_IMPORT_PLAN_GENERATED',
ASSET_IMPORT_PLAN_ITEM_RESOLVED = 'ASSET_IMPORT_PLAN_ITEM_RESOLVED',
ASSET_IMPORT_PLAN_APPLIED = 'ASSET_IMPORT_PLAN_APPLIED',
ASSET_IMPORT_PLAN_ROLLED_BACK = 'ASSET_IMPORT_PLAN_ROLLED_BACK',
ASSET_IMPORT_BATCH_CANCELLED = 'ASSET_IMPORT_BATCH_CANCELLED',
SOURCE_DOCUMENT_CREATED = 'SOURCE_DOCUMENT_CREATED',
AREA_LEGAL_RIGHT_CREATED = 'AREA_LEGAL_RIGHT_CREATED',
AREA_LEGAL_RIGHT_UPDATED = 'AREA_LEGAL_RIGHT_UPDATED',
AREA_LEGAL_RIGHT_ORGANIZATION_ENDED = 'AREA_LEGAL_RIGHT_ORGANIZATION_ENDED',
ASSET_GEOMETRY_UPDATED = 'ASSET_GEOMETRY_UPDATED',
ASSET_GEOMETRY_REMOVED = 'ASSET_GEOMETRY_REMOVED',
ASSET_MEDIA_UPLOADED = 'ASSET_MEDIA_UPLOADED',
ASSET_MEDIA_UPDATED = 'ASSET_MEDIA_UPDATED',
ASSET_MEDIA_REMOVED = 'ASSET_MEDIA_REMOVED',
ASSET_PROVENANCE_UPDATED = 'ASSET_PROVENANCE_UPDATED',
ASSET_PROVENANCE_VERIFIED = 'ASSET_PROVENANCE_VERIFIED',
ASSET_AREA_COMPANY_RELATION_CREATED = 'ASSET_AREA_COMPANY_RELATION_CREATED',
ASSET_AREA_COMPANY_RELATION_ENDED = 'ASSET_AREA_COMPANY_RELATION_ENDED',
SURVEY_CAMPAIGN_CREATED = 'SURVEY_CAMPAIGN_CREATED',
SURVEY_CAMPAIGN_UPDATED = 'SURVEY_CAMPAIGN_UPDATED',
SURVEY_CAMPAIGN_STATUS_CHANGED = 'SURVEY_CAMPAIGN_STATUS_CHANGED',
SURVEY_TARGET_ADDED = 'SURVEY_TARGET_ADDED',
SURVEY_TARGET_UPDATED = 'SURVEY_TARGET_UPDATED',
SURVEY_TARGET_ASSIGNED = 'SURVEY_TARGET_ASSIGNED',
SURVEY_TARGET_STATUS_CHANGED = 'SURVEY_TARGET_STATUS_CHANGED',
SURVEY_REPORT_SAVED = 'SURVEY_REPORT_SAVED',
SURVEY_REPORT_SUBMITTED = 'SURVEY_REPORT_SUBMITTED',
SURVEY_REPORT_APPROVED = 'SURVEY_REPORT_APPROVED',
SURVEY_REPORT_REJECTED = 'SURVEY_REPORT_REJECTED',
INSPECTION_VISIT_CREATED = 'INSPECTION_VISIT_CREATED',
INSPECTION_VISIT_UPDATED = 'INSPECTION_VISIT_UPDATED',
INSPECTION_VISIT_STATUS_CHANGED = 'INSPECTION_VISIT_STATUS_CHANGED',
INSPECTION_VISIT_ASSETS_UPDATED = 'INSPECTION_VISIT_ASSETS_UPDATED',
INSPECTION_VISIT_TEAM_UPDATED = 'INSPECTION_VISIT_TEAM_UPDATED',
INSPECTION_VISIT_CHECKLIST_GENERATED = 'INSPECTION_VISIT_CHECKLIST_GENERATED',
INSPECTION_VISIT_ASSET_EXCLUDED = 'INSPECTION_VISIT_ASSET_EXCLUDED',
INSPECTION_VISIT_ASSET_REINCLUDED = 'INSPECTION_VISIT_ASSET_REINCLUDED',
INSPECTION_VISIT_STARTED = 'INSPECTION_VISIT_STARTED',
INSPECTION_ACT_CREATED = 'INSPECTION_ACT_CREATED',
INSPECTION_ACT_UPDATED = 'INSPECTION_ACT_UPDATED',
INSPECTION_ACT_CANCELLED = 'INSPECTION_ACT_CANCELLED',
INSPECTION_ACT_RESPONSIBLE_UPDATED = 'INSPECTION_ACT_RESPONSIBLE_UPDATED',
INSPECTION_ACT_READY = 'INSPECTION_ACT_READY',
INSPECTION_ACT_REOPENED = 'INSPECTION_ACT_REOPENED',
INSPECTION_ACT_SIGNATURE_RECORDED = 'INSPECTION_ACT_SIGNATURE_RECORDED',
INSPECTION_ACT_COMPANY_OUTCOME_RECORDED = 'INSPECTION_ACT_COMPANY_OUTCOME_RECORDED',
INSPECTION_ACT_CLOSED = 'INSPECTION_ACT_CLOSED',
INSPECTION_REPORT_GENERATED = 'INSPECTION_REPORT_GENERATED',
INSPECTION_REPORT_REVISION_ADDED = 'INSPECTION_REPORT_REVISION_ADDED',
INSPECTION_REPORT_APPROVED = 'INSPECTION_REPORT_APPROVED',
INSPECTION_REPORT_SIGNED = 'INSPECTION_REPORT_SIGNED',
DOCUMENT_DELIVERY_SETTINGS_UPDATED = 'DOCUMENT_DELIVERY_SETTINGS_UPDATED',
DOCUMENT_DELIVERY_RETRY_REQUESTED = 'DOCUMENT_DELIVERY_RETRY_REQUESTED',
DOCUMENT_DELIVERY_SENT = 'DOCUMENT_DELIVERY_SENT',
INSPECTION_VERIFICATION_PLANNED = 'INSPECTION_VERIFICATION_PLANNED',
INSPECTION_VERIFICATION_RESULT_RECORDED = 'INSPECTION_VERIFICATION_RESULT_RECORDED',
INSPECTION_FINDING_CREATED = 'INSPECTION_FINDING_CREATED',
INSPECTION_FINDING_UPDATED = 'INSPECTION_FINDING_UPDATED',
INSPECTION_FINDING_FOLLOW_UP_UPDATED = 'INSPECTION_FINDING_FOLLOW_UP_UPDATED',
INSPECTION_FINDING_CLOSED = 'INSPECTION_FINDING_CLOSED',
INSPECTION_FINDING_EVIDENCE_UPLOADED = 'INSPECTION_FINDING_EVIDENCE_UPLOADED',
INSPECTION_FINDING_COMMUNICATION_CREATED = 'INSPECTION_FINDING_COMMUNICATION_CREATED',
FINDING_CATEGORY_CREATED = 'FINDING_CATEGORY_CREATED',
FINDING_CATEGORY_UPDATED = 'FINDING_CATEGORY_UPDATED',
FINDING_CATALOG_ITEM_CREATED = 'FINDING_CATALOG_ITEM_CREATED',
FINDING_CATALOG_ITEM_UPDATED = 'FINDING_CATALOG_ITEM_UPDATED',
FINDING_CATALOG_TYPE_APPLICABILITY_UPDATED = 'FINDING_CATALOG_TYPE_APPLICABILITY_UPDATED',
FINDING_CATALOG_ASSET_SELECTION_UPDATED = 'FINDING_CATALOG_ASSET_SELECTION_UPDATED',
FINDING_CATALOG_PROPOSAL_MATCHED = 'FINDING_CATALOG_PROPOSAL_MATCHED',
FINDING_CATALOG_PROPOSAL_REJECTED = 'FINDING_CATALOG_PROPOSAL_REJECTED',
}
@Entity({ name: 'audit_events' })
@Index('idx_audit_events_occurred_at', ['occurredAt'])
@Index('idx_audit_events_actor_user_id', ['actorUserId'])
@Index('idx_audit_events_action', ['action'])
@Index('idx_audit_events_entity', ['entityType', 'entityId'])
@Index('idx_audit_events_request_id', ['requestId'])
export class AuditEvent {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'occurred_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
occurredAt!: Date;
@Column({ name: 'actor_user_id', type: 'uuid', nullable: true })
actorUserId!: string | null;
@Column({ name: 'actor_username', type: 'varchar', length: 80, nullable: true })
actorUsername!: string | null;
@Column({ type: 'varchar', length: 100 })
action!: string;
@Column({ name: 'entity_type', type: 'varchar', length: 100, nullable: true })
entityType!: string | null;
@Column({ name: 'entity_id', type: 'varchar', length: 255, nullable: true })
entityId!: string | null;
@Column({ name: 'request_id', type: 'varchar', length: 128, nullable: true })
requestId!: string | null;
@Column({ type: 'varchar', length: 32 })
source!: AuditSource;
@Column({ type: 'inet', nullable: true })
ip!: string | null;
@Column({ name: 'user_agent', type: 'text', nullable: true })
userAgent!: string | null;
@Column({ name: 'before_data', type: 'jsonb', nullable: true })
beforeData!: Record<string, unknown> | null;
@Column({ name: 'after_data', type: 'jsonb', nullable: true })
afterData!: Record<string, unknown> | null;
@Column({ type: 'jsonb', nullable: true })
metadata!: Record<string, unknown> | null;
}
@@ -0,0 +1,54 @@
import {
Column,
CreateDateColumn,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import { User } from './user.entity';
@Entity({ name: 'auth_sessions' })
@Index('idx_auth_sessions_user_id', ['userId'])
@Index('idx_auth_sessions_expires_at', ['expiresAt'])
@Index('idx_auth_sessions_revoked_at', ['revokedAt'])
@Index('idx_auth_sessions_replaced_by_session_id', ['replacedBySessionId'])
export class AuthSession {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'user_id', type: 'uuid' })
userId!: string;
@Column({ name: 'refresh_token_hash', type: 'text', select: false })
refreshTokenHash!: string;
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
createdAt!: Date;
@Column({ name: 'expires_at', type: 'timestamptz' })
expiresAt!: Date;
@Column({ name: 'last_used_at', type: 'timestamptz' })
lastUsedAt!: Date;
@Column({ name: 'revoked_at', type: 'timestamptz', nullable: true })
revokedAt!: Date | null;
@Column({ name: 'replaced_by_session_id', type: 'uuid', nullable: true })
replacedBySessionId!: string | null;
@Column({ type: 'inet', nullable: true })
ip!: string | null;
@Column({ name: 'user_agent', type: 'text', nullable: true })
userAgent!: string | null;
@Column({ name: 'device_label', type: 'text', nullable: true })
deviceLabel!: string | null;
@ManyToOne(() => User, { onDelete: 'RESTRICT' })
@JoinColumn({ name: 'user_id' })
user!: User;
}
@@ -0,0 +1,21 @@
import { Column, Entity, PrimaryColumn, UpdateDateColumn } from 'typeorm';
export enum DocumentSequenceType {
ACT = 'ACT',
REPORT = 'REPORT',
}
@Entity({ name: 'document_annual_sequences' })
export class DocumentAnnualSequence {
@PrimaryColumn({ name: 'document_type', type: 'varchar', length: 20 })
documentType!: DocumentSequenceType;
@PrimaryColumn({ type: 'integer' })
year!: number;
@Column({ name: 'last_number', type: 'integer', default: 0 })
lastNumber!: number;
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
updatedAt!: Date;
}
@@ -0,0 +1,28 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'finding_catalog_asset_overrides' })
@Index('uq_finding_catalog_asset_overrides_pair', ['assetId', 'catalogItemId'], { unique: true })
@Index('idx_finding_catalog_asset_overrides_asset', ['assetId'])
export class FindingCatalogAssetOverride extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ name: 'catalog_item_id', type: 'uuid' })
catalogItemId!: string;
@Column({ name: 'is_enabled', type: 'boolean' })
isEnabled!: boolean;
@Column({ type: 'text' })
reason!: string;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,15 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'finding_catalog_asset_type_profiles' })
@Index('idx_finding_catalog_asset_type_profiles_updated', ['updatedAt'])
export class FindingCatalogAssetTypeProfile extends TimestampedEntity {
@PrimaryColumn({ name: 'asset_type_id', type: 'uuid' })
assetTypeId!: string;
@Column({ type: 'text' })
reason!: string;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,19 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'finding_catalog_item_asset_types' })
@Index('uq_finding_catalog_item_asset_types_pair', ['catalogItemId', 'assetTypeId'], { unique: true })
@Index('idx_finding_catalog_item_asset_types_type', ['assetTypeId', 'catalogItemId'])
export class FindingCatalogItemAssetType extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'catalog_item_id', type: 'uuid' })
catalogItemId!: string;
@Column({ name: 'asset_type_id', type: 'uuid' })
assetTypeId!: string;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
}
@@ -0,0 +1,41 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'finding_catalog_items' })
@Index('uq_finding_catalog_items_code', ['code'], { unique: true })
@Index('uq_finding_catalog_items_source', ['categoryId', 'sourceNumber'], { unique: true })
@Index('idx_finding_catalog_items_active', ['categoryId', 'isActive'])
export class FindingCatalogItem extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'category_id', type: 'uuid' })
categoryId!: string;
@Column({ type: 'varchar', length: 120 })
code!: string;
@Column({ name: 'source_number', type: 'integer' })
sourceNumber!: number;
@Column({ type: 'varchar', length: 500 })
title!: string;
@Column({ name: 'legal_basis', type: 'text', nullable: true })
legalBasis!: string | null;
@Column({ type: 'text', nullable: true })
glossary!: string | null;
@Column({ name: 'import_note', type: 'text', nullable: true })
importNote!: string | null;
@Column({ name: 'suggested_severity', type: 'smallint', nullable: true })
suggestedSeverity!: number | null;
@Column({ type: 'integer', default: 1 })
revision!: number;
@Column({ name: 'is_active', type: 'boolean', default: true })
isActive!: boolean;
}
@@ -0,0 +1,56 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum FindingCatalogProposalStatus {
PENDING = 'PENDING',
MATCHED = 'MATCHED',
REJECTED = 'REJECTED',
}
@Entity({ name: 'finding_catalog_proposals' })
@Index('uq_finding_catalog_proposals_finding', ['findingId'], { unique: true })
@Index('idx_finding_catalog_proposals_status', ['status', 'createdAt'])
@Index('idx_finding_catalog_proposals_asset_type', ['assetTypeId', 'status'])
export class FindingCatalogProposal extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'finding_id', type: 'uuid' })
findingId!: string;
@Column({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ name: 'asset_type_id', type: 'uuid' })
assetTypeId!: string;
@Column({ name: 'proposed_title', type: 'varchar', length: 500 })
proposedTitle!: string;
@Column({ name: 'proposed_legal_basis', type: 'text', nullable: true })
proposedLegalBasis!: string | null;
@Column({ name: 'proposed_severity', type: 'smallint', nullable: true })
proposedSeverity!: number | null;
@Column({ type: 'text' })
description!: string;
@Column({ type: 'varchar', length: 20, default: FindingCatalogProposalStatus.PENDING })
status!: FindingCatalogProposalStatus;
@Column({ name: 'resolved_catalog_item_id', type: 'uuid', nullable: true })
resolvedCatalogItemId!: string | null;
@Column({ name: 'office_notes', type: 'text', nullable: true })
officeNotes!: string | null;
@Column({ name: 'reviewed_by', type: 'uuid', nullable: true })
reviewedBy!: string | null;
@Column({ name: 'reviewed_at', type: 'timestamptz', nullable: true })
reviewedAt!: Date | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
}
@@ -0,0 +1,22 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'finding_categories' })
@Index('uq_finding_categories_code', ['code'], { unique: true })
@Index('idx_finding_categories_active_order', ['isActive', 'sortOrder'])
export class FindingCategory extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 80 })
code!: string;
@Column({ type: 'varchar', length: 200 })
name!: string;
@Column({ name: 'sort_order', type: 'integer', default: 0 })
sortOrder!: number;
@Column({ name: 'is_active', type: 'boolean', default: true })
isActive!: boolean;
}
+237
View File
@@ -0,0 +1,237 @@
export { AuditAction, AuditEvent, AuditSource } from './audit-event.entity';
export { AuthSession } from './auth-session.entity';
export { Permission } from './permission.entity';
export { RolePermission } from './role-permission.entity';
export { Role } from './role.entity';
export { UserRole } from './user-role.entity';
export { User, UserStatus } from './user.entity';
export { Asset, AssetDataOrigin, AssetInformationStatus, AssetOperationalStatus } from './asset.entity';
export {
AssetVersion,
AssetVersionChangeType,
} from './asset-version.entity';
export {
AssetAttributeDataType,
AssetAttributeDefinition,
} from './asset-attribute-definition.entity';
export { AssetAttributeValue } from './asset-attribute-value.entity';
export { AreaCompanyRelation, AreaOrganizationRole } from './area-company-relation.entity';
export { OrganizationProfile, OrganizationKind } from './organization-profile.entity';
export { OrganizationMembership, OrganizationMembershipRole } from './organization-membership.entity';
export { SourceDocument, SourceDocumentType } from './source-document.entity';
export { AssetSourceDocument, AssetSourceDocumentRelationType } from './asset-source-document.entity';
export { AssetExternalIdentifier } from './asset-external-identifier.entity';
export { AreaLegalRight, AreaLegalRightType, AreaLegalRightStatus } from './area-legal-right.entity';
export { AreaLegalRightOrganization, AreaLegalRightOrganizationRole } from './area-legal-right-organization.entity';
export { AssetTypeParentRule } from './asset-type-parent-rule.entity';
export { AssetType, AssetTypeOperationalRole } from './asset-type.entity';
export {
AssetGeometry,
AssetGeometrySource,
AssetGeometryType,
} from './asset-geometry.entity';
export {
AssetMedia,
AssetMediaKind,
AssetMediaSource,
} from './asset-media.entity';
export {
SurveyCampaign,
SurveyCampaignStatus,
} from './survey-campaign.entity';
export {
SurveyCampaignTarget,
SurveyTargetStatus,
} from './survey-campaign-target.entity';
export {
SurveyReportOutcome,
SurveyReportStatus,
SurveyTargetReport,
} from './survey-target-report.entity';
export { SurveyTargetReportMedia } from './survey-target-report-media.entity';
export {
SurveyReportVersionEvent,
SurveyTargetReportVersion,
} from './survey-target-report-version.entity';
export {
InspectionVisit,
InspectionVisitStatus,
} from './inspection-visit.entity';
export { InspectionVisitAsset, InspectionVisitAssetPlanningSource } from './inspection-visit-asset.entity';
export { InspectionVisitMember } from './inspection-visit-member.entity';
export {
DocumentAnnualSequence,
DocumentSequenceType,
} from './document-annual-sequence.entity';
export {
InspectionAct,
InspectionActStatus,
} from './inspection-act.entity';
export { InspectionActAsset } from './inspection-act-asset.entity';
export {
InspectionReport,
InspectionReportPdfStatus,
InspectionReportReviewStatus,
InspectionReportStatus,
InspectionReportWordStatus,
} from './inspection-report.entity';
export {
InspectionActVersion,
InspectionActVersionEvent,
} from './inspection-act-version.entity';
export {
InspectionActResponsible,
InspectionResponsibleAttendanceStatus,
InspectionResponsibleDocumentType,
} from './inspection-act-responsible.entity';
export {
InspectionActClosure,
InspectionActUploadMode,
} from './inspection-act-closure.entity';
export {
InspectionActSignature,
InspectionActSignatureSource,
InspectionActSignatureStatus,
InspectionActSignerType,
} from './inspection-act-signature.entity';
export { FindingCategory } from './finding-category.entity';
export { FindingCatalogItem } from './finding-catalog-item.entity';
export { FindingCatalogItemAssetType } from './finding-catalog-item-asset-type.entity';
export { FindingCatalogAssetTypeProfile } from './finding-catalog-asset-type-profile.entity';
export { FindingCatalogAssetOverride } from './finding-catalog-asset-override.entity';
export { FindingCatalogProposal, FindingCatalogProposalStatus } from './finding-catalog-proposal.entity';
export {
InspectionFinding,
InspectionFindingResponseDueBasis,
InspectionFindingStatus,
} from './inspection-finding.entity';
export {
InspectionFindingVersion,
InspectionFindingVersionEvent,
} from './inspection-finding-version.entity';
export {
InspectionCommunicationChannel,
InspectionCommunicationDirection,
InspectionCommunicationType,
InspectionFindingCommunication,
} from './inspection-finding-communication.entity';
export {
InspectionEvidenceKind,
InspectionEvidencePurpose,
InspectionEvidenceSource,
InspectionFindingEvidence,
} from './inspection-finding-evidence.entity';
export {
InspectionFindingVerificationVisit,
InspectionVerificationOutcome,
} from './inspection-finding-verification-visit.entity';
export {
InspectionFindingVerificationEvent,
InspectionFindingVerificationEventType,
} from './inspection-finding-verification-event.entity';
import { AuditEvent } from './audit-event.entity';
import { AuthSession } from './auth-session.entity';
import { Permission } from './permission.entity';
import { RolePermission } from './role-permission.entity';
import { Role } from './role.entity';
import { UserRole } from './user-role.entity';
import { User } from './user.entity';
import { Asset } from './asset.entity';
import { AssetAttributeDefinition } from './asset-attribute-definition.entity';
import { AssetAttributeValue } from './asset-attribute-value.entity';
import { AssetTypeParentRule } from './asset-type-parent-rule.entity';
import { AssetType } from './asset-type.entity';
import { AreaCompanyRelation } from './area-company-relation.entity';
import { OrganizationProfile } from './organization-profile.entity';
import { OrganizationMembership } from './organization-membership.entity';
import { SourceDocument } from './source-document.entity';
import { AssetSourceDocument } from './asset-source-document.entity';
import { AssetExternalIdentifier } from './asset-external-identifier.entity';
import { AreaLegalRight } from './area-legal-right.entity';
import { AreaLegalRightOrganization } from './area-legal-right-organization.entity';
import { AssetGeometry } from './asset-geometry.entity';
import { AssetVersion } from './asset-version.entity';
import { AssetMedia } from './asset-media.entity';
import { SurveyCampaign } from './survey-campaign.entity';
import { SurveyCampaignTarget } from './survey-campaign-target.entity';
import { SurveyTargetReport } from './survey-target-report.entity';
import { SurveyTargetReportMedia } from './survey-target-report-media.entity';
import { SurveyTargetReportVersion } from './survey-target-report-version.entity';
import { InspectionVisit } from './inspection-visit.entity';
import { InspectionVisitAsset } from './inspection-visit-asset.entity';
import { InspectionVisitMember } from './inspection-visit-member.entity';
import { DocumentAnnualSequence } from './document-annual-sequence.entity';
import { InspectionAct } from './inspection-act.entity';
import { InspectionActAsset } from './inspection-act-asset.entity';
import { InspectionReport } from './inspection-report.entity';
import { InspectionActVersion } from './inspection-act-version.entity';
import { InspectionActResponsible } from './inspection-act-responsible.entity';
import { InspectionActClosure } from './inspection-act-closure.entity';
import { InspectionActSignature } from './inspection-act-signature.entity';
import { FindingCategory } from './finding-category.entity';
import { FindingCatalogItem } from './finding-catalog-item.entity';
import { FindingCatalogItemAssetType } from './finding-catalog-item-asset-type.entity';
import { FindingCatalogAssetTypeProfile } from './finding-catalog-asset-type-profile.entity';
import { FindingCatalogAssetOverride } from './finding-catalog-asset-override.entity';
import { FindingCatalogProposal } from './finding-catalog-proposal.entity';
import { InspectionFinding } from './inspection-finding.entity';
import { InspectionFindingVersion } from './inspection-finding-version.entity';
import { InspectionFindingCommunication } from './inspection-finding-communication.entity';
import { InspectionFindingEvidence } from './inspection-finding-evidence.entity';
import { InspectionFindingVerificationVisit } from './inspection-finding-verification-visit.entity';
import { InspectionFindingVerificationEvent } from './inspection-finding-verification-event.entity';
export const PHASE_A_ENTITIES = [
User,
Role,
Permission,
UserRole,
RolePermission,
AuthSession,
AuditEvent,
AssetType,
AssetTypeParentRule,
AssetAttributeDefinition,
Asset,
AssetAttributeValue,
AreaCompanyRelation,
OrganizationProfile,
OrganizationMembership,
SourceDocument,
AssetSourceDocument,
AssetExternalIdentifier,
AreaLegalRight,
AreaLegalRightOrganization,
AssetGeometry,
AssetVersion,
AssetMedia,
SurveyCampaign,
SurveyCampaignTarget,
SurveyTargetReport,
SurveyTargetReportMedia,
SurveyTargetReportVersion,
InspectionVisit,
InspectionVisitAsset,
InspectionVisitMember,
DocumentAnnualSequence,
InspectionAct,
InspectionActAsset,
InspectionReport,
InspectionActVersion,
InspectionActResponsible,
InspectionActClosure,
InspectionActSignature,
FindingCategory,
FindingCatalogItem,
FindingCatalogItemAssetType,
FindingCatalogAssetTypeProfile,
FindingCatalogAssetOverride,
FindingCatalogProposal,
InspectionFinding,
InspectionFindingVersion,
InspectionFindingCommunication,
InspectionFindingEvidence,
InspectionFindingVerificationVisit,
InspectionFindingVerificationEvent,
];
@@ -0,0 +1,19 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'inspection_act_assets' })
@Index('idx_inspection_act_assets_asset_id', ['assetId'])
@Index('idx_inspection_act_assets_included', ['actId', 'included'])
export class InspectionActAsset extends TimestampedEntity {
@PrimaryColumn({ name: 'act_id', type: 'uuid' })
actId!: string;
@PrimaryColumn({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ type: 'boolean', default: true })
included!: boolean;
@Column({ name: 'added_by', type: 'uuid', nullable: true })
addedBy!: string | null;
}
@@ -0,0 +1,51 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
export enum InspectionActUploadMode {
IMMEDIATE = 'IMMEDIATE',
DEFERRED = 'DEFERRED',
}
@Entity({ name: 'inspection_act_closures' })
export class InspectionActClosure {
@PrimaryColumn({ name: 'act_id', type: 'uuid' })
actId!: string;
@Column({ name: 'schema_version', type: 'varchar', length: 40 })
schemaVersion!: string;
@Column({ name: 'prepared_snapshot', type: 'jsonb' })
preparedSnapshot!: Record<string, unknown>;
@Column({ name: 'prepared_sha256', type: 'char', length: 64 })
preparedSha256!: string;
@Column({ name: 'prepared_at', type: 'timestamptz' })
preparedAt!: Date;
@Column({ name: 'prepared_by', type: 'uuid' })
preparedBy!: string;
@Column({ name: 'final_snapshot', type: 'jsonb', nullable: true })
finalSnapshot!: Record<string, unknown> | null;
@Column({ name: 'final_sha256', type: 'char', length: 64, nullable: true })
finalSha256!: string | null;
@Column({ name: 'device_closed_at', type: 'timestamptz', nullable: true })
deviceClosedAt!: Date | null;
@Column({ name: 'server_closed_at', type: 'timestamptz', nullable: true })
serverClosedAt!: Date | null;
@Column({ name: 'upload_mode', type: 'varchar', length: 20, nullable: true })
uploadMode!: InspectionActUploadMode | null;
@Column({ name: 'closed_by', type: 'uuid', nullable: true })
closedBy!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
@Column({ name: 'updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
updatedAt!: Date;
}
@@ -0,0 +1,52 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
export enum InspectionResponsibleAttendanceStatus {
PRESENT = 'PRESENT',
ABSENT = 'ABSENT',
}
export enum InspectionResponsibleDocumentType {
DNI = 'DNI',
CUIL = 'CUIL',
PASSPORT = 'PASSPORT',
OTHER = 'OTHER',
}
@Entity({ name: 'inspection_act_responsibles' })
export class InspectionActResponsible {
@PrimaryColumn({ name: 'act_id', type: 'uuid' })
actId!: string;
@Column({ name: 'attendance_status', type: 'varchar', length: 20 })
attendanceStatus!: InspectionResponsibleAttendanceStatus;
@Column({ name: 'full_name', type: 'varchar', length: 200, nullable: true })
fullName!: string | null;
@Column({ name: 'document_type', type: 'varchar', length: 20, nullable: true })
documentType!: InspectionResponsibleDocumentType | null;
@Column({ name: 'document_number', type: 'varchar', length: 40, nullable: true })
documentNumber!: string | null;
@Column({ type: 'varchar', length: 200, nullable: true })
position!: string | null;
@Column({ type: 'varchar', length: 320, nullable: true })
email!: string | null;
@Column({ type: 'varchar', length: 50, nullable: true })
phone!: string | null;
@Column({ name: 'absence_reason', type: 'text', nullable: true })
absenceReason!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
@Column({ name: 'updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
updatedAt!: Date;
}
@@ -0,0 +1,110 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { InspectionResponsibleDocumentType } from './inspection-act-responsible.entity';
export enum InspectionActSignerType {
INSPECTOR = 'INSPECTOR',
COMPANY_RESPONSIBLE = 'COMPANY_RESPONSIBLE',
}
export enum InspectionActSignatureStatus {
SIGNED = 'SIGNED',
REFUSED = 'REFUSED',
ABSENT = 'ABSENT',
}
export enum InspectionActSignatureSource {
WEB = 'WEB',
ANDROID = 'ANDROID',
}
@Entity({ name: 'inspection_act_signatures' })
@Index('idx_inspection_act_signatures_act_created', ['actId', 'createdAt'])
@Index('idx_inspection_act_signatures_sha256', ['signaturePayloadSha256'])
export class InspectionActSignature {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'act_id', type: 'uuid' })
actId!: string;
@Column({ name: 'signer_type', type: 'varchar', length: 32 })
signerType!: InspectionActSignerType;
@Column({ name: 'signer_user_id', type: 'uuid', nullable: true })
signerUserId!: string | null;
@Column({ name: 'signer_name', type: 'varchar', length: 200 })
signerName!: string;
@Column({ name: 'document_type', type: 'varchar', length: 20, nullable: true })
documentType!: InspectionResponsibleDocumentType | null;
@Column({ name: 'document_number', type: 'varchar', length: 40, nullable: true })
documentNumber!: string | null;
@Column({ type: 'varchar', length: 200, nullable: true })
position!: string | null;
@Column({ type: 'varchar', length: 20 })
status!: InspectionActSignatureStatus;
@Column({ type: 'text', nullable: true })
reason!: string | null;
@Column({ name: 'original_name', type: 'varchar', length: 255, nullable: true })
originalName!: string | null;
@Column({ name: 'stored_name', type: 'varchar', length: 80, nullable: true })
storedName!: string | null;
@Column({ name: 'mime_type', type: 'varchar', length: 100, nullable: true })
mimeType!: string | null;
@Column({ name: 'size_bytes', type: 'bigint', nullable: true })
sizeBytes!: number | null;
@Column({ name: 'image_sha256', type: 'char', length: 64, nullable: true })
imageSha256!: string | null;
@Column({ name: 'consent_text', type: 'text', nullable: true })
consentText!: string | null;
@Column({ name: 'consent_version', type: 'varchar', length: 20, nullable: true })
consentVersion!: string | null;
@Column({ name: 'consent_accepted_at', type: 'timestamptz', nullable: true })
consentAcceptedAt!: Date | null;
@Column({ name: 'client_signed_at', type: 'timestamptz', nullable: true })
clientSignedAt!: Date | null;
@Column({ name: 'signed_at', type: 'timestamptz', nullable: true })
signedAt!: Date | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
latitude!: number | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
longitude!: number | null;
@Column({ name: 'accuracy_m', type: 'numeric', precision: 12, scale: 3, nullable: true })
accuracyM!: number | null;
@Column({ name: 'device_label', type: 'varchar', length: 200, nullable: true })
deviceLabel!: string | null;
@Column({ type: 'varchar', length: 20 })
source!: InspectionActSignatureSource;
@Column({ name: 'prepared_sha256', type: 'char', length: 64 })
preparedSha256!: string;
@Column({ name: 'signature_payload_sha256', type: 'char', length: 64 })
signaturePayloadSha256!: string;
@Column({ name: 'uploaded_by', type: 'uuid' })
uploadedBy!: string;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,39 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum InspectionActVersionEvent {
CREATED = 'CREATED',
UPDATED = 'UPDATED',
READY = 'READY',
REOPENED = 'REOPENED',
CLOSED = 'CLOSED',
CANCELLED = 'CANCELLED',
}
@Entity({ name: 'inspection_act_versions' })
@Index('uq_inspection_act_versions_number', ['actId', 'versionNumber'], { unique: true })
@Index('idx_inspection_act_versions_created_at', ['createdAt'])
export class InspectionActVersion {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'act_id', type: 'uuid' })
actId!: string;
@Column({ name: 'version_number', type: 'integer' })
versionNumber!: number;
@Column({ type: 'varchar', length: 24 })
event!: InspectionActVersionEvent;
@Column({ type: 'jsonb' })
snapshot!: Record<string, unknown>;
@Column({ name: 'actor_user_id', type: 'uuid', nullable: true })
actorUserId!: string | null;
@Column({ name: 'actor_username', type: 'varchar', length: 80, nullable: true })
actorUsername!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,70 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum InspectionActStatus {
DRAFT = 'DRAFT',
READY = 'READY',
CLOSED = 'CLOSED',
CANCELLED = 'CANCELLED',
RECTIFIED = 'RECTIFIED',
}
@Entity({ name: 'inspection_acts' })
@Index('uq_inspection_acts_visit', ['visitId'], { unique: true })
@Index('uq_inspection_acts_year_number', ['actYear', 'actNumber'], { unique: true })
@Index('uq_inspection_acts_code', ['code'], { unique: true })
@Index('idx_inspection_acts_visit_status', ['visitId', 'status'])
@Index('idx_inspection_acts_occurred_at', ['occurredAt'])
@Index('idx_inspection_acts_created_by', ['createdBy'])
export class InspectionAct extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'visit_id', type: 'uuid' })
visitId!: string;
@Column({ name: 'act_year', type: 'integer' })
actYear!: number;
@Column({ name: 'act_number', type: 'integer' })
actNumber!: number;
@Column({ type: 'varchar', length: 24 })
code!: string;
@Column({ type: 'varchar', length: 24, default: InspectionActStatus.DRAFT })
status!: InspectionActStatus;
@Column({ name: 'occurred_at', type: 'timestamptz' })
occurredAt!: Date;
@Column({ type: 'varchar', length: 200 })
title!: string;
@Column({ type: 'text' })
summary!: string;
@Column({ type: 'text', nullable: true })
observations!: string | null;
@Column({ name: 'current_version', type: 'integer', default: 0 })
currentVersion!: number;
@Column({ name: 'cancellation_reason', type: 'text', nullable: true })
cancellationReason!: string | null;
@Column({ name: 'closed_at', type: 'timestamptz', nullable: true })
closedAt!: Date | null;
@Column({ name: 'closed_by', type: 'uuid', nullable: true })
closedBy!: string | null;
@Column({ name: 'closure_sha256', type: 'char', length: 64, nullable: true })
closureSha256!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,64 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum InspectionCommunicationDirection {
INBOUND = 'INBOUND',
OUTBOUND = 'OUTBOUND',
INTERNAL = 'INTERNAL',
}
export enum InspectionCommunicationChannel {
EMAIL = 'EMAIL',
IN_PERSON = 'IN_PERSON',
PHONE = 'PHONE',
LETTER = 'LETTER',
SYSTEM = 'SYSTEM',
OTHER = 'OTHER',
}
export enum InspectionCommunicationType {
COMPANY_RESPONSE = 'COMPANY_RESPONSE',
AUTHORITY_NOTICE = 'AUTHORITY_NOTICE',
FOLLOW_UP = 'FOLLOW_UP',
OTHER = 'OTHER',
}
@Entity({ name: 'inspection_finding_communications' })
@Index('uq_inspection_finding_communications_id_finding', ['id', 'findingId'], { unique: true })
@Index('idx_inspection_finding_communications_timeline', ['findingId', 'occurredAt'])
export class InspectionFindingCommunication {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'finding_id', type: 'uuid' })
findingId!: string;
@Column({ type: 'varchar', length: 20 })
direction!: InspectionCommunicationDirection;
@Column({ type: 'varchar', length: 20 })
channel!: InspectionCommunicationChannel;
@Column({ type: 'varchar', length: 32 })
type!: InspectionCommunicationType;
@Column({ name: 'occurred_at', type: 'timestamptz' })
occurredAt!: Date;
@Column({ type: 'varchar', length: 250 })
subject!: string;
@Column({ type: 'text', nullable: true })
details!: string | null;
@Column({ name: 'contact_name', type: 'varchar', length: 200, nullable: true })
contactName!: string | null;
@Column({ name: 'contact_email', type: 'varchar', length: 320, nullable: true })
contactEmail!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,89 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum InspectionEvidenceKind {
PHOTO = 'PHOTO',
DOCUMENT = 'DOCUMENT',
}
export enum InspectionEvidencePurpose {
OBSERVATION = 'OBSERVATION',
VERIFICATION = 'VERIFICATION',
COMPANY_RESPONSE = 'COMPANY_RESPONSE',
COMMUNICATION_ATTACHMENT = 'COMMUNICATION_ATTACHMENT',
OTHER_DOCUMENT = 'OTHER_DOCUMENT',
}
export enum InspectionEvidenceSource {
WEB = 'WEB',
ANDROID = 'ANDROID',
IMPORT = 'IMPORT',
}
@Entity({ name: 'inspection_finding_evidence' })
@Index('idx_inspection_finding_evidence_finding_created', ['findingId', 'createdAt'])
@Index('idx_inspection_finding_evidence_sha256', ['sha256'])
@Index('idx_inspection_finding_evidence_communication', ['communicationId'])
export class InspectionFindingEvidence {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'finding_id', type: 'uuid' })
findingId!: string;
@Column({ name: 'communication_id', type: 'uuid', nullable: true })
communicationId!: string | null;
@Column({ name: 'verification_visit_id', type: 'uuid', nullable: true })
verificationVisitId!: string | null;
@Column({ type: 'varchar', length: 20 })
kind!: InspectionEvidenceKind;
@Column({ type: 'varchar', length: 40 })
purpose!: InspectionEvidencePurpose;
@Column({ name: 'original_name', type: 'varchar', length: 255 })
originalName!: string;
@Column({ name: 'stored_name', type: 'varchar', length: 80 })
storedName!: string;
@Column({ name: 'mime_type', type: 'varchar', length: 100 })
mimeType!: string;
@Column({ name: 'size_bytes', type: 'bigint' })
sizeBytes!: string;
@Column({ type: 'char', length: 64 })
sha256!: string;
@Column({ type: 'varchar', length: 200, nullable: true })
title!: string | null;
@Column({ type: 'text', nullable: true })
description!: string | null;
@Column({ name: 'captured_at', type: 'timestamptz', nullable: true })
capturedAt!: Date | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
latitude!: string | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
longitude!: string | null;
@Column({ name: 'accuracy_m', type: 'numeric', precision: 12, scale: 3, nullable: true })
accuracyM!: string | null;
@Column({ name: 'device_label', type: 'varchar', length: 200, nullable: true })
deviceLabel!: string | null;
@Column({ type: 'varchar', length: 20 })
source!: InspectionEvidenceSource;
@Column({ name: 'uploaded_by', type: 'uuid', nullable: true })
uploadedBy!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,54 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { InspectionVerificationOutcome } from './inspection-finding-verification-visit.entity';
export enum InspectionFindingVerificationEventType {
CONTROL_DATE_DEFINED = 'CONTROL_DATE_DEFINED',
CONTROL_DATE_CHANGED = 'CONTROL_DATE_CHANGED',
CONTROL_DATE_CLEARED = 'CONTROL_DATE_CLEARED',
VISIT_PLANNED = 'VISIT_PLANNED',
RESULT_RECORDED = 'RESULT_RECORDED',
}
@Entity({ name: 'inspection_finding_verification_events' })
@Index('idx_inspection_finding_verification_events_finding', ['findingId', 'occurredAt'])
@Index('idx_inspection_finding_verification_events_visit', ['verificationVisitId'])
export class InspectionFindingVerificationEvent {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'finding_id', type: 'uuid' })
findingId!: string;
@Column({ name: 'verification_visit_id', type: 'uuid', nullable: true })
verificationVisitId!: string | null;
@Column({ name: 'event_type', type: 'varchar', length: 40 })
eventType!: InspectionFindingVerificationEventType;
@Column({ name: 'occurred_at', type: 'timestamptz' })
occurredAt!: Date;
@Column({ name: 'target_control_on', type: 'date', nullable: true })
targetControlOn!: string | null;
@Column({ name: 'previous_control_on', type: 'date', nullable: true })
previousControlOn!: string | null;
@Column({ name: 'next_control_on', type: 'date', nullable: true })
nextControlOn!: string | null;
@Column({ type: 'varchar', length: 24, nullable: true })
outcome!: InspectionVerificationOutcome | null;
@Column({ type: 'text', nullable: true })
notes!: string | null;
@Column({ name: 'actor_user_id', type: 'uuid', nullable: true })
actorUserId!: string | null;
@Column({ name: 'actor_username', type: 'varchar', length: 80, nullable: true })
actorUsername!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,47 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum InspectionVerificationOutcome {
RESOLVED = 'RESOLVED',
NOT_RESOLVED = 'NOT_RESOLVED',
REQUIRES_NEW_DATE = 'REQUIRES_NEW_DATE',
}
@Entity({ name: 'inspection_finding_verification_visits' })
@Index('uq_inspection_finding_verification_visit', ['findingId', 'visitId'], { unique: true })
@Index('idx_inspection_finding_verification_finding', ['findingId'])
@Index('idx_inspection_finding_verification_visit', ['visitId'])
export class InspectionFindingVerificationVisit extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'finding_id', type: 'uuid' })
findingId!: string;
@Column({ name: 'visit_id', type: 'uuid' })
visitId!: string;
@Column({ name: 'linked_by', type: 'uuid', nullable: true })
linkedBy!: string | null;
@Column({ name: 'target_control_on', type: 'date', nullable: true })
targetControlOn!: string | null;
@Column({ type: 'varchar', length: 24, nullable: true })
outcome!: InspectionVerificationOutcome | null;
@Column({ name: 'result_notes', type: 'text', nullable: true })
resultNotes!: string | null;
@Column({ name: 'verified_at', type: 'timestamptz', nullable: true })
verifiedAt!: Date | null;
@Column({ name: 'result_recorded_at', type: 'timestamptz', nullable: true })
resultRecordedAt!: Date | null;
@Column({ name: 'result_recorded_by', type: 'uuid', nullable: true })
resultRecordedBy!: string | null;
@Column({ name: 'rescheduled_control_on', type: 'date', nullable: true })
rescheduledControlOn!: string | null;
}
@@ -0,0 +1,37 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum InspectionFindingVersionEvent {
CREATED = 'CREATED',
UPDATED = 'UPDATED',
FOLLOW_UP_UPDATED = 'FOLLOW_UP_UPDATED',
VERIFICATION_RECORDED = 'VERIFICATION_RECORDED',
}
@Entity({ name: 'inspection_finding_versions' })
@Index('uq_inspection_finding_versions_number', ['findingId', 'versionNumber'], { unique: true })
@Index('idx_inspection_finding_versions_created_at', ['createdAt'])
export class InspectionFindingVersion {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'finding_id', type: 'uuid' })
findingId!: string;
@Column({ name: 'version_number', type: 'integer' })
versionNumber!: number;
@Column({ type: 'varchar', length: 32 })
event!: InspectionFindingVersionEvent;
@Column({ type: 'jsonb' })
snapshot!: Record<string, unknown>;
@Column({ name: 'actor_user_id', type: 'uuid', nullable: true })
actorUserId!: string | null;
@Column({ name: 'actor_username', type: 'varchar', length: 80, nullable: true })
actorUsername!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,108 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum InspectionFindingResponseDueBasis {
FINDING_DATE = 'FINDING_DATE',
REPORT_NOTIFICATION = 'REPORT_NOTIFICATION',
}
export enum InspectionFindingStatus {
OPEN = 'OPEN',
CLOSED = 'CLOSED',
VOIDED = 'VOIDED',
}
@Entity({ name: 'inspection_findings' })
@Index('uq_inspection_findings_number', ['actId', 'findingNumber'], { unique: true })
@Index('uq_inspection_findings_code', ['code'], { unique: true })
@Index('idx_inspection_findings_status_control', ['status', 'nextControlOn'])
@Index('idx_inspection_findings_asset_status', ['assetId', 'status'])
@Index('idx_inspection_findings_catalog_item', ['catalogItemId'])
export class InspectionFinding extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'act_id', type: 'uuid' })
actId!: string;
@Column({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ name: 'catalog_item_id', type: 'uuid', nullable: true })
catalogItemId!: string | null;
@Column({ name: 'finding_number', type: 'integer' })
findingNumber!: number;
@Column({ type: 'varchar', length: 40 })
code!: string;
@Column({ type: 'varchar', length: 20, default: InspectionFindingStatus.OPEN })
status!: InspectionFindingStatus;
@Column({ type: 'varchar', length: 500 })
title!: string;
@Column({ type: 'text' })
description!: string;
@Column({ name: 'legal_basis', type: 'text', nullable: true })
legalBasis!: string | null;
@Column({ type: 'text', nullable: true })
glossary!: string | null;
@Column({ name: 'catalog_revision', type: 'integer', nullable: true })
catalogRevision!: number | null;
@Column({ name: 'suggested_severity', type: 'smallint', nullable: true })
suggestedSeverity!: number | null;
@Column({ type: 'smallint', nullable: true })
severity!: number | null;
@Column({ name: 'correction_due_on', type: 'date', nullable: true })
correctionDueOn!: string | null;
@Column({ name: 'response_due_basis', type: 'varchar', length: 32, nullable: true })
responseDueBasis!: InspectionFindingResponseDueBasis | null;
@Column({ name: 'response_due_days', type: 'integer', nullable: true })
responseDueDays!: number | null;
@Column({ name: 'response_due_base_on', type: 'date', nullable: true })
responseDueBaseOn!: string | null;
@Column({ name: 'report_notified_on', type: 'date', nullable: true })
reportNotifiedOn!: string | null;
@Column({ name: 'company_response', type: 'text', nullable: true })
companyResponse!: string | null;
@Column({ name: 'company_response_received_on', type: 'date', nullable: true })
companyResponseReceivedOn!: string | null;
@Column({ name: 'company_committed_correction_on', type: 'date', nullable: true })
companyCommittedCorrectionOn!: string | null;
@Column({ name: 'next_control_on', type: 'date', nullable: true })
nextControlOn!: string | null;
@Column({ name: 'current_version', type: 'integer', default: 0 })
currentVersion!: number;
@Column({ name: 'closed_at', type: 'timestamptz', nullable: true })
closedAt!: Date | null;
@Column({ name: 'closed_by', type: 'uuid', nullable: true })
closedBy!: string | null;
@Column({ name: 'closure_notes', type: 'text', nullable: true })
closureNotes!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,124 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum InspectionReportStatus {
FROZEN = 'FROZEN',
CANCELLED = 'CANCELLED',
}
export enum InspectionReportPdfStatus {
PENDING = 'PENDING',
READY = 'READY',
FAILED = 'FAILED',
}
export enum InspectionReportWordStatus {
PENDING = 'PENDING',
READY = 'READY',
FAILED = 'FAILED',
}
export enum InspectionReportReviewStatus {
PENDING_REVIEW = 'PENDING_REVIEW',
APPROVED = 'APPROVED',
SIGNED = 'SIGNED',
}
@Entity({ name: 'inspection_reports' })
@Index('uq_inspection_reports_visit', ['visitId'], { unique: true })
@Index('uq_inspection_reports_act', ['actId'], { unique: true })
@Index('uq_inspection_reports_year_number', ['reportYear', 'reportNumber'], { unique: true })
@Index('uq_inspection_reports_code', ['code'], { unique: true })
@Index('idx_inspection_reports_generated_at', ['generatedAt'])
@Index('idx_inspection_reports_status', ['status', 'pdfStatus'])
export class InspectionReport extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'visit_id', type: 'uuid' })
visitId!: string;
@Column({ name: 'act_id', type: 'uuid' })
actId!: string;
@Column({ name: 'report_year', type: 'integer' })
reportYear!: number;
@Column({ name: 'report_number', type: 'integer' })
reportNumber!: number;
@Column({ type: 'varchar', length: 24 })
code!: string;
@Column({ type: 'varchar', length: 24, default: InspectionReportStatus.FROZEN })
status!: InspectionReportStatus;
@Column({ name: 'pdf_status', type: 'varchar', length: 24, default: InspectionReportPdfStatus.PENDING })
pdfStatus!: InspectionReportPdfStatus;
@Column({ name: 'word_status', type: 'varchar', length: 24, default: InspectionReportWordStatus.PENDING })
wordStatus!: InspectionReportWordStatus;
@Column({ name: 'word_original_name', type: 'varchar', length: 255, nullable: true })
wordOriginalName!: string | null;
@Column({ name: 'word_stored_name', type: 'varchar', length: 255, nullable: true })
wordStoredName!: string | null;
@Column({ name: 'word_mime_type', type: 'varchar', length: 120, nullable: true })
wordMimeType!: string | null;
@Column({ name: 'word_size_bytes', type: 'integer', nullable: true })
wordSizeBytes!: number | null;
@Column({ name: 'word_sha256', type: 'char', length: 64, nullable: true })
wordSha256!: string | null;
@Column({ name: 'word_generated_at', type: 'timestamptz', nullable: true })
wordGeneratedAt!: Date | null;
@Column({ name: 'word_error', type: 'varchar', length: 500, nullable: true })
wordError!: string | null;
@Column({ name: 'review_status', type: 'varchar', length: 32, default: InspectionReportReviewStatus.PENDING_REVIEW })
reviewStatus!: InspectionReportReviewStatus;
@Column({ name: 'current_revision_number', type: 'integer', default: 0 })
currentRevisionNumber!: number;
@Column({ name: 'approved_revision_id', type: 'uuid', nullable: true })
approvedRevisionId!: string | null;
@Column({ name: 'approved_by', type: 'uuid', nullable: true })
approvedBy!: string | null;
@Column({ name: 'approved_at', type: 'timestamptz', nullable: true })
approvedAt!: Date | null;
@Column({ name: 'review_note', type: 'varchar', length: 1000, nullable: true })
reviewNote!: string | null;
@Column({ name: 'signed_at', type: 'timestamptz', nullable: true })
signedAt!: Date | null;
@Column({ type: 'varchar', length: 220 })
title!: string;
@Column({ name: 'act_version', type: 'integer' })
actVersion!: number;
@Column({ name: 'act_closure_sha256', type: 'char', length: 64 })
actClosureSha256!: string;
@Column({ name: 'frozen_sha256', type: 'char', length: 64 })
frozenSha256!: string;
@Column({ name: 'frozen_snapshot', type: 'jsonb' })
frozenSnapshot!: Record<string, unknown>;
@Column({ name: 'generated_at', type: 'timestamptz' })
generatedAt!: Date;
@Column({ name: 'generated_by', type: 'uuid' })
generatedBy!: string;
}
@@ -0,0 +1,38 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum InspectionVisitAssetPlanningSource {
LEGACY = 'LEGACY',
AUTOMATIC = 'AUTOMATIC',
PREVENTIVE = 'PREVENTIVE',
VERIFICATION = 'VERIFICATION',
}
@Entity({ name: 'inspection_visit_assets' })
@Index('idx_inspection_visit_assets_asset_id', ['assetId'])
@Index('idx_inspection_visit_assets_included', ['visitId', 'included'])
export class InspectionVisitAsset extends TimestampedEntity {
@PrimaryColumn({ name: 'visit_id', type: 'uuid' })
visitId!: string;
@PrimaryColumn({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ type: 'boolean', default: true })
included!: boolean;
@Column({ name: 'planning_source', type: 'varchar', length: 24, default: InspectionVisitAssetPlanningSource.LEGACY })
planningSource!: InspectionVisitAssetPlanningSource;
@Column({ name: 'exclusion_reason', type: 'text', nullable: true })
exclusionReason!: string | null;
@Column({ name: 'excluded_by', type: 'uuid', nullable: true })
excludedBy!: string | null;
@Column({ name: 'excluded_at', type: 'timestamptz', nullable: true })
excludedAt!: Date | null;
@Column({ name: 'added_by', type: 'uuid', nullable: true })
addedBy!: string | null;
}
@@ -0,0 +1,19 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'inspection_visit_members' })
@Index('idx_inspection_visit_members_user_id', ['userId'])
@Index('idx_inspection_visit_members_included', ['visitId', 'included'])
export class InspectionVisitMember extends TimestampedEntity {
@PrimaryColumn({ name: 'visit_id', type: 'uuid' })
visitId!: string;
@PrimaryColumn({ name: 'user_id', type: 'uuid' })
userId!: string;
@Column({ type: 'boolean', default: true })
included!: boolean;
@Column({ name: 'assigned_by', type: 'uuid', nullable: true })
assignedBy!: string | null;
}
@@ -0,0 +1,76 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum InspectionVisitStatus {
DRAFT = 'DRAFT',
PLANNED = 'PLANNED',
IN_PROGRESS = 'IN_PROGRESS',
CLOSED = 'CLOSED',
CANCELLED = 'CANCELLED',
}
@Entity({ name: 'inspection_visits' })
@Index('uq_inspection_visits_code', ['code'], { unique: true })
@Index('idx_inspection_visits_status', ['status'])
@Index('idx_inspection_visits_scope_asset_id', ['scopeAssetId'])
@Index('idx_inspection_visits_lead_inspector_user_id', ['leadInspectorUserId'])
@Index('idx_inspection_visits_planned_dates', ['plannedStartAt', 'plannedEndAt'])
@Index('idx_inspection_visits_operational_context', ['operationalAreaId', 'operatorCompanyId'])
export class InspectionVisit extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 80 })
code!: string;
@Column({ type: 'varchar', length: 200 })
title!: string;
@Column({ type: 'text', nullable: true })
objective!: string | null;
@Column({ type: 'varchar', length: 24, default: InspectionVisitStatus.DRAFT })
status!: InspectionVisitStatus;
@Column({ name: 'scope_asset_id', type: 'uuid', nullable: true })
scopeAssetId!: string | null;
@Column({ name: 'operational_area_id', type: 'uuid', nullable: true })
operationalAreaId!: string | null;
@Column({ name: 'operator_company_id', type: 'uuid', nullable: true })
operatorCompanyId!: string | null;
@Column({ name: 'lead_inspector_user_id', type: 'uuid', nullable: true })
leadInspectorUserId!: string | null;
@Column({ name: 'planned_start_at', type: 'timestamptz', nullable: true })
plannedStartAt!: Date | null;
@Column({ name: 'planned_end_at', type: 'timestamptz', nullable: true })
plannedEndAt!: Date | null;
@Column({ name: 'actual_started_at', type: 'timestamptz', nullable: true })
actualStartedAt!: Date | null;
@Column({ name: 'actual_closed_at', type: 'timestamptz', nullable: true })
actualClosedAt!: Date | null;
@Column({ type: 'text', nullable: true })
instructions!: string | null;
@Column({ name: 'cancellation_reason', type: 'text', nullable: true })
cancellationReason!: string | null;
@Column({ name: 'checklist_generation', type: 'integer', default: 0 })
checklistGeneration!: number;
@Column({ name: 'checklist_generated_at', type: 'timestamptz', nullable: true })
checklistGeneratedAt!: Date | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,21 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum OrganizationMembershipRole { MEMBER='MEMBER', LEAD_MEMBER='LEAD_MEMBER', OTHER='OTHER' }
@Entity({name:'organization_memberships'})
@Index('idx_organization_memberships_parent_id',['parentOrganizationId'])
@Index('idx_organization_memberships_member_id',['memberOrganizationId'])
@Index('idx_organization_memberships_valid_until',['validUntil'])
export class OrganizationMembership extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid') id!:string;
@Column({name:'parent_organization_id',type:'uuid'}) parentOrganizationId!:string;
@Column({name:'member_organization_id',type:'uuid'}) memberOrganizationId!:string;
@Column({type:'enum',enum:OrganizationMembershipRole,enumName:'organization_membership_role'}) role!:OrganizationMembershipRole;
@Column({name:'participation_percent',type:'numeric',precision:7,scale:4,nullable:true}) participationPercent!:string|null;
@Column({name:'valid_from',type:'date',default:()=> 'CURRENT_DATE'}) validFrom!:string;
@Column({name:'valid_until',type:'date',nullable:true}) validUntil!:string|null;
@Column({name:'source_document_id',type:'uuid',nullable:true}) sourceDocumentId!:string|null;
@Column({type:'text',nullable:true}) notes!:string|null;
@Column({name:'end_reason',type:'text',nullable:true}) endReason!:string|null;
@Column({name:'created_by',type:'uuid',nullable:true}) createdBy!:string|null;
@Column({name:'ended_by',type:'uuid',nullable:true}) endedBy!:string|null;
}
@@ -0,0 +1,13 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum OrganizationKind { COMPANY='COMPANY', UTE='UTE', PUBLIC_ENTITY='PUBLIC_ENTITY', OTHER='OTHER' }
@Entity({ name: 'organization_profiles' })
export class OrganizationProfile extends TimestampedEntity {
@PrimaryColumn({ name:'asset_id', type:'uuid' }) assetId!: string;
@Column({ name:'organization_kind', type:'enum', enum:OrganizationKind, enumName:'organization_kind', default:OrganizationKind.COMPANY }) organizationKind!: OrganizationKind;
@Column({ name:'legal_name', type:'varchar', length:240, nullable:true }) legalName!: string|null;
@Column({ name:'tax_id', type:'varchar', length:32, nullable:true }) taxId!: string|null;
@Column({ name:'notification_email', type:'varchar', length:320, nullable:true }) notificationEmail!: string|null;
@Column({ type:'text', nullable:true }) notes!: string|null;
@Column({ name:'updated_by', type:'uuid', nullable:true }) updatedBy!: string|null;
}
@@ -0,0 +1,16 @@
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity({ name: 'permissions' })
export class Permission {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 120 })
code!: string;
@Column({ type: 'text' })
description!: string;
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
createdAt!: Date;
}
@@ -0,0 +1,21 @@
import { Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { Permission } from './permission.entity';
import { Role } from './role.entity';
@Entity({ name: 'role_permissions' })
@Index('idx_role_permissions_permission_id', ['permissionId'])
export class RolePermission {
@PrimaryColumn({ name: 'role_id', type: 'uuid' })
roleId!: string;
@PrimaryColumn({ name: 'permission_id', type: 'uuid' })
permissionId!: string;
@ManyToOne(() => Role, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'role_id' })
role!: Role;
@ManyToOne(() => Permission, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'permission_id' })
permission!: Permission;
}
@@ -0,0 +1,20 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'roles' })
export class Role extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 80 })
code!: string;
@Column({ type: 'varchar', length: 120 })
name!: string;
@Column({ type: 'text' })
description!: string;
@Column({ name: 'is_system', type: 'boolean', default: false })
isSystem!: boolean;
}
@@ -0,0 +1,6 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum SourceDocumentType { NOTE='NOTE', TECHNICAL_REPORT='TECHNICAL_REPORT', INSPECTION_ACT='INSPECTION_ACT', INVENTORY='INVENTORY', RESOLUTION='RESOLUTION', DECREE='DECREE', CONTRACT='CONTRACT', SPREADSHEET='SPREADSHEET', OTHER='OTHER' }
@Entity({name:'source_documents'})
@Index('idx_source_documents_number',['documentNumber']) @Index('idx_source_documents_document_date',['documentDate'])
export class SourceDocument extends TimestampedEntity { @PrimaryGeneratedColumn('uuid') id!:string; @Column({name:'document_type',type:'enum',enum:SourceDocumentType,enumName:'source_document_type'}) documentType!:SourceDocumentType; @Column({name:'document_number',type:'varchar',length:160,nullable:true}) documentNumber!:string|null; @Column({type:'varchar',length:300}) title!:string; @Column({type:'varchar',length:240,nullable:true}) issuer!:string|null; @Column({name:'document_date',type:'date',nullable:true}) documentDate!:string|null; @Column({name:'external_reference',type:'varchar',length:500,nullable:true}) externalReference!:string|null; @Column({type:'text',nullable:true}) notes!:string|null; @Column({name:'created_by',type:'uuid',nullable:true}) createdBy!:string|null; @Column({name:'updated_by',type:'uuid',nullable:true}) updatedBy!:string|null; }
@@ -0,0 +1,44 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum SurveyTargetStatus {
PENDING = 'PENDING',
IN_PROGRESS = 'IN_PROGRESS',
SUBMITTED = 'SUBMITTED',
COMPLETED = 'COMPLETED',
SKIPPED = 'SKIPPED',
}
@Entity({ name: 'survey_campaign_targets' })
@Index('uq_survey_campaign_targets_campaign_asset', ['campaignId', 'assetId'], { unique: true })
@Index('idx_survey_campaign_targets_campaign_status', ['campaignId', 'status'])
@Index('idx_survey_campaign_targets_asset_id', ['assetId'])
@Index('idx_survey_campaign_targets_assigned_user_id', ['assignedUserId'])
export class SurveyCampaignTarget extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'campaign_id', type: 'uuid' })
campaignId!: string;
@Column({ name: 'asset_id', type: 'uuid' })
assetId!: string;
@Column({ name: 'assigned_user_id', type: 'uuid', nullable: true })
assignedUserId!: string | null;
@Column({ type: 'varchar', length: 24, default: SurveyTargetStatus.PENDING })
status!: SurveyTargetStatus;
@Column({ name: 'due_at', type: 'timestamptz', nullable: true })
dueAt!: Date | null;
@Column({ type: 'text', nullable: true })
instructions!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,51 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum SurveyCampaignStatus {
DRAFT = 'DRAFT',
PLANNED = 'PLANNED',
IN_PROGRESS = 'IN_PROGRESS',
COMPLETED = 'COMPLETED',
CANCELLED = 'CANCELLED',
}
@Entity({ name: 'survey_campaigns' })
@Index('uq_survey_campaigns_code', ['code'], { unique: true })
@Index('idx_survey_campaigns_status', ['status'])
@Index('idx_survey_campaigns_scope_asset_id', ['scopeAssetId'])
@Index('idx_survey_campaigns_coordinator_user_id', ['coordinatorUserId'])
@Index('idx_survey_campaigns_planned_dates', ['plannedStartAt', 'plannedEndAt'])
export class SurveyCampaign extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 80 })
code!: string;
@Column({ type: 'varchar', length: 200 })
name!: string;
@Column({ type: 'text', nullable: true })
description!: string | null;
@Column({ type: 'varchar', length: 24, default: SurveyCampaignStatus.DRAFT })
status!: SurveyCampaignStatus;
@Column({ name: 'planned_start_at', type: 'timestamptz', nullable: true })
plannedStartAt!: Date | null;
@Column({ name: 'planned_end_at', type: 'timestamptz', nullable: true })
plannedEndAt!: Date | null;
@Column({ name: 'scope_asset_id', type: 'uuid', nullable: true })
scopeAssetId!: string | null;
@Column({ name: 'coordinator_user_id', type: 'uuid', nullable: true })
coordinatorUserId!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,19 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
@Entity({ name: 'survey_target_report_media' })
@Index('idx_survey_target_report_media_media_id', ['mediaId'])
@Index('idx_survey_target_report_media_included', ['reportId', 'included'])
export class SurveyTargetReportMedia extends TimestampedEntity {
@PrimaryColumn({ name: 'report_id', type: 'uuid' })
reportId!: string;
@PrimaryColumn({ name: 'media_id', type: 'uuid' })
mediaId!: string;
@Column({ type: 'boolean', default: true })
included!: boolean;
@Column({ name: 'added_by', type: 'uuid', nullable: true })
addedBy!: string | null;
}
@@ -0,0 +1,36 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
export enum SurveyReportVersionEvent {
SUBMITTED = 'SUBMITTED',
APPROVED = 'APPROVED',
REJECTED = 'REJECTED',
}
@Entity({ name: 'survey_target_report_versions' })
@Index('uq_survey_target_report_versions_number', ['reportId', 'versionNumber'], { unique: true })
@Index('idx_survey_target_report_versions_created_at', ['createdAt'])
export class SurveyTargetReportVersion {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'report_id', type: 'uuid' })
reportId!: string;
@Column({ name: 'version_number', type: 'integer' })
versionNumber!: number;
@Column({ type: 'varchar', length: 24 })
event!: SurveyReportVersionEvent;
@Column({ type: 'jsonb' })
snapshot!: Record<string, unknown>;
@Column({ name: 'actor_user_id', type: 'uuid', nullable: true })
actorUserId!: string | null;
@Column({ name: 'actor_username', type: 'varchar', length: 80, nullable: true })
actorUsername!: string | null;
@Column({ name: 'created_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}
@@ -0,0 +1,73 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum SurveyReportOutcome {
CONFIRMED = 'CONFIRMED',
CHANGES_RECORDED = 'CHANGES_RECORDED',
NOT_LOCATED = 'NOT_LOCATED',
}
export enum SurveyReportStatus {
DRAFT = 'DRAFT',
SUBMITTED = 'SUBMITTED',
APPROVED = 'APPROVED',
REJECTED = 'REJECTED',
}
@Entity({ name: 'survey_target_reports' })
@Index('uq_survey_target_reports_target_id', ['targetId'], { unique: true })
@Index('idx_survey_target_reports_status', ['status'])
@Index('idx_survey_target_reports_submitted_by', ['submittedBy'])
@Index('idx_survey_target_reports_reviewed_by', ['reviewedBy'])
export class SurveyTargetReport extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'target_id', type: 'uuid' })
targetId!: string;
@Column({ type: 'varchar', length: 32, nullable: true })
outcome!: SurveyReportOutcome | null;
@Column({ type: 'varchar', length: 24, default: SurveyReportStatus.DRAFT })
status!: SurveyReportStatus;
@Column({ name: 'observed_at', type: 'timestamptz', nullable: true })
observedAt!: Date | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
latitude!: string | null;
@Column({ type: 'numeric', precision: 9, scale: 6, nullable: true })
longitude!: string | null;
@Column({ name: 'accuracy_m', type: 'numeric', precision: 12, scale: 3, nullable: true })
accuracyM!: string | null;
@Column({ type: 'text', nullable: true })
notes!: string | null;
@Column({ name: 'asset_version_at_submission', type: 'integer', nullable: true })
assetVersionAtSubmission!: number | null;
@Column({ name: 'submitted_at', type: 'timestamptz', nullable: true })
submittedAt!: Date | null;
@Column({ name: 'submitted_by', type: 'uuid', nullable: true })
submittedBy!: string | null;
@Column({ name: 'reviewed_at', type: 'timestamptz', nullable: true })
reviewedAt!: Date | null;
@Column({ name: 'reviewed_by', type: 'uuid', nullable: true })
reviewedBy!: string | null;
@Column({ name: 'review_notes', type: 'text', nullable: true })
reviewNotes!: string | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}
@@ -0,0 +1,9 @@
import { CreateDateColumn, UpdateDateColumn } from 'typeorm';
export abstract class TimestampedEntity {
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
createdAt!: Date;
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
updatedAt!: Date;
}
@@ -0,0 +1,35 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { Role } from './role.entity';
import { User } from './user.entity';
@Entity({ name: 'user_roles' })
@Index('idx_user_roles_user_id', ['userId'])
@Index('idx_user_roles_role_id', ['roleId'])
export class UserRole {
@PrimaryColumn({ name: 'user_id', type: 'uuid' })
userId!: string;
@PrimaryColumn({ name: 'role_id', type: 'uuid' })
roleId!: string;
@Column({ name: 'assigned_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
assignedAt!: Date;
@Column({ name: 'assigned_by', type: 'uuid', nullable: true })
assignedBy!: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'user_id' })
user!: User;
@ManyToOne(() => Role, { onDelete: 'RESTRICT' })
@JoinColumn({ name: 'role_id' })
role!: Role;
}
@@ -0,0 +1,59 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import { TimestampedEntity } from './timestamped.entity';
export enum UserStatus {
ACTIVE = 'ACTIVE',
INACTIVE = 'INACTIVE',
}
@Entity({ name: 'users' })
@Index('idx_users_status', ['status'])
@Index('idx_users_locked_until', ['lockedUntil'])
export class User extends TimestampedEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ type: 'varchar', length: 80 })
username!: string;
@Column({ type: 'varchar', length: 320, nullable: true })
email!: string | null;
@Column({ name: 'password_hash', type: 'text', select: false })
passwordHash!: string;
@Column({ name: 'first_name', type: 'varchar', length: 120 })
firstName!: string;
@Column({ name: 'last_name', type: 'varchar', length: 120 })
lastName!: string;
@Column({
type: 'enum',
enum: UserStatus,
enumName: 'user_status',
default: UserStatus.ACTIVE,
})
status!: UserStatus;
@Column({ name: 'must_change_password', type: 'boolean', default: true })
mustChangePassword!: boolean;
@Column({ name: 'failed_login_attempts', type: 'integer', default: 0 })
failedLoginAttempts!: number;
@Column({ name: 'locked_until', type: 'timestamptz', nullable: true })
lockedUntil!: Date | null;
@Column({ name: 'last_login_at', type: 'timestamptz', nullable: true })
lastLoginAt!: Date | null;
@Column({ name: 'password_changed_at', type: 'timestamptz', nullable: true })
passwordChangedAt!: Date | null;
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy!: string | null;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy!: string | null;
}