import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as lambdaNodejs from 'aws-cdk-lib/aws-lambda-nodejs'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as dynamodb from 'aws-cdk-lib/aws-dynamodb'; import * as events from 'aws-cdk-lib/aws-events'; import * as targets from 'aws-cdk-lib/aws-events-targets'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as path from 'path'; export interface WorkorderSyncProps { region: string; kbDocsBucket: s3.Bucket; knowledgeBaseId: string; dataSourceId: string; } export class WorkorderSyncConstruct extends Construct { public readonly syncLambda: lambdaNodejs.NodejsFunction; constructor(scope: Construct, id: string, props: WorkorderSyncProps) { super(scope, id); // Import existing DynamoDB tables by name (owned by workorder-ingest stack) const workOrdersTable = dynamodb.Table.fromTableName( this, 'WorkOrdersTable', 'WorkOrders', ); const commentsTable = dynamodb.Table.fromTableName( this, 'WorkOrderCommentsTable', 'WorkOrderComments', ); // Lambda — scans DynamoDB work orders + comments, uploads markdown to S3, triggers KB ingestion this.syncLambda = new lambdaNodejs.NodejsFunction(this, 'SyncLambda', { functionName: 'seahaven-workorder-sync', entry: path.join(__dirname, '../../lambda/workorder-sync/index.ts'), runtime: lambda.Runtime.NODEJS_22_X, memorySize: 512, timeout: cdk.Duration.minutes(5), environment: { WORK_ORDERS_TABLE: workOrdersTable.tableName, COMMENTS_TABLE: commentsTable.tableName, KB_BUCKET_NAME: props.kbDocsBucket.bucketName, KNOWLEDGE_BASE_ID: props.knowledgeBaseId, DATA_SOURCE_ID: props.dataSourceId, REGION: props.region, }, }); // Grant read access to both DynamoDB tables workOrdersTable.grantReadData(this.syncLambda); commentsTable.grantReadData(this.syncLambda); // Grant read/write to the KB docs bucket (read to list+delete old, write new) props.kbDocsBucket.grantReadWrite(this.syncLambda); // Allow Lambda to start a Bedrock KB ingestion job this.syncLambda.addToRolePolicy( new iam.PolicyStatement({ actions: ['bedrock:StartIngestionJob'], resources: [ `arn:aws:bedrock:${props.region}:*:knowledge-base/${props.knowledgeBaseId}`, ], }), ); // EventBridge rule — fires daily at 02:00 UTC const dailyRule = new events.Rule(this, 'DailySyncRule', { ruleName: 'seahaven-workorder-daily-sync', description: 'Daily Work Orders → KB sync at 02:00 UTC', schedule: events.Schedule.cron({ minute: '0', hour: '2' }), }); dailyRule.addTarget(new targets.LambdaFunction(this.syncLambda)); } }