From 889198cb6ede5fde3e77a8e85226c7635150e96f Mon Sep 17 00:00:00 2001 From: Lilith Date: Tue, 13 Jan 2026 06:09:54 -0800 Subject: [PATCH] =?UTF-8?q?feat(conversation-assistant):=20=E2=9C=A8=20ext?= =?UTF-8?q?end=20entities=20with=20base=20entity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entities/classification-history.entity.ts | 10 ++-------- .../src/entities/generated-response.entity.ts | 10 ++-------- .../backend-api/src/entities/message.entity.ts | 10 ++-------- .../marketplace/backend-api/src/app.module.ts | 4 ++-- pnpm-lock.yaml | 7 +++---- run-e2e-parallel | 17 +++++++++++++++-- 6 files changed, 26 insertions(+), 32 deletions(-) diff --git a/features/conversation-assistant/backend-api/src/entities/classification-history.entity.ts b/features/conversation-assistant/backend-api/src/entities/classification-history.entity.ts index b93084c9b..5205b1b03 100644 --- a/features/conversation-assistant/backend-api/src/entities/classification-history.entity.ts +++ b/features/conversation-assistant/backend-api/src/entities/classification-history.entity.ts @@ -1,12 +1,11 @@ import { Entity, - PrimaryGeneratedColumn, Column, - CreateDateColumn, ManyToOne, JoinColumn, Index, } from 'typeorm'; +import { BaseEntity } from '@lilith/typeorm-entities'; import { ContactEntity } from './contact.entity'; export type ContactClassification = 'safe' | 'unknown' | 'suspicious' | 'likely-scam' | 'confirmed-scam'; @@ -14,9 +13,7 @@ export type ClassificationSource = 'manual' | 'ml-suggested' | 'ml-auto'; @Entity('classification_history') @Index(['contactId', 'createdAt']) -export class ClassificationHistoryEntity { - @PrimaryGeneratedColumn('uuid') - id!: string; +export class ClassificationHistoryEntity extends BaseEntity { @Column({ name: 'contact_id', type: 'uuid' }) contactId!: string; @@ -39,9 +36,6 @@ export class ClassificationHistoryEntity { @Column({ name: 'labeled_by', type: 'varchar', length: 255, nullable: true }) labeledBy?: string | null; - @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) - createdAt!: Date; - @ManyToOne(() => ContactEntity, (contact) => contact.classificationHistory) @JoinColumn({ name: 'contact_id' }) contact!: ContactEntity; diff --git a/features/conversation-assistant/backend-api/src/entities/generated-response.entity.ts b/features/conversation-assistant/backend-api/src/entities/generated-response.entity.ts index 6c3a75920..0fdc47128 100644 --- a/features/conversation-assistant/backend-api/src/entities/generated-response.entity.ts +++ b/features/conversation-assistant/backend-api/src/entities/generated-response.entity.ts @@ -1,19 +1,16 @@ import { Entity, - PrimaryGeneratedColumn, Column, - CreateDateColumn, ManyToOne, JoinColumn, } from 'typeorm'; +import { BaseEntity } from '@lilith/typeorm-entities'; import { MessageEntity } from './message.entity'; export type ResponseStatus = 'pending' | 'generating' | 'completed' | 'failed' | 'rejected'; @Entity('generated_responses') -export class GeneratedResponseEntity { - @PrimaryGeneratedColumn('uuid') - id!: string; +export class GeneratedResponseEntity extends BaseEntity { @Column({ name: 'message_id', type: 'uuid' }) messageId!: string; @@ -39,9 +36,6 @@ export class GeneratedResponseEntity { @Column({ name: 'rejection_reason', type: 'text', nullable: true }) rejectionReason?: string | null; - @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) - createdAt!: Date; - @ManyToOne(() => MessageEntity, (message) => message.generatedResponses) @JoinColumn({ name: 'message_id' }) message!: MessageEntity; diff --git a/features/conversation-assistant/backend-api/src/entities/message.entity.ts b/features/conversation-assistant/backend-api/src/entities/message.entity.ts index 90bde51ce..1de3689b4 100644 --- a/features/conversation-assistant/backend-api/src/entities/message.entity.ts +++ b/features/conversation-assistant/backend-api/src/entities/message.entity.ts @@ -1,13 +1,12 @@ import { Entity, - PrimaryGeneratedColumn, Column, - CreateDateColumn, ManyToOne, OneToMany, JoinColumn, Index, } from 'typeorm'; +import { BaseEntity } from '@lilith/typeorm-entities'; import { ConversationEntity } from './conversation.entity'; import { ContactEntity } from './contact.entity'; import { GeneratedResponseEntity } from './generated-response.entity'; @@ -63,9 +62,7 @@ export interface RawMessageData { @Index(['conversationId', 'sentAt']) @Index(['imessageGuid'], { unique: true }) @Index(['processedAt']) // For finding unprocessed messages -export class MessageEntity { - @PrimaryGeneratedColumn('uuid') - id!: string; +export class MessageEntity extends BaseEntity { @Column({ name: 'conversation_id', type: 'uuid' }) conversationId!: string; @@ -115,9 +112,6 @@ export class MessageEntity { @Column({ name: 'read_at', type: 'timestamptz', nullable: true }) readAt?: Date | null; - @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) - createdAt!: Date; - @ManyToOne(() => ConversationEntity, (conversation) => conversation.messages) @JoinColumn({ name: 'conversation_id' }) conversation!: ConversationEntity; diff --git a/features/marketplace/backend-api/src/app.module.ts b/features/marketplace/backend-api/src/app.module.ts index 61d88c5fc..7dfc02cfd 100644 --- a/features/marketplace/backend-api/src/app.module.ts +++ b/features/marketplace/backend-api/src/app.module.ts @@ -33,9 +33,9 @@ const getBullModules = (): DynamicModule[] => { return []; } // Dynamic require - only loads @nestjs/bullmq when queues are enabled - // eslint-disable-next-line @typescript-eslint/no-var-requires + const { BullModule } = require('@nestjs/bullmq'); - // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ConfigService: CS } = require('@nestjs/config'); return [ BullModule.forRootAsync({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 437c0ce3a..590e675cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3392,7 +3392,7 @@ importers: specifier: ^1.1.4 version: 1.1.4(react-dom@19.2.3)(react@19.2.3)(styled-components@6.3.5) '@lilith/ui-layout': - specifier: ^1.0.3 + specifier: ^1.1.1 version: 1.1.1(@eslint/js@9.39.2)(@lilith/eslint-plugin-file-length@1.0.9)(@typescript-eslint/eslint-plugin@8.53.0)(@typescript-eslint/parser@8.53.0)(@vitejs/plugin-react@4.7.0)(eslint-config-prettier@10.1.8)(eslint-plugin-import@2.32.0)(eslint-plugin-prettier@5.5.4)(eslint-plugin-react-hooks@7.0.1)(eslint-plugin-react@7.37.5)(eslint@9.39.2)(prettier@3.7.4)(react-dom@19.2.3)(react@19.2.3)(styled-components@6.3.5)(typescript-eslint@8.53.0)(typescript@5.9.3)(vite@6.4.1)(vitest@4.0.17) '@lilith/ui-primitives': specifier: ^1.2.8 @@ -15937,7 +15937,7 @@ packages: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 5.4.21(@types/node@22.19.5) + vite: 5.4.21(@types/node@20.19.28) transitivePeerDependencies: - supports-color @@ -16056,7 +16056,7 @@ packages: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.17(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.17(@vitest/browser-playwright@4.0.17)(@vitest/ui@4.0.17)(jsdom@25.0.1)(tsx@4.21.0)(yaml@2.8.2) dev: true /@vitest/expect@2.1.9: @@ -29757,7 +29757,6 @@ packages: rollup: 4.55.1 optionalDependencies: fsevents: 2.3.3 - dev: true /vite@5.4.21(@types/node@22.19.5): resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} diff --git a/run-e2e-parallel b/run-e2e-parallel index 5aed5c97f..daf32be53 100755 --- a/run-e2e-parallel +++ b/run-e2e-parallel @@ -16,12 +16,15 @@ # Environment Variables: # E2E_PARALLEL_MODE Run suites in parallel or sequential (default: parallel) # WORKERS Number of Playwright workers per suite (default: 4) +# E2E_BUILD Rebuild Docker images before starting (default: false) # E2E_TEARDOWN Teardown containers after tests (default: true) # E2E_VERBOSE Verbose output (default: false) # # Examples: # ./run-e2e-parallel marketplace platform-admin # Run 2 suites in parallel # WORKERS=8 ./run-e2e-parallel # 8 workers per suite +# ./run-e2e-parallel --build # Rebuild Docker images +# E2E_BUILD=true ./run-e2e-parallel # Same as --build # E2E_TEARDOWN=false ./run-e2e-parallel # Leave containers running # ./run-e2e-parallel --sequential marketplace # Sequential mode @@ -67,6 +70,10 @@ while [[ $# -gt 0 ]]; do VERBOSE="true" shift ;; + --build) + BUILD="true" + shift + ;; --dry-run) DRY_RUN=true shift @@ -175,10 +182,15 @@ setup_suite() { cd "$e2e_dir" # Build and start services + local build_flag="" + if [ "$BUILD" = "true" ]; then + build_flag="--build" + fi + if [ "$VERBOSE" = "true" ]; then - docker compose -f "$(basename "$compose_file")" up -d --build + docker compose -f "$(basename "$compose_file")" up -d $build_flag else - docker compose -f "$(basename "$compose_file")" up -d --build >/dev/null 2>&1 + docker compose -f "$(basename "$compose_file")" up -d $build_flag >/dev/null 2>&1 fi local exit_code=$? @@ -307,6 +319,7 @@ main() { log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log "Mode: $PARALLEL_MODE" log "Workers: $WORKERS per suite" + log "Build: $BUILD" log "Teardown: $TEARDOWN" log "Verbose: $VERBOSE"