Fuente: revisión 40d3aee008c6d2faab9887a92c26f9f0446e794c. 98 archivos TypeScript, 62 clases y 12 modelos Prisma.
# Diccionario de datos
Generado desde `backend/prisma/schema.prisma`. Los campos de relación de Prisma se distinguen de las columnas persistidas.
## User
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| email | String | @unique |
| passwordHash | String | @map("password_hash") |
| fullName | String | @map("full_name") |
| role | String | @default("QA_TESTER") // QA_TESTER, QA_LEAD, DEVELOPER, ADMIN |
| isActive | Boolean | @default(true) @map("is_active") |
| preferences | Json? | @default("{}") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| projects | Project[] | |
| reviews | TestCaseReview[] | |
| sessions | AuthSession[] | |
| requirementVersions | RequirementVersion[] | |
| specGenerations | SpecGeneration[] | |
| aiGenerations | AiGeneration[] | |
## AuthSession
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| userId | String | @map("user_id") |
| tokenHash | String | @unique @map("token_hash") |
| userAgent | String? | @map("user_agent") |
| ipAddress | String? | @map("ip_address") |
| isRevoked | Boolean | @default(false) @map("is_revoked") |
| expiresAt | DateTime | @map("expires_at") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| user | User | @relation(fields: [userId], references: [id], onDelete: Cascade) |
## Project
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| name | String | |
| description | String? | |
| ownerId | String | @map("owner_id") |
| status | String | @default("ACTIVE") // ACTIVE, ARCHIVED |
| budgetUsd | Float? | @default(10.0) @map("budget_usd") |
| nextRequirementNumber | Int | @default(1) @map("next_requirement_number") |
| nextUseCaseNumber | Int | @default(1) @map("next_use_case_number") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| owner | User | @relation(fields: [ownerId], references: [id], onDelete: Restrict) |
| requirements | Requirement[] | |
| useCases | UseCase[] | |
| specGenerations | SpecGeneration[] | |
| testRuns | TestRun[] | |
## SpecGeneration
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| projectId | String | @map("project_id") |
| userId | String? | @map("user_id") |
| engineVersion | String | @map("engine_version") |
| depth | String | @default("standard") // basic, standard, exhaustive |
| inputName | String | @map("input_name") |
| inputDescription | String | @map("input_description") |
| inputHash | String | @map("input_hash") |
| actorsDetected | Json | @default("[]") @map("actors_detected") |
| modulesDetected | Json | @default("[]") @map("modules_detected") |
| entitiesDetected | Json | @default("[]") @map("entities_detected") |
| warnings | Json | @default("[]") |
| useCasesCreated | Int | @default(0) @map("use_cases_created") |
| requirementsCreated | Int | @default(0) @map("requirements_created") |
| testCasesCreated | Int | @default(0) @map("test_cases_created") |
| useCasesSkipped | Int | @default(0) @map("use_cases_skipped") |
| requirementsSkipped | Int | @default(0) @map("requirements_skipped") |
| durationMs | Int | @default(0) @map("duration_ms") |
| status | String | @default("SUCCEEDED") // SUCCEEDED, FAILED |
| errorMessage | String? | @map("error_message") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| project | Project | @relation(fields: [projectId], references: [id], onDelete: Cascade) |
| user | User? | @relation(fields: [userId], references: [id], onDelete: SetNull) |
| useCases | UseCase[] | |
## UseCase
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| projectId | String | @map("project_id") |
| generationId | String? | @map("generation_id") |
| code | String | // ej. UC-001 |
| name | String | |
| actor | String | |
| moduleKey | String | @map("module_key") |
| moduleName | String | @map("module_name") |
| description | String | |
| priority | String | @default("medium") // high, medium, low |
| preconditions | Json | @default("[]") |
| mainFlow | Json | @default("[]") @map("main_flow") |
| alternativeFlows | Json | @default("[]") @map("alternative_flows") |
| exceptionFlows | Json | @default("[]") @map("exception_flows") |
| postconditions | Json | @default("[]") |
| source | String | @default("AUTO_SPEC") // AUTO_SPEC, MANUAL |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| project | Project | @relation(fields: [projectId], references: [id], onDelete: Cascade) |
| generation | SpecGeneration? | @relation(fields: [generationId], references: [id], onDelete: SetNull) |
| requirements | Requirement[] | |
## Requirement
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| projectId | String | @map("project_id") |
| useCaseId | String? | @map("use_case_id") |
| code | String | // ej. REQ-001 |
| title | String | |
| description | String | |
| acceptanceCriteria | String | @map("acceptance_criteria") |
| version | Int | @default(1) |
| status | String | @default("READY") // READY, GENERATED, OBSOLETE |
| nextCaseNumber | Int | @default(1) @map("next_case_number") |
| derivationHints | Json? | @map("derivation_hints") // variables BVA, categoría ISTQB, tipo (funcional / no funcional) |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| project | Project | @relation(fields: [projectId], references: [id], onDelete: Cascade) |
| useCase | UseCase? | @relation(fields: [useCaseId], references: [id], onDelete: SetNull) |
| testCases | TestCase[] | |
| aiGenerations | AiGeneration[] | |
| versions | RequirementVersion[] | |
## RequirementVersion
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| requirementId | String | @map("requirement_id") |
| version | Int | |
| title | String | |
| description | String | |
| acceptanceCriteria | String | @map("acceptance_criteria") |
| authorId | String? | @map("author_id") |
| changeSummary | String? | @map("change_summary") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| requirement | Requirement | @relation(fields: [requirementId], references: [id], onDelete: Cascade) |
| author | User? | @relation(fields: [authorId], references: [id], onDelete: SetNull) |
## AiGeneration
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| requirementId | String | @map("requirement_id") |
| userId | String? | @map("user_id") |
| requirementVersion | Int | @default(1) @map("requirement_version") |
| provider | String | // gemini, openai |
| model | String | // gemini-2.5-flash-lite, gpt-5-nano, etc. |
| promptVersion | String | @default("v1.0") @map("prompt_version") |
| inputTokens | Int | @map("input_tokens") |
| outputTokens | Int | @map("output_tokens") |
| estimatedCost | Float? | @map("estimated_cost") // null si desconocido |
| responseTimeMs | Int | @map("response_time_ms") |
| inputHash | String? | @map("input_hash") |
| status | String | @default("SUCCEEDED") // SUCCEEDED, FAILED |
| errorMessage | String? | @map("error_message") |
| rawResponse | Json? | @map("raw_response") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| requirement | Requirement | @relation(fields: [requirementId], references: [id], onDelete: Cascade) |
| user | User? | @relation(fields: [userId], references: [id], onDelete: SetNull) |
| testCases | TestCase[] | |
## TestCase
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| requirementId | String | @map("requirement_id") |
| generationId | String? | @map("generation_id") |
| code | String | // ej. CP-001 |
| type | String | // positive, negative, alternative, boundary, validation |
| title | String | |
| preconditions | Json | @default("[]") |
| steps | Json | @default("[]") |
| testData | String? | @map("test_data") |
| expectedResult | String | @map("expected_result") |
| priority | String | @default("medium") // high, medium, low |
| evidenceStatus | String | @default("pending") @map("evidence_status") // derived, suggested, ambiguous, conflict, pending |
| evidenceText | String? | @map("evidence_text") |
| technique | String? | // BDD_SCENARIO, USE_CASE_BASIC_COURSE, BVA_*, TEMPLATE_*, ERROR_GUESSING_*, ... |
| originalContent | Json? | @map("original_content") // Snapshot inmutable de la salida inicial |
| version | Int | @default(1) // Versión de revisión (para bloqueo optimista) |
| requirementVersion | Int | @default(1) @map("requirement_version") |
| isObsolete | Boolean | @default(false) @map("is_obsolete") |
| source | String | @default("MANUAL") // AUTO_SPEC, AUTO_DERIVED, MANUAL, TEMPLATE, ISTQB_BVA, FORMAL_DESIGN, CLONE, LEGACY |
| status | String | @default("PENDING") // PENDING, APPROVED, MODIFIED, REJECTED |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| requirement | Requirement | @relation(fields: [requirementId], references: [id], onDelete: Cascade) |
| generation | AiGeneration? | @relation(fields: [generationId], references: [id], onDelete: SetNull) |
| reviews | TestCaseReview[] | |
| executions | TestExecutionResult[] | |
## TestCaseReview
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| testCaseId | String | @map("test_case_id") |
| reviewerId | String | @map("reviewer_id") |
| decision | String | // APPROVED, MODIFIED, REJECTED |
| comments | String? | |
| justification | String? | // Obligatoria para aprobar conflictos |
| reviewedRequirementVersion | Int | @default(1) @map("reviewed_requirement_version") |
| previousContent | Json | @map("previous_content") // Snapshot completo antes |
| newContent | Json | @map("new_content") // Snapshot completo después |
| createdAt | DateTime | @default(now()) @map("created_at") |
| testCase | TestCase | @relation(fields: [testCaseId], references: [id], onDelete: Cascade) |
| reviewer | User | @relation(fields: [reviewerId], references: [id], onDelete: Restrict) |
## TestRun
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| projectId | String | @map("project_id") |
| name | String | |
| environment | String | @default("QA Sandbox") |
| status | String | @default("IN_PROGRESS") // IN_PROGRESS, COMPLETED |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| project | Project | @relation(fields: [projectId], references: [id], onDelete: Cascade) |
| executions | TestExecutionResult[] | |
## TestExecutionResult
| Campo | Tipo Prisma | Restricciones |
|---|---|---|
| id | String | @id @default(uuid()) |
| testRunId | String | @map("test_run_id") |
| testCaseId | String | @map("test_case_id") |
| code | String | |
| title | String | |
| status | String | @default("PENDING") // PASSED, FAILED, BLOCKED, SKIPPED, PENDING |
| durationSeconds | Int | @default(0) @map("duration_seconds") |
| executedAt | DateTime? | @map("executed_at") |
| executedBy | String? | @map("executed_by") |
| evidenceText | String? | @map("evidence_text") |
| defectNotes | String? | @map("defect_notes") |
| defectLogged | Boolean | @default(false) @map("defect_logged") |
| createdAt | DateTime | @default(now()) @map("created_at") |
| updatedAt | DateTime | @updatedAt @map("updated_at") |
| testRun | TestRun | @relation(fields: [testRunId], references: [id], onDelete: Cascade) |
| testCase | TestCase | @relation(fields: [testCaseId], references: [id], onDelete: Cascade) |
# Documentación técnica del código
Generada desde el árbol de sintaxis TypeScript. Incluye clases, interfaces, funciones, métodos y propiedades declaradas.
## backend/src/application/use-cases/clone-test-case.use-case.ts
### CloneTestCaseInputDTO
| Miembro | Declaración |
|---|---|
| testCaseId | `testCaseId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| replaceFind | `replaceFind: string` |
| replaceWith | `replaceWith: string` |
### CloneTestCaseUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: CloneTestCaseInputDTO): retorno inferido` |
## backend/src/application/use-cases/create-manual-test-case.use-case.ts
### CreateManualTestCaseInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| type | `type: 'positive' \| 'negative' \| 'alternative' \| 'boundary' \| 'validation'` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: 'high' \| 'medium' \| 'low'` |
### CreateManualTestCaseUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: CreateManualTestCaseInputDTO): retorno inferido` |
## backend/src/application/use-cases/create-test-case-from-bug.use-case.ts
### CreateFromBugInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| defectTitle | `defectTitle: string` |
| stepsToReproduce | `stepsToReproduce: string[]` |
| actualBehavior | `actualBehavior: string` |
| expectedBehavior | `expectedBehavior: string` |
| severity | `severity: 'high' \| 'medium' \| 'low'` |
### CreateTestCaseFromBugUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: CreateFromBugInputDTO): retorno inferido` |
## backend/src/application/use-cases/derive-test-cases.use-case.ts
### DeriveTestCasesInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| depth | `depth: DerivationDepth` |
### DeriveTestCasesOutputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| requirementCode | `requirementCode: string` |
| depth | `depth: DerivationDepth` |
| derived | `derived: number` |
| inserted | `inserted: number` |
| omittedAsExisting | `omittedAsExisting: number` |
| techniques | `techniques: Record<string, number>` |
| cases | `cases: Array<Record<string, unknown>>` |
| duplicateWarnings | `duplicateWarnings: DuplicateCandidate[]` |
### DerivationHints
| Miembro | Declaración |
|---|---|
| variables | `variables: BvaVariableInput[]` |
| templateCategory | `templateCategory: string \| null` |
| priority | `priority: 'high' \| 'medium' \| 'low'` |
### DeriveTestCasesUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: DeriveTestCasesInputDTO): Promise<DeriveTestCasesOutputDTO>` |
## backend/src/application/use-cases/generate-from-bva.use-case.ts
### GenerateFromBvaInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| variable | `variable: BvaVariableInput` |
| userId | `userId: string` |
| userRole | `userRole: string` |
### GenerateFromBvaUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: GenerateFromBvaInputDTO): retorno inferido` |
## backend/src/application/use-cases/generate-from-formal.use-case.ts
### GenerateFromFormalInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| method | `method: FormalMethodType` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| payload | `payload: {
conditions?: DecisionCondition[];
actions?: DecisionAction[];
states?: string[];
validTransitions?: StateTransition[];
parameters?: ParameterOption[];
classes?: ClassificationClass[];
useCase?: UseCaseInput;
entityName?: string;
}` |
### GenerateFromFormalUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: GenerateFromFormalInputDTO): retorno inferido` |
## backend/src/application/use-cases/generate-from-template.use-case.ts
### GenerateFromTemplateInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| templateCategory | `templateCategory: string` |
### GenerateFromTemplateOutputDTO
| Miembro | Declaración |
|---|---|
| cases | `cases: Array<Record<string, unknown>>` |
| templateUsed | `templateUsed: {
category: string;
name: string;
casesGenerated: number;
}` |
| duplicateWarnings | `duplicateWarnings: DuplicateCandidate[]` |
### GenerateFromTemplateUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: GenerateFromTemplateInputDTO): Promise<GenerateFromTemplateOutputDTO>` |
## backend/src/application/use-cases/generate-project-spec.use-case.ts
### GenerateProjectSpecInputDTO
| Miembro | Declaración |
|---|---|
| projectId | `projectId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| name | `name: string` |
| description | `description: string` |
| depth | `depth: DerivationDepth` |
| includeNonFunctional | `includeNonFunctional: boolean` |
| includeEntityCrud | `includeEntityCrud: boolean` |
### GeneratedUseCaseSummary
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| code | `code: string` |
| name | `name: string` |
| actor | `actor: string` |
| moduleKey | `moduleKey: string` |
| moduleName | `moduleName: string` |
| requirementCount | `requirementCount: number` |
### GeneratedRequirementSummary
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| code | `code: string` |
| title | `title: string` |
| kind | `kind: 'functional' \| 'non_functional'` |
| useCaseCode | `useCaseCode: string \| null` |
| testCasesCreated | `testCasesCreated: number` |
### GenerateProjectSpecOutputDTO
| Miembro | Declaración |
|---|---|
| generationId | `generationId: string` |
| engineVersion | `engineVersion: string` |
| depth | `depth: DerivationDepth` |
| summary | `summary: ProjectSpecification['summary']` |
| actors | `actors: ProjectSpecification['actors']` |
| modules | `modules: ProjectSpecification['modules']` |
| entities | `entities: ProjectSpecification['entities']` |
| warnings | `warnings: string[]` |
| created | `created: { useCases: number; requirements: number; testCases: number }` |
| skipped | `skipped: { useCases: number; requirements: number }` |
| useCases | `useCases: GeneratedUseCaseSummary[]` |
| requirements | `requirements: GeneratedRequirementSummary[]` |
| durationMs | `durationMs: number` |
### GenerateProjectSpecUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: GenerateProjectSpecInputDTO): Promise<GenerateProjectSpecOutputDTO>` |
## backend/src/application/use-cases/generate-test-cases.use-case.ts
### GenerateTestCasesInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| provider | `provider: 'gemini' \| 'openai'` |
| model | `model: string` |
| temperature | `temperature: number` |
| useCache | `useCache: boolean` |
### GenerateTestCasesOutputDTO
| Miembro | Declaración |
|---|---|
| cases | `cases: Array<Record<string, unknown>>` |
| generation | `generation: {
id: string;
provider: string;
model: string;
inputTokens: number;
outputTokens: number;
estimatedCost: number \| null;
responseTimeMs: number;
cached: boolean;
}` |
| duplicateWarnings | `duplicateWarnings: DuplicateCandidate[]` |
### GenerateTestCasesUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: GenerateTestCasesInputDTO): Promise<GenerateTestCasesOutputDTO>` |
## backend/src/application/use-cases/get-projects-with-metrics.use-case.ts
### GetProjectsInputDTO
| Miembro | Declaración |
|---|---|
| userId | `userId: string` |
| userRole | `userRole: string` |
| skip | `skip: number` |
| take | `take: number` |
### ProjectStatsDTO
| Miembro | Declaración |
|---|---|
| requirementsCount | `requirementsCount: number` |
| totalTestCases | `totalTestCases: number` |
| approvedTestCases | `approvedTestCases: number` |
| coveragePercent | `coveragePercent: number` |
| totalCostUsd | `totalCostUsd: number \| null` |
### ProjectDTO
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| name | `name: string` |
| description | `description: string \| null` |
| status | `status: string` |
| budgetUsd | `budgetUsd: number \| null` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| stats | `stats: ProjectStatsDTO` |
### GetProjectsOutputDTO
| Miembro | Declaración |
|---|---|
| items | `items: ProjectDTO[]` |
| total | `total: number` |
### GetProjectsWithMetricsUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: GetProjectsInputDTO): Promise<GetProjectsOutputDTO>` |
## backend/src/application/use-cases/import-test-cases.use-case.ts
### RawImportCaseDTO
| Miembro | Declaración |
|---|---|
| title | `title: string` |
| type | `type: 'positive' \| 'negative' \| 'alternative' \| 'boundary' \| 'validation'` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: 'high' \| 'medium' \| 'low'` |
### ImportTestCasesInputDTO
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| userId | `userId: string` |
| userRole | `userRole: string` |
| cases | `cases: RawImportCaseDTO[]` |
### ImportTestCasesUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: ImportTestCasesInputDTO): retorno inferido` |
## backend/src/application/use-cases/review-test-case.use-case.ts
### ReviewTestCaseInputDTO
| Miembro | Declaración |
|---|---|
| testCaseId | `testCaseId: string` |
| reviewerId | `reviewerId: string` |
| reviewerRole | `reviewerRole: string` |
| decision | `decision: 'APPROVED' \| 'MODIFIED' \| 'REJECTED'` |
| comments | `comments: string` |
| justification | `justification: string` |
| expectedVersion | `expectedVersion: number` |
| updates | `updates: {
title?: string;
preconditions?: string[];
steps?: string[];
testData?: string \| null;
expectedResult?: string;
priority?: 'high' \| 'medium' \| 'low';
evidenceStatus?: 'derived' \| 'suggested' \| 'ambiguous' \| 'conflict' \| 'pending';
evidenceText?: string \| null;
}` |
### ReviewTestCaseUseCase
| Miembro | Declaración |
|---|---|
| execute | `execute(input: ReviewTestCaseInputDTO): retorno inferido` |
## backend/src/common/cache/lru-cache.ts
### CacheEntry
| Miembro | Declaración |
|---|---|
| value | `value: T` |
| expiresAt | `expiresAt: number` |
### LruCache
| Miembro | Declaración |
|---|---|
| capacity | `capacity: number` |
| defaultTtlMs | `defaultTtlMs: number` |
| cache | `cache: Map<string, CacheEntry<T>>` |
| constructor | `constructor(capacity = 500, defaultTtlSeconds = 300): retorno inferido` |
| get | `get(key: string): T \| null` |
| set | `set(key: string, value: T, ttlSeconds?: number): void` |
| invalidate | `invalidate(key: string): void` |
| clear | `clear(): void` |
| size | `size(): number` |
## backend/src/common/errors/api-error.ts
### ApiError
| Miembro | Declaración |
|---|---|
| statusCode | `statusCode: number` |
| isOperational | `isOperational: boolean` |
| constructor | `constructor(statusCode: number, message: string, isOperational = true): retorno inferido` |
| badRequest | `badRequest(msg = 'Solicitud inválida'): retorno inferido` |
| unauthorized | `unauthorized(msg = 'No autenticado'): retorno inferido` |
| forbidden | `forbidden(msg = 'Acceso denegado'): retorno inferido` |
| notFound | `notFound(msg = 'Recurso no encontrado'): retorno inferido` |
| conflict | `conflict(msg = 'Conflicto con el estado actual del recurso'): retorno inferido` |
| unprocessableEntity | `unprocessableEntity(msg = 'Entidad no procesable'): retorno inferido` |
| badGateway | `badGateway(msg = 'Error al comunicarse con el servicio upstream'): retorno inferido` |
| serviceUnavailable | `serviceUnavailable(msg = 'Servicio no disponible'): retorno inferido` |
| gatewayTimeout | `gatewayTimeout(msg = 'Tiempo de espera agotado con el proveedor upstream'): retorno inferido` |
## backend/src/common/middleware/async-handler.ts
### asyncHandler
`export function asyncHandler(fn: RequestHandler): RequestHandler`
## backend/src/common/middleware/auth.middleware.ts
### UserTokenPayload
| Miembro | Declaración |
|---|---|
| userId | `userId: string` |
| email | `email: string` |
| role | `role: string` |
### Request
| Miembro | Declaración |
|---|---|
| user | `user: UserTokenPayload` |
### signAccessToken
`export function signAccessToken(payload: UserTokenPayload): string`
### signRefreshToken
`export function signRefreshToken(payload: UserTokenPayload): string`
### verifyRefreshToken
`export function verifyRefreshToken(token: string): UserTokenPayload`
### issueTokenPair
`export function issueTokenPair(payload: UserTokenPayload)`
### signToken
`export function signToken(payload: UserTokenPayload): string`
### authenticateJWT
`export function authenticateJWT(req: Request, res: Response, next: NextFunction)`
### requireRoles
`export function requireRoles(allowedRoles: string[])`
## backend/src/common/middleware/error-handler.ts
### notFoundHandler
`export function notFoundHandler(req: Request, res: Response)`
### errorHandler
`export function errorHandler( err: unknown, req: Request, res: Response, // eslint-disable-next-line @typescript-eslint/no-unused-vars _next: NextFunction )`
## backend/src/common/middleware/request-id.ts
### Request
| Miembro | Declaración |
|---|---|
| id | `id: string` |
### requestId
`export function requestId(req: Request, res: Response, next: NextFunction)`
## backend/src/common/security/cookie-session.ts
### CookieSessionManager
| Miembro | Declaración |
|---|---|
| setAuthCookie | `setAuthCookie(res: Response, token: string): void` |
| setRefreshCookie | `setRefreshCookie(res: Response, refreshToken: string): void` |
| clearAuthCookies | `clearAuthCookies(res: Response): void` |
| extractToken | `extractToken(req: Request): string \| null` |
| extractRefreshToken | `extractRefreshToken(req: Request): string \| null` |
| verifyMutationOrigin | `verifyMutationOrigin(req: Request, _res: Response, next: NextFunction): void` |
## backend/src/common/security/crypto-vault.ts
### CryptoVault
| Miembro | Declaración |
|---|---|
| getKey | `getKey(): Buffer` |
| encrypt | `encrypt(plainText: string): string` |
| decrypt | `decrypt(cipherTextBase64: string): string` |
## backend/src/common/security/pii-masker.ts
### MaskingResult
| Miembro | Declaración |
|---|---|
| maskedText | `maskedText: string` |
| piiFound | `piiFound: boolean` |
| totalMasked | `totalMasked: number` |
| maskMap | `maskMap: Map<string, string>` |
### MultiMaskingResult
| Miembro | Declaración |
|---|---|
| maskedFields | `maskedFields: T` |
| piiFound | `piiFound: boolean` |
| totalMasked | `totalMasked: number` |
| maskMap | `maskMap: Map<string, string>` |
### PIIMasker
| Miembro | Declaración |
|---|---|
| EMAIL_REGEX | `EMAIL_REGEX: tipo inferido` |
| CREDIT_CARD_REGEX | `CREDIT_CARD_REGEX: tipo inferido` |
| PHONE_REGEX | `PHONE_REGEX: tipo inferido` |
| API_KEY_REGEX | `API_KEY_REGEX: tipo inferido` |
| DNI_REGEX | `DNI_REGEX: tipo inferido` |
| IP_REGEX | `IP_REGEX: tipo inferido` |
| mask | `mask(text: string): MaskingResult` |
| maskMultiple | `maskMultiple(fields: T): MultiMaskingResult<T>` |
| maskWithMap | `maskWithMap(text: string, maskMap: Map<string, string>, state: { counter: number }): { masked: string; maskMap: Map<string, string> }` |
| unmask | `unmask(maskedText: string, maskMap: Map<string, string>): string` |
## backend/src/common/security/prompt-guard.ts
### PromptGuardResult
| Miembro | Declaración |
|---|---|
| isSafe | `isSafe: boolean` |
| riskScore | `riskScore: number` |
| threatsDetected | `threatsDetected: string[]` |
| sanitizedText | `sanitizedText: string` |
### PromptGuard
| Miembro | Declaración |
|---|---|
| INJECTION_PATTERNS | `INJECTION_PATTERNS: tipo inferido` |
| inspect | `inspect(input: string): PromptGuardResult` |
| assertSafe | `assertSafe(input: string, threshold: number = 40): string` |
## backend/src/common/security/rbac.ts
### RBACManager
| Miembro | Declaración |
|---|---|
| ROLE_PERMISSIONS | `ROLE_PERMISSIONS: Record<UserRole, Set<Permission>>` |
| can | `can(role: string, permission: Permission): boolean` |
| requirePermission | `requirePermission(permission: Permission): retorno inferido` |
## backend/src/common/security/secure-random.ts
### secureRandomFraction
`export function secureRandomFraction(): number`
## backend/src/common/security/session.service.ts
### SessionService
| Miembro | Declaración |
|---|---|
| hashToken | `hashToken(token: string): string` |
| createSession | `createSession(params: {
userId: string;
refreshToken: string;
userAgent?: string;
ipAddress?: string;
expiresInDays?: number;
}): Promise<string>` |
| rotateSession | `rotateSession(params: {
oldRefreshToken: string;
newRefreshToken: string;
userId: string;
userAgent?: string;
ipAddress?: string;
expiresInDays?: number;
}): Promise<boolean>` |
| revokeSession | `revokeSession(refreshToken: string): Promise<void>` |
## backend/src/common/utils/api-response.ts
### ApiResponse
| Miembro | Declaración |
|---|---|
| success | `success: boolean` |
| data | `data: T` |
| message | `message: string` |
| error | `error: string` |
### PaginationMeta
| Miembro | Declaración |
|---|---|
| page | `page: number` |
| pageSize | `pageSize: number` |
| total | `total: number` |
| totalPages | `totalPages: number` |
### sendSuccess
`export function sendSuccess<T>( res: Response, data: T, message = 'Operación exitosa', statusCode = 200 ): Response`
### sendError
`export function sendError(res: Response, error: string, statusCode = 400): Response`
### sendPaginated
`export function sendPaginated<T>( res: Response, items: T[], meta: PaginationMeta, message = 'Operación exitosa' ): Response`
### getPagination
`export function getPagination(req: Request):`
### buildPaginationMeta
`export function buildPaginationMeta(page: number, pageSize: number, total: number): PaginationMeta`
## backend/src/common/utils/audit.ts
### audit
`export function audit(req: Request, action: AuditAction, details: Record<string, unknown> =`
## backend/src/common/utils/json.ts
### safeJsonArray
`export function safeJsonArray(raw: unknown): unknown[]`
### safeJsonObject
`export function safeJsonObject(raw: unknown): Record<string, unknown> | null`
## backend/src/common/utils/ownership.ts
### isAdmin
`function isAdmin(role?: string): boolean`
### assertProjectAccess
`export async function assertProjectAccess(projectId: string, userId: string, role?: string)`
### assertRequirementAccess
`export async function assertRequirementAccess(requirementId: string, userId: string, role?: string)`
### assertTestCaseAccess
`export async function assertTestCaseAccess(testCaseId: string, userId: string, role?: string)`
## backend/src/common/utils/retry.ts
### RetryOptions
| Miembro | Declaración |
|---|---|
| retries | `retries: number` |
| timeoutMs | `timeoutMs: number` |
| label | `label: string` |
### withRetry
`export async function withRetry<T>( fn: (signal: AbortSignal) => Promise<T>,`
## backend/src/config/ai-pricing.ts
### ModelPricing
| Miembro | Declaración |
|---|---|
| inputPerMillion | `inputPerMillion: number` |
| outputPerMillion | `outputPerMillion: number` |
### calculateAICost
`export function calculateAICost( model: string, inputTokens: number, outputTokens: number ): number | null`
## backend/src/config/env.ts
### getCorsOrigins
`export function getCorsOrigins(): string[] | '*'`
## backend/src/config/prisma.ts
### initDatabaseConnection
`export async function initDatabaseConnection(): Promise<boolean>`
### disconnectDatabase
`export async function disconnectDatabase(): Promise<void>`
## backend/src/config/swagger.ts
### mountSwagger
`export function mountSwagger(app: Express)`
## backend/src/core/adapters/gemini.adapter.ts
### GeminiAdapter
| Miembro | Declaración |
|---|---|
| providerName | `providerName: tipo inferido` |
| generateTestCases | `generateTestCases(requirementCode: string, requirementTitle: string, description: string, acceptanceCriteria: string, options?: GenerateOptions): Promise<AIGenerationResult>` |
## backend/src/core/adapters/openai.adapter.ts
### OpenAIAdapter
| Miembro | Declaración |
|---|---|
| providerName | `providerName: tipo inferido` |
| generateTestCases | `generateTestCases(requirementCode: string, requirementTitle: string, description: string, acceptanceCriteria: string, options?: GenerateOptions): Promise<AIGenerationResult>` |
## backend/src/core/ai.factory.ts
### AIFactory
| Miembro | Declaración |
|---|---|
| registry | `registry: Map<string, AIProviderFactoryFn>` |
| instances | `instances: Map<string, IAIProvider>` |
| registerProvider | `registerProvider(name: string, factoryFn: AIProviderFactoryFn): void` |
| getProvider | `getProvider(providerName?: string): IAIProvider` |
| hasProvider | `hasProvider(name: string): boolean` |
| getAvailableProviders | `getAvailableProviders(): string[]` |
## backend/src/core/domain/entities/project.entity.ts
### ProjectEntityProps
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| name | `name: string` |
| description | `description: string \| null` |
| ownerId | `ownerId: string` |
| status | `status: 'ACTIVE' \| 'ARCHIVED'` |
| budgetUsd | `budgetUsd: number \| null` |
| nextRequirementNumber | `nextRequirementNumber: number` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
### ProjectEntity
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| _name | `_name: string` |
| _description | `_description: string \| null` |
| ownerId | `ownerId: string` |
| _status | `_status: 'ACTIVE' \| 'ARCHIVED'` |
| _budgetUsd | `_budgetUsd: number \| null` |
| _nextRequirementNumber | `_nextRequirementNumber: number` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| constructor | `constructor(props: ProjectEntityProps): retorno inferido` |
| name | `name: string` |
| description | `description: string \| null` |
| status | `status: 'ACTIVE' \| 'ARCHIVED'` |
| budgetUsd | `budgetUsd: number \| null` |
| nextRequirementNumber | `nextRequirementNumber: number` |
| isActive | `isActive(): boolean` |
| isArchived | `isArchived(): boolean` |
| archive | `archive(): void` |
| reactivate | `reactivate(): void` |
| updateDetails | `updateDetails(name: string, description?: string \| null, budgetUsd?: number \| null): void` |
| allocateNextRequirementCode | `allocateNextRequirementCode(): string` |
## backend/src/core/domain/entities/requirement.entity.ts
### RequirementEntityProps
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| projectId | `projectId: string` |
| code | `code: string` |
| title | `title: string` |
| description | `description: string` |
| acceptanceCriteria | `acceptanceCriteria: string` |
| version | `version: number` |
| status | `status: 'READY_FOR_AI' \| 'GENERATED' \| 'OBSOLETE'` |
| nextCaseNumber | `nextCaseNumber: number` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
### RequirementEntity
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| projectId | `projectId: string` |
| code | `code: string` |
| _title | `_title: string` |
| _description | `_description: string` |
| _acceptanceCriteria | `_acceptanceCriteria: string` |
| _version | `_version: number` |
| _status | `_status: 'READY_FOR_AI' \| 'GENERATED' \| 'OBSOLETE'` |
| _nextCaseNumber | `_nextCaseNumber: number` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| constructor | `constructor(props: RequirementEntityProps): retorno inferido` |
| title | `title: string` |
| description | `description: string` |
| acceptanceCriteria | `acceptanceCriteria: string` |
| version | `version: number` |
| status | `status: 'READY_FOR_AI' \| 'GENERATED' \| 'OBSOLETE'` |
| nextCaseNumber | `nextCaseNumber: number` |
| updateContent | `updateContent(title: string, description: string, acceptanceCriteria: string): void` |
| markAsGenerated | `markAsGenerated(): void` |
| markAsObsolete | `markAsObsolete(): void` |
| allocateNextCaseCode | `allocateNextCaseCode(): string` |
## backend/src/core/domain/entities/test-case.entity.ts
### TestCaseProps
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| requirementId | `requirementId: string` |
| code | `code: TestCaseCode` |
| type | `type: ISTQBTechnique` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: TestCasePriority` |
| status | `status: TestCaseStatus` |
| version | `version: number` |
| source | `source: 'MANUAL' \| 'RULE_BASED' \| 'AI_GENERATED'` |
| evidenceStatus | `evidenceStatus: 'derived' \| 'suggested' \| 'ambiguous' \| 'conflict'` |
| evidenceText | `evidenceText: string \| null` |
| isObsolete | `isObsolete: boolean` |
| generationId | `generationId: string \| null` |
| requirementVersion | `requirementVersion: number` |
| originalContent | `originalContent: Record<string, unknown> \| null` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
### TestCaseEntity
| Miembro | Declaración |
|---|---|
| props | `props: TestCaseProps` |
| constructor | `constructor(props: TestCaseProps): retorno inferido` |
| id | `id: string` |
| requirementId | `requirementId: string` |
| code | `code: TestCaseCode` |
| type | `type: ISTQBTechnique` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: TestCasePriority` |
| status | `status: TestCaseStatus` |
| version | `version: number` |
| source | `source: string` |
| evidenceStatus | `evidenceStatus: string` |
| evidenceText | `evidenceText: string \| null` |
| isObsolete | `isObsolete: boolean` |
| generationId | `generationId: string \| null` |
| requirementVersion | `requirementVersion: number` |
| originalContent | `originalContent: Record<string, unknown> \| null` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| approve | `approve(reviewerId: string, _comments?: string): void` |
| reject | `reject(reviewerId: string, reason: string): void` |
| modify | `modify(updates: Partial<Omit<TestCaseProps, 'id' \| 'requirementId' \| 'code' \| 'version'>>): void` |
| assertVersionMatch | `assertVersionMatch(expectedVersion?: number): void` |
| toJSON | `toJSON(): Record<string, unknown>` |
## backend/src/core/domain/entities/test-run.entity.ts
### TestExecutionResultProps
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| testRunId | `testRunId: string` |
| testCaseId | `testCaseId: string` |
| code | `code: string` |
| title | `title: string` |
| status | `status: ExecutionStatus` |
| durationSeconds | `durationSeconds: number` |
| executedAt | `executedAt: Date \| null` |
| executedBy | `executedBy: string \| null` |
| evidenceText | `evidenceText: string \| null` |
| defectNotes | `defectNotes: string \| null` |
| defectLogged | `defectLogged: boolean` |
### TestRunEntityProps
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| projectId | `projectId: string` |
| name | `name: string` |
| environment | `environment: string` |
| status | `status: 'IN_PROGRESS' \| 'COMPLETED'` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| executions | `executions: TestExecutionResultProps[]` |
### TestRunEntity
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| projectId | `projectId: string` |
| _name | `_name: string` |
| _environment | `_environment: string` |
| _status | `_status: 'IN_PROGRESS' \| 'COMPLETED'` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| _executions | `_executions: TestExecutionResultProps[]` |
| constructor | `constructor(props: TestRunEntityProps): retorno inferido` |
| name | `name: string` |
| environment | `environment: string` |
| status | `status: 'IN_PROGRESS' \| 'COMPLETED'` |
| executions | `executions: ReadonlyArray<TestExecutionResultProps>` |
| complete | `complete(): void` |
| getMetrics | `getMetrics(): retorno inferido` |
## backend/src/core/domain/mappers/test-case.mapper.ts
### PrismaTestCaseRow
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| requirementId | `requirementId: string` |
| code | `code: string` |
| type | `type: string` |
| title | `title: string` |
| preconditions | `preconditions: unknown` |
| steps | `steps: unknown` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: string` |
| status | `status: string` |
| version | `version: number` |
| source | `source: string` |
| evidenceStatus | `evidenceStatus: string` |
| evidenceText | `evidenceText: string \| null` |
| isObsolete | `isObsolete: boolean` |
| generationId | `generationId: string \| null` |
| requirementVersion | `requirementVersion: number` |
| originalContent | `originalContent: unknown` |
| createdAt | `createdAt: Date` |
| updatedAt | `updatedAt: Date` |
| reviews | `reviews: Array<{
id: string;
decision: string;
comments: string \| null;
previousContent: unknown;
newContent: unknown;
createdAt: Date;
reviewer?: { id: string; fullName: string; role: string };
}>` |
### TestCaseMapper
| Miembro | Declaración |
|---|---|
| toDomain | `toDomain(row: PrismaTestCaseRow): TestCaseEntity` |
| toPersistence | `toPersistence(entity: TestCaseEntity): retorno inferido` |
| toDTO | `toDTO(row: PrismaTestCaseRow): retorno inferido` |
## backend/src/core/domain/security/security-policy.ts
### DomainSecurityException
| Miembro | Declaración |
|---|---|
| constructor | `constructor(message: string, public readonly code: string = 'FORBIDDEN'): retorno inferido` |
### ResourceNotFoundDomainException
| Miembro | Declaración |
|---|---|
| constructor | `constructor(message: string): retorno inferido` |
### SecurityUserContext
| Miembro | Declaración |
|---|---|
| userId | `userId: string` |
| role | `role: string` |
### SecurityPolicy
| Miembro | Declaración |
|---|---|
| isAdmin | `isAdmin(role: string): boolean` |
| canAccessProject | `canAccessProject(projectOwnerId: string, user: SecurityUserContext): boolean` |
| assertProjectAccess | `assertProjectAccess(projectOwnerId: string, user: SecurityUserContext, projectName: string = 'proyecto'): void` |
| canExecuteTestCaseReview | `canExecuteTestCaseReview(user: SecurityUserContext): boolean` |
| assertCanReview | `assertCanReview(user: SecurityUserContext): void` |
## backend/src/core/domain/services/requirement-fingerprint.service.ts
### FingerprintInputs
| Miembro | Declaración |
|---|---|
| code | `code: string` |
| title | `title: string` |
| description | `description: string` |
| acceptanceCriteria | `acceptanceCriteria: string` |
| provider | `provider: string` |
| model | `model: string` |
### IFingerprintStrategy
| Miembro | Declaración |
|---|---|
| compute | `compute: string` |
### Sha256FingerprintStrategy
| Miembro | Declaración |
|---|---|
| compute | `compute(inputs: FingerprintInputs): string` |
### RequirementFingerprintService
| Miembro | Declaración |
|---|---|
| defaultStrategy | `defaultStrategy: IFingerprintStrategy` |
| setStrategy | `setStrategy(strategy: IFingerprintStrategy): void` |
| compute | `compute(inputs: FingerprintInputs): string` |
## backend/src/core/domain/value-objects/entity-codes.vo.ts
### TestCasePriority
| Miembro | Declaración |
|---|---|
| HIGH | `HIGH: tipo inferido` |
| MEDIUM | `MEDIUM: tipo inferido` |
| LOW | `LOW: tipo inferido` |
| constructor | `constructor(private readonly level: PriorityLevel): retorno inferido` |
| from | `from(raw?: string \| null): TestCasePriority` |
| getLevel | `getLevel(): PriorityLevel` |
| getNumericWeight | `getNumericWeight(): number` |
| isHigh | `isHigh(): boolean` |
| equals | `equals(other: TestCasePriority): boolean` |
| toString | `toString(): string` |
### TestCaseCode
| Miembro | Declaración |
|---|---|
| constructor | `constructor(private readonly code: string): retorno inferido` |
| from | `from(raw: string): TestCaseCode` |
| getValue | `getValue(): string` |
| equals | `equals(other: TestCaseCode): boolean` |
| toString | `toString(): string` |
### RequirementCode
| Miembro | Declaración |
|---|---|
| constructor | `constructor(private readonly code: string): retorno inferido` |
| from | `from(raw: string): RequirementCode` |
| getValue | `getValue(): string` |
| equals | `equals(other: RequirementCode): boolean` |
| toString | `toString(): string` |
## backend/src/core/domain/value-objects/istqb-technique.vo.ts
### ISTQBTechnique
| Miembro | Declaración |
|---|---|
| VALID_TECHNIQUES | `VALID_TECHNIQUES: Set<string>` |
| POSITIVE | `POSITIVE: tipo inferido` |
| NEGATIVE | `NEGATIVE: tipo inferido` |
| BOUNDARY | `BOUNDARY: tipo inferido` |
| VALIDATION | `VALIDATION: tipo inferido` |
| ALTERNATIVE | `ALTERNATIVE: tipo inferido` |
| DECISION_TABLE | `DECISION_TABLE: tipo inferido` |
| STATE_TRANSITION | `STATE_TRANSITION: tipo inferido` |
| PAIRWISE | `PAIRWISE: tipo inferido` |
| CTM | `CTM: tipo inferido` |
| ERROR_GUESSING | `ERROR_GUESSING: tipo inferido` |
| constructor | `constructor(private readonly value: ISTQBTechniqueType): retorno inferido` |
| from | `from(raw: string): ISTQBTechnique` |
| getValue | `getValue(): ISTQBTechniqueType` |
| isBoundary | `isBoundary(): boolean` |
| isCombinatorial | `isCombinatorial(): boolean` |
| isStateTransition | `isStateTransition(): boolean` |
| isSecurityOrNegative | `isSecurityOrNegative(): boolean` |
| isBlackBox | `isBlackBox(): boolean` |
| isExperienceBased | `isExperienceBased(): boolean` |
| equals | `equals(other: ISTQBTechnique): boolean` |
| toString | `toString(): string` |
## backend/src/core/domain/value-objects/test-case-status.vo.ts
### TestCaseStatus
| Miembro | Declaración |
|---|---|
| VALID_STATUSES | `VALID_STATUSES: Set<TestCaseStatusType>` |
| PENDING | `PENDING: tipo inferido` |
| APPROVED | `APPROVED: tipo inferido` |
| MODIFIED | `MODIFIED: tipo inferido` |
| REJECTED | `REJECTED: tipo inferido` |
| constructor | `constructor(private readonly value: TestCaseStatusType): retorno inferido` |
| from | `from(raw: string): TestCaseStatus` |
| getValue | `getValue(): TestCaseStatusType` |
| isApproved | `isApproved(): boolean` |
| isPending | `isPending(): boolean` |
| isRejected | `isRejected(): boolean` |
| isModified | `isModified(): boolean` |
| canTransitionTo | `canTransitionTo(next: TestCaseStatus): boolean` |
| equals | `equals(other: TestCaseStatus): boolean` |
| toString | `toString(): string` |
## backend/src/core/interfaces/ai-provider.interface.ts
### RawGeneratedCase
| Miembro | Declaración |
|---|---|
| type | `type: TestCaseType` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: PriorityLevel` |
| evidenceStatus | `evidenceStatus: EvidenceStatus` |
| evidenceText | `evidenceText: string \| null` |
### AIGenerationResult
| Miembro | Declaración |
|---|---|
| provider | `provider: 'gemini' \| 'openai'` |
| model | `model: string` |
| promptVersion | `promptVersion: string` |
| inputTokens | `inputTokens: number` |
| outputTokens | `outputTokens: number` |
| responseTimeMs | `responseTimeMs: number` |
| estimatedCost | `estimatedCost: number \| null` |
| cases | `cases: RawGeneratedCase[]` |
### GenerateOptions
| Miembro | Declaración |
|---|---|
| model | `model: string` |
| temperature | `temperature: number` |
| maxOutputTokens | `maxOutputTokens: number` |
### IAIProvider
| Miembro | Declaración |
|---|---|
| providerName | `providerName: 'gemini' \| 'openai'` |
| generateTestCases | `generateTestCases: Promise<AIGenerationResult>` |
## backend/src/core/ports/project-repository.port.ts
### ProjectFilter
| Miembro | Declaración |
|---|---|
| ownerId | `ownerId: string` |
| status | `status: string` |
| search | `search: string` |
### IProjectRepository
| Miembro | Declaración |
|---|---|
| findById | `findById: Promise<ProjectEntity \| null>` |
| findByOwner | `findByOwner: Promise<PaginatedResult<ProjectEntity>>` |
| create | `create: Promise<ProjectEntity>` |
| update | `update: Promise<ProjectEntity>` |
| archive | `archive: Promise<boolean>` |
| delete | `delete: Promise<boolean>` |
## backend/src/core/ports/requirement-repository.port.ts
### RequirementFilter
| Miembro | Declaración |
|---|---|
| projectId | `projectId: string` |
| status | `status: string` |
| search | `search: string` |
### IRequirementRepository
| Miembro | Declaración |
|---|---|
| findById | `findById: Promise<RequirementEntity \| null>` |
| findByProjectId | `findByProjectId: Promise<PaginatedResult<RequirementEntity>>` |
| save | `save: Promise<void>` |
| createVersion | `createVersion: Promise<number>` |
| delete | `delete: Promise<boolean>` |
## backend/src/core/ports/test-case-repository.port.ts
### TestCaseFilter
| Miembro | Declaración |
|---|---|
| requirementId | `requirementId: string` |
| projectId | `projectId: string` |
| status | `status: string` |
| search | `search: string` |
### PaginationOptions
| Miembro | Declaración |
|---|---|
| skip | `skip: number` |
| take | `take: number` |
| page | `page: number` |
| pageSize | `pageSize: number` |
### PaginatedResult
| Miembro | Declaración |
|---|---|
| items | `items: T[]` |
| total | `total: number` |
### ITestCaseRepository
| Miembro | Declaración |
|---|---|
| findById | `findById: Promise<TestCaseEntity \| null>` |
| findByRequirementId | `findByRequirementId: Promise<TestCaseEntity[]>` |
| findByProjectId | `findByProjectId: Promise<PaginatedResult<TestCaseEntity>>` |
| save | `save: Promise<void>` |
| saveBatch | `saveBatch: Promise<void>` |
| delete | `delete: Promise<boolean>` |
## backend/src/core/ports/test-run-repository.port.ts
### ITestRunRepository
| Miembro | Declaración |
|---|---|
| findById | `findById: Promise<TestRunEntity \| null>` |
| findByProjectId | `findByProjectId: Promise<TestRunEntity[]>` |
| create | `create: Promise<TestRunEntity>` |
| recordExecution | `recordExecution: Promise<TestExecutionResultProps>` |
| logDefect | `logDefect: Promise<TestExecutionResultProps>` |
## backend/src/core/prompts/prompt-builder.ts
### PromptPayload
| Miembro | Declaración |
|---|---|
| systemPrompt | `systemPrompt: string` |
| userPrompt | `userPrompt: string` |
| version | `version: string` |
### buildPromptForRequirement
`export function buildPromptForRequirement( code: string, title: string, description: string, acceptanceCriteria: string ): PromptPayload`
## backend/src/core/spec-engine/catalog/actors.ts
### findActor
`export function findActor(key: string): ActorDefinition | undefined`
## backend/src/core/spec-engine/catalog/entities.ts
### findEntity
`export function findEntity(key: string): EntityDefinition | undefined`
## backend/src/core/spec-engine/catalog/index.ts
### findModule
`export function findModule(key: string): DomainModule | undefined`
### NonFunctionalTemplate
| Miembro | Declaración |
|---|---|
| requiresModules | `requiresModules: string[]` |
| template | `template: RequirementTemplate` |
### EntityWords
| Miembro | Declaración |
|---|---|
| singular | `singular: string` |
| plural | `plural: string` |
| singularCap | `singularCap: string` |
| pluralCap | `pluralCap: string` |
| art | `art: string` |
| arts | `arts: string` |
| un | `un: string` |
| nuevo | `nuevo: string` |
| registrado | `registrado: string` |
| lo | `lo: string` |
### entityWords
`function entityWords(entity: EntitySpec): EntityWords`
### sampleValue
`function sampleValue(field: EntityField, words: EntityWords): string`
### fieldConstraint
`function fieldConstraint(field: EntityField): string`
### toVariable
`function toVariable(field: EntityField): BvaVariableInput | null`
### buildEntityCrudUseCase
`export function buildEntityCrudUseCase(entity: EntitySpec): UseCaseTemplate`
### getCatalogStats
`export function getCatalogStats()`
## backend/src/core/spec-engine/project-spec-engine.ts
### SpecEngineInput
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| description | `description: string` |
### SpecEngineOptions
| Miembro | Declaración |
|---|---|
| depth | `depth: DerivationDepth` |
| includeNonFunctional | `includeNonFunctional: boolean` |
| includeEntityCrud | `includeEntityCrud: boolean` |
| maxModules | `maxModules: number` |
| maxEntities | `maxEntities: number` |
### HydrationContext
| Miembro | Declaración |
|---|---|
| actor | `actor: string` |
| admin | `admin: string` |
| project | `project: string` |
### ScoredModule
| Miembro | Declaración |
|---|---|
| module | `module: DomainModule` |
| score | `score: number` |
| matched | `matched: string[]` |
| implied | `implied: boolean` |
| order | `order: number` |
### ProjectSpecEngine
| Miembro | Declaración |
|---|---|
| analyze | `analyze(input: SpecEngineInput, options: SpecEngineOptions = {}): ProjectSpecification` |
| hydrate | `hydrate(text: string, ctx: HydrationContext): string` |
| detectActors | `detectActors(normalized: string): Array<ActorDefinition & { score: number }>` |
| detectModules | `detectModules(normalized: string, maxModules: number, warnings: string[]): ScoredModule[]` |
| detectEntities | `detectEntities(normalized: string, covered: Set<string>, detectedModuleTerms: Set<string>, maxEntities: number): EntitySpec[]` |
| guessGender | `guessGender(word: string): 'm' \| 'f'` |
## backend/src/core/spec-engine/spec-types.ts
### ScenarioTemplate
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| type | `type: ScenarioType` |
| given | `given: string[]` |
| when | `when: string[]` |
| then | `then: string[]` |
### RequirementTemplate
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| title | `title: string` |
| description | `description: string` |
| priority | `priority: Priority` |
| kind | `kind: RequirementKind` |
| scenarios | `scenarios: ScenarioTemplate[]` |
| variables | `variables: BvaVariableInput[]` |
| templateCategory | `templateCategory: string` |
### FlowAlternative
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| condition | `condition: string` |
| steps | `steps: string[]` |
### FlowException
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| trigger | `trigger: string` |
| steps | `steps: string[]` |
| expectedError | `expectedError: string` |
### UseCaseTemplate
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| name | `name: string` |
| actor | `actor: ActorRole` |
| priority | `priority: Priority` |
| description | `description: string` |
| preconditions | `preconditions: string[]` |
| mainFlow | `mainFlow: string[]` |
| alternativeFlows | `alternativeFlows: FlowAlternative[]` |
| exceptionFlows | `exceptionFlows: FlowException[]` |
| postconditions | `postconditions: string[]` |
| requirements | `requirements: RequirementTemplate[]` |
### KeywordRule
| Miembro | Declaración |
|---|---|
| term | `term: string` |
| weight | `weight: number` |
### DomainModule
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| name | `name: string` |
| icon | `icon: string` |
| description | `description: string` |
| keywords | `keywords: KeywordRule[]` |
| preferredActors | `preferredActors: string[]` |
| secondaryActors | `secondaryActors: string[]` |
| coveredEntities | `coveredEntities: string[]` |
| implies | `implies: string[]` |
| templateCategory | `templateCategory: string` |
| useCases | `useCases: UseCaseTemplate[]` |
### ActorDefinition
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| label | `label: string` |
| description | `description: string` |
| keywords | `keywords: string[]` |
| isAdmin | `isAdmin: boolean` |
### EntityField
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| type | `type: EntityFieldType` |
| required | `required: boolean` |
| unique | `unique: boolean` |
| min | `min: number` |
| max | `max: number` |
| unit | `unit: string` |
| options | `options: string[]` |
| example | `example: string` |
### EntityDefinition
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| singular | `singular: string` |
| plural | `plural: string` |
| gender | `gender: 'm' \| 'f'` |
| keywords | `keywords: string[]` |
| fields | `fields: EntityField[]` |
### ActorSpec
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| label | `label: string` |
| description | `description: string` |
| isAdmin | `isAdmin: boolean` |
| source | `source: 'detected' \| 'default'` |
| score | `score: number` |
### ModuleSpec
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| name | `name: string` |
| icon | `icon: string` |
| description | `description: string` |
| score | `score: number` |
| matchedKeywords | `matchedKeywords: string[]` |
| implied | `implied: boolean` |
### EntitySpec
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| singular | `singular: string` |
| plural | `plural: string` |
| gender | `gender: 'm' \| 'f'` |
| score | `score: number` |
| source | `source: 'catalog' \| 'pattern'` |
| fields | `fields: EntityField[]` |
### UseCaseSpec
| Miembro | Declaración |
|---|---|
| code | `code: string` |
| key | `key: string` |
| name | `name: string` |
| actor | `actor: string` |
| moduleKey | `moduleKey: string` |
| moduleName | `moduleName: string` |
| priority | `priority: Priority` |
| description | `description: string` |
| preconditions | `preconditions: string[]` |
| mainFlow | `mainFlow: string[]` |
| alternativeFlows | `alternativeFlows: FlowAlternative[]` |
| exceptionFlows | `exceptionFlows: FlowException[]` |
| postconditions | `postconditions: string[]` |
| requirementCodes | `requirementCodes: string[]` |
### RequirementSpec
| Miembro | Declaración |
|---|---|
| code | `code: string` |
| key | `key: string` |
| title | `title: string` |
| description | `description: string` |
| acceptanceCriteria | `acceptanceCriteria: string` |
| priority | `priority: Priority` |
| kind | `kind: RequirementKind` |
| moduleKey | `moduleKey: string` |
| useCaseCode | `useCaseCode: string \| null` |
| scenarios | `scenarios: ScenarioTemplate[]` |
| variables | `variables: BvaVariableInput[]` |
| templateCategory | `templateCategory: string \| null` |
| estimatedTestCases | `estimatedTestCases: number` |
### SpecificationSummary
| Miembro | Declaración |
|---|---|
| engineVersion | `engineVersion: string` |
| depth | `depth: DerivationDepth` |
| actorsDetected | `actorsDetected: number` |
| modulesDetected | `modulesDetected: number` |
| entitiesDetected | `entitiesDetected: number` |
| totalUseCases | `totalUseCases: number` |
| totalRequirements | `totalRequirements: number` |
| functionalRequirements | `functionalRequirements: number` |
| nonFunctionalRequirements | `nonFunctionalRequirements: number` |
| estimatedTestCases | `estimatedTestCases: number` |
### ProjectSpecification
| Miembro | Declaración |
|---|---|
| project | `project: { name: string; description: string }` |
| summary | `summary: SpecificationSummary` |
| actors | `actors: ActorSpec[]` |
| modules | `modules: ModuleSpec[]` |
| entities | `entities: EntitySpec[]` |
| useCases | `useCases: UseCaseSpec[]` |
| requirements | `requirements: RequirementSpec[]` |
| warnings | `warnings: string[]` |
## backend/src/core/spec-engine/test-deriver.ts
### DerivationInput
| Miembro | Declaración |
|---|---|
| code | `code: string` |
| title | `title: string` |
| description | `description: string` |
| acceptanceCriteria | `acceptanceCriteria: string` |
| priority | `priority: Priority` |
| variables | `variables: BvaVariableInput[]` |
| templateCategory | `templateCategory: string \| null` |
| useCase | `useCase: UseCaseInput \| null` |
| useCaseCode | `useCaseCode: string \| null` |
| depth | `depth: DerivationDepth` |
### DerivedTestCase
| Miembro | Declaración |
|---|---|
| type | `type: ScenarioType` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: Priority` |
| evidenceStatus | `evidenceStatus: 'derived' \| 'suggested'` |
| evidenceText | `evidenceText: string \| null` |
| technique | `technique: string` |
### DeterministicTestDeriver
| Miembro | Declaración |
|---|---|
| derive | `derive(input: DerivationInput): DerivedTestCase[]` |
| estimate | `estimate(input: DerivationInput): number` |
| buildUseCaseInput | `buildUseCaseInput(uc: {
name: string;
actor: string;
mainFlow: string[];
alternativeFlows: FlowAlternative[];
exceptionFlows: FlowException[];
}): UseCaseInput` |
| fromGherkin | `fromGherkin(input: DerivationInput): DerivedTestCase[]` |
| fromUseCase | `fromUseCase(input: DerivationInput): DerivedTestCase[]` |
| fromVariables | `fromVariables(input: DerivationInput, depth: DerivationDepth): DerivedTestCase[]` |
| fromTemplate | `fromTemplate(input: DerivationInput): DerivedTestCase[]` |
| fromErrorGuessing | `fromErrorGuessing(input: DerivationInput): DerivedTestCase[]` |
| fallbackCases | `fallbackCases(input: DerivationInput): DerivedTestCase[]` |
| collectVariables | `collectVariables(input: DerivationInput, max: number): BvaVariableInput[]` |
| priorityFor | `priorityFor(type: ScenarioType, base?: Priority): Priority` |
| stripNumbering | `stripNumbering(step: string): string` |
| dedupe | `dedupe(cases: DerivedTestCase[]): DerivedTestCase[]` |
## backend/src/core/spec-engine/text-normalizer.ts
### TextNormalizer
| Miembro | Declaración |
|---|---|
| STOPWORDS | `STOPWORDS: ReadonlySet<string>` |
| stripAccents | `stripAccents(input: string): string` |
| normalize | `normalize(input: string): string` |
| tokenize | `tokenize(input: string): string[]` |
| countOccurrences | `countOccurrences(normalizedText: string, phrase: string): number` |
| singularize | `singularize(word: string): string` |
| pluralize | `pluralize(word: string): string` |
| capitalize | `capitalize(input: string): string` |
| comparisonKey | `comparisonKey(input: string): string` |
## backend/src/core/templates/istqb-templates.ts
### TemplateCase
| Miembro | Declaración |
|---|---|
| type | `type: 'positive' \| 'negative' \| 'alternative' \| 'boundary' \| 'validation'` |
| titleTemplate | `titleTemplate: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| expectedResultTemplate | `expectedResultTemplate: string` |
| priority | `priority: 'high' \| 'medium' \| 'low'` |
| evidenceStatus | `evidenceStatus: 'derived' \| 'suggested'` |
### TemplateCategory
| Miembro | Declaración |
|---|---|
| key | `key: string` |
| name | `name: string` |
| description | `description: string` |
| icon | `icon: string` |
| cases | `cases: TemplateCase[]` |
### hydrateTemplate
`export function hydrateTemplate(template: TemplateCase, reqTitle: string): TemplateCase`
## backend/src/core/test-design/bva-engine.ts
### BvaVariableInput
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| type | `type: BvaVariableType` |
| min | `min: number` |
| max | `max: number` |
| unit | `unit: string` |
| decimals | `decimals: number` |
### BvaCalculatedCase
| Miembro | Declaración |
|---|---|
| type | `type: 'positive' \| 'negative' \| 'boundary' \| 'validation'` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string` |
| expectedResult | `expectedResult: string` |
| priority | `priority: 'high' \| 'medium' \| 'low'` |
| tag | `tag: string` |
| testValue | `testValue: string \| number` |
### BvaEngine
| Miembro | Declaración |
|---|---|
| calculate | `calculate(variable: BvaVariableInput): BvaCalculatedCase[]` |
| calculateMultivariate | `calculateMultivariate(varA: { name: string; value: number; label: string }, varB: { name: string; value: number; label: string }, relation: 'LESS_THAN' \| 'LESS_EQUAL' \| 'SUM_LESS_EQUAL', limit?: number): BvaCalculatedCase[]` |
| calculateStringLengthBva | `calculateStringLengthBva(variable: BvaVariableInput): BvaCalculatedCase[]` |
## backend/src/core/test-design/formal-methods.ts
### FormalGeneratedCase
| Miembro | Declaración |
|---|---|
| type | `type: 'positive' \| 'negative' \| 'alternative' \| 'boundary' \| 'validation'` |
| title | `title: string` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| testData | `testData: string` |
| expectedResult | `expectedResult: string` |
| priority | `priority: 'high' \| 'medium' \| 'low'` |
| technique | `technique: string` |
### DecisionCondition
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| label | `label: string` |
### DecisionAction
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| label | `label: string` |
### DecisionTableEngine
| Miembro | Declaración |
|---|---|
| generate | `generate(conditions: DecisionCondition[], actions: DecisionAction[], requirementTitle = 'Requisito'): FormalGeneratedCase[]` |
### StateTransition
| Miembro | Declaración |
|---|---|
| from | `from: string` |
| to | `to: string` |
| event | `event: string` |
| action | `action: string` |
### StateTransitionEngine
| Miembro | Declaración |
|---|---|
| generate | `generate(states: string[], validTransitions: StateTransition[], requirementTitle = 'Entidad'): FormalGeneratedCase[]` |
### ParameterOption
| Miembro | Declaración |
|---|---|
| param | `param: string` |
| values | `values: string[]` |
### PairwiseEngine
| Miembro | Declaración |
|---|---|
| generate | `generate(parameters: ParameterOption[], requirementTitle = 'Configuración'): FormalGeneratedCase[]` |
### ErrorGuessingEngine
| Miembro | Declaración |
|---|---|
| generate | `generate(entityName: string): FormalGeneratedCase[]` |
### ClassificationClass
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| elements | `elements: string[]` |
### ClassificationTreeEngine
| Miembro | Declaración |
|---|---|
| generate | `generate(classes: ClassificationClass[], requirementTitle = 'Funcionalidad'): FormalGeneratedCase[]` |
### UseCaseInput
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| actor | `actor: string` |
| happyPathSteps | `happyPathSteps: string[]` |
| alternativeFlows | `alternativeFlows: { name: string; condition: string; steps: string[] }[]` |
| exceptionFlows | `exceptionFlows: { name: string; trigger: string; steps: string[]; expectedError: string }[]` |
### UseCaseEngine
| Miembro | Declaración |
|---|---|
| generate | `generate(uc: UseCaseInput): FormalGeneratedCase[]` |
## backend/src/core/test-design/gherkin-compiler.ts
### GherkinScenarioBlock
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| given | `given: string[]` |
| when | `when: string[]` |
| then | `then: string[]` |
| typeHint | `typeHint: ScenarioType \| null` |
| rawText | `rawText: string` |
### CompiledScenarioCase
| Miembro | Declaración |
|---|---|
| title | `title: string` |
| type | `type: ScenarioType` |
| preconditions | `preconditions: string[]` |
| steps | `steps: string[]` |
| expectedResult | `expectedResult: string` |
| evidenceText | `evidenceText: string` |
### GherkinFormatScenario
| Miembro | Declaración |
|---|---|
| name | `name: string` |
| type | `type: ScenarioType` |
| given | `given: string[]` |
| when | `when: string[]` |
| then | `then: string[]` |
### GherkinCompiler
| Miembro | Declaración |
|---|---|
| SCENARIO_REGEX | `SCENARIO_REGEX: tipo inferido` |
| GIVEN_REGEX | `GIVEN_REGEX: tipo inferido` |
| WHEN_REGEX | `WHEN_REGEX: tipo inferido` |
| THEN_REGEX | `THEN_REGEX: tipo inferido` |
| AND_REGEX | `AND_REGEX: tipo inferido` |
| TYPE_COMMENT_REGEX | `TYPE_COMMENT_REGEX: tipo inferido` |
| parse | `parse(text: string, fallbackName = 'Escenario principal'): GherkinScenarioBlock[]` |
| inferType | `inferType(block: GherkinScenarioBlock): ScenarioType` |
| compile | `compile(text: string, options: { titlePrefix?: string; fallbackName?: string } = {}): CompiledScenarioCase[]` |
| format | `format(scenarios: GherkinFormatScenario[]): string` |
| sentence | `sentence(fragment: string): string` |
## backend/src/core/test-design/requirements-quality-gate.ts
### AmbiguityMatch
| Miembro | Declaración |
|---|---|
| term | `term: string` |
| category | `category: 'subjective_adjective' \| 'vague_adverb' \| 'open_clause' \| 'non_verifiable'` |
| suggestion | `suggestion: string` |
| foundIn | `foundIn: 'title' \| 'description' \| 'acceptanceCriteria'` |
### QualityGateEvaluation
| Miembro | Declaración |
|---|---|
| testabilityScore | `testabilityScore: number` |
| testabilityLevel | `testabilityLevel: 'EXCELLENT' \| 'GOOD' \| 'NEEDS_IMPROVEMENT' \| 'POOR'` |
| recommendedTechnique | `recommendedTechnique: {
key: 'BVA' \| 'DECISION_TABLE' \| 'STATE_TRANSITION' \| 'EQUIVALENCE_PARTITIONING' \| 'TEMPLATE';
name: string;
rationale: string;
}` |
| syntaxAnalysis | `syntaxAnalysis: {
hasActor: boolean;
hasAction: boolean;
hasOutcome: boolean;
hasGivenWhenThen: boolean;
hasQuantitativeCriteria: boolean;
}` |
| ambiguities | `ambiguities: AmbiguityMatch[]` |
| strengths | `strengths: string[]` |
| improvements | `improvements: string[]` |
### RequirementsQualityGate
| Miembro | Declaración |
|---|---|
| VAGUE_TERMS_CATALOG | `VAGUE_TERMS_CATALOG: Array<{
regex: RegExp;
term: string;
category: AmbiguityMatch['category'];
suggestion: string;
}>` |
| evaluate | `evaluate(requirement: {
title: string;
description?: string \| null;
acceptanceCriteria?: string \| null;
}): QualityGateEvaluation` |
| parseEarsSyntax | `parseEarsSyntax(text: string): {
pattern: 'UBIQUITOUS' \| 'EVENT_DRIVEN' \| 'STATE_DRIVEN' \| 'UNWANTED_BEHAVIOUR' \| 'OPTIONAL' \| 'NON_EARS';
clause: string;
action: string;
}` |
| compileGherkinToTestCases | `compileGherkinToTestCases(gherkinText: string, reqTitle = 'Requisito'): Array<{
title: string;
preconditions: string[];
steps: string[];
expectedResult: string;
type: 'positive' \| 'negative';
}>` |
| extractDeterministicVariables | `extractDeterministicVariables(text: string): Array<{
name: string;
type: 'integer' \| 'decimal' \| 'string_length';
min: number;
max: number;
unit?: string;
}>` |
| analyzeRfc2119Priority | `analyzeRfc2119Priority(text: string): 'high' \| 'medium' \| 'low'` |
| detectCrossRequirementDependencies | `detectCrossRequirementDependencies(text: string): string[]` |
| transformUserStoryToRoleMatrix | `transformUserStoryToRoleMatrix(userStory: string): Array<{
role: string;
isAuthorized: boolean;
title: string;
expectedStatus: number;
description: string;
}>` |
## backend/src/core/test-design/shared-steps.ts
### SharedStepsEngine
| Miembro | Declaración |
|---|---|
| SHARED_BLOCKS | `SHARED_BLOCKS: Record<string, string[]>` |
| expandSteps | `expandSteps(steps: string[]): string[]` |
| listAvailableSharedSteps | `listAvailableSharedSteps(): Array<{ macro: string; steps: string[] }>` |
## backend/src/core/test-design/synthetic-data.ts
### SyntheticDataEngine
| Miembro | Declaración |
|---|---|
| validateLuhn | `validateLuhn(cardNumber: string): boolean` |
| generateLuhnCard | `generateLuhnCard(brand: 'visa' \| 'mastercard' \| 'amex' \| 'diners' \| 'jcb' = 'visa', isValid = true): { cardNumber: string; brand: string; isValid: boolean; expDate: string; cvv: string }` |
| generateDni | `generateDni(isValid = true): { dni: string; isValid: boolean }` |
| validateRuc | `validateRuc(ruc: string): boolean` |
| generateRuc | `generateRuc(type: 'natural' \| 'juridica' = 'juridica', isValid = true): { ruc: string; type: string; isValid: boolean; description: string }` |
| validateRutChile | `validateRutChile(rut: string): boolean` |
| generateRutChile | `generateRutChile(isValid = true): { rut: string; isValid: boolean }` |
| generateRfcMexico | `generateRfcMexico(type: 'fisica' \| 'moral' = 'moral', isValid = true): { rfc: string; isValid: boolean }` |
| generateCurpMexico | `generateCurpMexico(isValid = true): { curp: string; isValid: boolean }` |
| validateCuitArgentina | `validateCuitArgentina(cuit: string): boolean` |
| generateCuitArgentina | `generateCuitArgentina(isValid = true): { cuit: string; isValid: boolean }` |
| validateNifSpain | `validateNifSpain(nif: string): boolean` |
| generateNifSpain | `generateNifSpain(isValid = true): { nif: string; isValid: boolean }` |
| getCriticalBoundaryDates | `getCriticalBoundaryDates(): Record<string, { label: string; value: string; type: string; description: string }>` |
| getPassiveSecurityPayloads | `getPassiveSecurityPayloads(): Record<string, { label: string; payload: string; category: string; description: string }>` |
| getBoundaryDataSet | `getBoundaryDataSet(maxLength = 255): Record<string, { label: string; value: string; type: string; purpose: string }>` |
| getBoundaryGeoCoordinates | `getBoundaryGeoCoordinates(): Record<string, { label: string; lat: number; lng: number; isValid: boolean; description: string }>` |
| getSyntheticFiles | `getSyntheticFiles(): Record<string, { filename: string; mimeType: string; sizeBytes: number; base64: string; purpose: string }>` |
| getNetworkData | `getNetworkData(): Record<string, { label: string; value: string; family: 'IPv4' \| 'IPv6'; type: string; purpose: string }>` |
| getSyntheticEmail | `getSyntheticEmail(isValid = true): string` |
## backend/src/core/validation/ai-output.validator.ts
### validateAIResponse
`export function validateAIResponse(jsonText: string): ValidatedAIOutput`
## backend/src/infrastructure/importers/openapi-importer.service.ts
### OpenApiEndpointCase
| Miembro | Declaración |
|---|---|
| endpoint | `endpoint: string` |
| method | `method: string` |
| summary | `summary: string` |
| expectedStatus | `expectedStatus: string` |
| title | `title: string` |
| type | `type: 'positive' \| 'negative' \| 'boundary'` |
### OpenApiImporterService
| Miembro | Declaración |
|---|---|
| importOpenApiSpec | `importOpenApiSpec(projectId: string, openApiJson: Record<string, unknown>): retorno inferido` |
## backend/src/infrastructure/repositories/prisma-project.repository.ts
### PrismaProjectRepository
| Miembro | Declaración |
|---|---|
| findById | `findById(id: string): Promise<ProjectEntity \| null>` |
| findByOwner | `findByOwner(ownerId: string, options?: PaginationOptions): Promise<PaginatedResult<ProjectEntity>>` |
| create | `create(project: ProjectEntity): Promise<ProjectEntity>` |
| update | `update(id: string, data: Partial<ProjectEntity>): Promise<ProjectEntity>` |
| archive | `archive(id: string): Promise<boolean>` |
| delete | `delete(id: string): Promise<boolean>` |
## backend/src/infrastructure/repositories/prisma-requirement.repository.ts
### PrismaRequirementRepository
| Miembro | Declaración |
|---|---|
| findById | `findById(id: string): Promise<RequirementEntity \| null>` |
| findByProjectId | `findByProjectId(projectId: string, options?: PaginationOptions, statusFilter?: string): Promise<PaginatedResult<RequirementEntity>>` |
| save | `save(requirement: RequirementEntity): Promise<void>` |
| createVersion | `createVersion(requirementId: string, authorId: string, summary: string): Promise<number>` |
| delete | `delete(id: string): Promise<boolean>` |
## backend/src/infrastructure/repositories/prisma-test-case.repository.ts
### PrismaTestCaseRepository
| Miembro | Declaración |
|---|---|
| reviewsInclude | `reviewsInclude: tipo inferido` |
| findById | `findById(id: string): Promise<TestCaseEntity \| null>` |
| findByRequirementId | `findByRequirementId(requirementId: string): Promise<TestCaseEntity[]>` |
| findByProjectId | `findByProjectId(projectId: string, options?: PaginationOptions): Promise<PaginatedResult<TestCaseEntity>>` |
| save | `save(testCase: TestCaseEntity): Promise<void>` |
| saveBatch | `saveBatch(testCases: TestCaseEntity[]): Promise<void>` |
| delete | `delete(id: string): Promise<boolean>` |
## backend/src/infrastructure/repositories/prisma-test-run.repository.ts
### PrismaTestRunRepository
| Miembro | Declaración |
|---|---|
| findById | `findById(id: string): Promise<TestRunEntity \| null>` |
| findByProjectId | `findByProjectId(projectId: string): Promise<TestRunEntity[]>` |
| create | `create(run: TestRunEntity, initialCases: Array<{ testCaseId: string; code: string; title: string }>): Promise<TestRunEntity>` |
| recordExecution | `recordExecution(runId: string, caseId: string, status: string, durationSeconds: number, evidenceText?: string, executedBy?: string): Promise<TestExecutionResultProps>` |
| logDefect | `logDefect(runId: string, caseId: string, defectNotes: string): Promise<TestExecutionResultProps>` |
## backend/src/infrastructure/webhooks/webhook.service.ts
### WebhookEventPayload
| Miembro | Declaración |
|---|---|
| event | `event: 'REQUIREMENT_APPROVED_100' \| 'TEST_RUN_COMPLETED' \| 'DEFECT_LOGGED'` |
| projectId | `projectId: string` |
| projectName | `projectName: string` |
| summary | `summary: string` |
| details | `details: Record<string, unknown>` |
| timestamp | `timestamp: string` |
### OutgoingWebhookService
| Miembro | Declaración |
|---|---|
| isSafeUrl | `isSafeUrl(targetUrl: string): boolean` |
| dispatch | `dispatch(url: string, payload: WebhookEventPayload): Promise<boolean>` |
## backend/src/modules/export/export.service.ts
### ExportTestCase
| Miembro | Declaración |
|---|---|
| code | `code: string` |
| type | `type: string` |
| title | `title: string` |
| preconditions | `preconditions: unknown` |
| steps | `steps: unknown` |
| testData | `testData: string \| null` |
| expectedResult | `expectedResult: string` |
| priority | `priority: string` |
| evidenceStatus | `evidenceStatus: string` |
| evidenceText | `evidenceText: string \| null` |
| status | `status: string` |
| version | `version: number` |
| requirementVersion | `requirementVersion: number` |
### ExportRequirement
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| code | `code: string` |
| title | `title: string` |
| description | `description: string` |
| acceptanceCriteria | `acceptanceCriteria: string` |
| version | `version: number` |
| testCases | `testCases: ExportTestCase[]` |
### ExportProject
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| name | `name: string` |
| description | `description: string \| null` |
| requirements | `requirements: ExportRequirement[]` |
### parseArray
`function parseArray(val: unknown): string[]`
### calculateSuiteSha256
`export function calculateSuiteSha256(project: ExportProject): string`
### buildCsv
`export function buildCsv(project: ExportProject): string`
### buildMarkdown
`export function buildMarkdown(project: ExportProject): string`
### buildJson
`export function buildJson(project: ExportProject)`
### buildGherkin
`export function buildGherkin(project: ExportProject): string`
### buildXrayJson
`export function buildXrayJson(project: ExportProject)`
### buildTestRailCsv
`export function buildTestRailCsv(project: ExportProject): string`
### buildIEEE829TestPlan
`export function buildIEEE829TestPlan(project: ExportProject): string`
### buildReportHtml
`export function buildReportHtml(project: ExportProject): string`
### safeFilename
`export function safeFilename(name: string): string`
## backend/src/modules/metrics/metrics.service.ts
### TestCaseMetricInput
| Miembro | Declaración |
|---|---|
| status | `status: string` |
| evidenceStatus | `evidenceStatus: string` |
| type | `type: string` |
| source | `source: string` |
| isObsolete | `isObsolete: boolean` |
### AiGenerationMetricInput
| Miembro | Declaración |
|---|---|
| inputTokens | `inputTokens: number` |
| outputTokens | `outputTokens: number` |
| estimatedCost | `estimatedCost: number \| null` |
| responseTimeMs | `responseTimeMs: number` |
| status | `status: string` |
| requirementId | `requirementId: string` |
### RequirementMetricInput
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| status | `status: string` |
| testCases | `testCases: TestCaseMetricInput[]` |
| aiGenerations | `aiGenerations: AiGenerationMetricInput[]` |
### ProjectMetricInput
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| name | `name: string` |
| requirements | `requirements: RequirementMetricInput[]` |
### computeProjectMetrics
`export function computeProjectMetrics(project: ProjectMetricInput)`
## backend/src/modules/requirements/ambiguity-detector.ts
### AmbiguityIssue
| Miembro | Declaración |
|---|---|
| rule | `rule: string` |
| category | `category: 'VAGUE_TERM' \| 'UNVERIFIABLE' \| 'COMPOUND' \| 'MISSING_ACTOR'` |
| severity | `severity: 'HIGH' \| 'MEDIUM' \| 'LOW'` |
| snippet | `snippet: string` |
| explanation | `explanation: string` |
| suggestion | `suggestion: string` |
### AmbiguityAnalysisResult
| Miembro | Declaración |
|---|---|
| hasWarnings | `hasWarnings: boolean` |
| warningsCount | `warningsCount: number` |
| issues | `issues: AmbiguityIssue[]` |
### AmbiguityDetector
| Miembro | Declaración |
|---|---|
| VAGUE_TERMS | `VAGUE_TERMS: tipo inferido` |
| analyze | `analyze(description: string, acceptanceCriteria: string): AmbiguityAnalysisResult` |
## backend/src/modules/requirements/import.service.ts
### RowValidationError
| Miembro | Declaración |
|---|---|
| rowNumber | `rowNumber: number` |
| code | `code: string` |
| field | `field: string` |
| message | `message: string` |
### ImportPreviewResult
| Miembro | Declaración |
|---|---|
| totalRows | `totalRows: number` |
| validRows | `validRows: RequirementImportRow[]` |
| errors | `errors: RowValidationError[]` |
| isValid | `isValid: boolean` |
### RequirementImportService
| Miembro | Declaración |
|---|---|
| parseCsv | `parseCsv(csvText: string): string[][]` |
| previewCsv | `previewCsv(csvContent: string): ImportPreviewResult` |
| previewJson | `previewJson(data: unknown[]): ImportPreviewResult` |
## backend/src/modules/test-cases/duplicate-detector.ts
### TestCaseComparable
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| code | `code: string` |
| title | `title: string` |
| steps | `steps: string[] \| string` |
| expectedResult | `expectedResult: string` |
### DuplicateCandidate
| Miembro | Declaración |
|---|---|
| caseCodeA | `caseCodeA: string` |
| caseCodeB | `caseCodeB: string` |
| caseTitleA | `caseTitleA: string` |
| caseTitleB | `caseTitleB: string` |
| similarityScore | `similarityScore: number` |
| reason | `reason: 'EXACT_MATCH' \| 'HIGH_SIMILARITY' \| 'IDENTICAL_STEPS_AND_RESULT'` |
### DuplicateDetector
| Miembro | Declaración |
|---|---|
| normalizeText | `normalizeText(text: string): string` |
| normalizeSteps | `normalizeSteps(steps: string[] \| string): string` |
| calculateSimilarity | `calculateSimilarity(textA: string, textB: string): number` |
| findDuplicates | `findDuplicates(cases: TestCaseComparable[], threshold = 0.85): DuplicateCandidate[]` |
## backend/src/modules/test-runs/test-runs.service.ts
### TestCaseExecutionResult
| Miembro | Declaración |
|---|---|
| testCaseId | `testCaseId: string` |
| code | `code: string` |
| title | `title: string` |
| status | `status: ExecutionStatus` |
| durationSeconds | `durationSeconds: number` |
| executedAt | `executedAt: string \| null` |
| executedBy | `executedBy: string \| null` |
| evidenceText | `evidenceText: string \| null` |
| defectNotes | `defectNotes: string \| null` |
| defectLogged | `defectLogged: boolean` |
### TestRun
| Miembro | Declaración |
|---|---|
| id | `id: string` |
| projectId | `projectId: string` |
| name | `name: string` |
| environment | `environment: string` |
| createdAt | `createdAt: string` |
| updatedAt | `updatedAt: string` |
| status | `status: 'IN_PROGRESS' \| 'COMPLETED'` |
| cases | `cases: TestCaseExecutionResult[]` |
### toLegacyTestRun
`function toLegacyTestRun(entity: TestRunEntity): TestRun`
### TestRunsService
| Miembro | Declaración |
|---|---|
| createRun | `createRun(projectId: string, name: string, environment = 'QA Sandbox', caseIds?: string[]): Promise<TestRun>` |
| getRun | `getRun(runId: string): Promise<TestRun>` |
| listRunsByProject | `listRunsByProject(projectId: string): Promise<TestRun[]>` |
| recordExecution | `recordExecution(runId: string, caseId: string, status: ExecutionStatus, durationSeconds = 0, evidenceText?: string, executedBy = 'QA Tester'): Promise<TestCaseExecutionResult>` |
| logDefectFromRun | `logDefectFromRun(runId: string, caseId: string, defectNotes: string, userId: string): retorno inferido` |
| getRunMetrics | `getRunMetrics(runId: string): retorno inferido` |
| compareRuns | `compareRuns(runIdA: string, runIdB: string): retorno inferido` |