This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
seahaven-slack-bot/lib/constructs/notion-sync.ts
Adam Moussa 8b18279023 feat: daily Notion → Bedrock KB sync
Adds a scheduled Lambda that pulls all pages from the Office Operations
Notion teamspace, converts them to markdown, uploads to the KB S3 bucket
under a notion/ prefix, and triggers a Bedrock ingestion job. Runs daily
at 02:00 UTC via EventBridge. Notion API key stored in Secrets Manager at
seahaven/notion/api-key (placeholder — fill in post-deploy).
2026-04-12 22:21:39 -04:00

83 lines
3.1 KiB
TypeScript

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 secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
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 NotionSyncProps {
region: string;
kbDocsBucket: s3.Bucket;
knowledgeBaseId: string;
dataSourceId: string;
}
export class NotionSyncConstruct extends Construct {
public readonly syncLambda: lambdaNodejs.NodejsFunction;
public readonly notionSecret: secretsmanager.Secret;
constructor(scope: Construct, id: string, props: NotionSyncProps) {
super(scope, id);
// Notion integration token — placeholder created here, filled in post-deploy.
// Update via: AWS Console → Secrets Manager → seahaven/notion/api-key → Retrieve and edit
this.notionSecret = new secretsmanager.Secret(this, 'NotionSecret', {
secretName: 'seahaven/notion/api-key',
description: 'Notion integration token for the Office Operations teamspace KB sync',
secretObjectValue: {
apiKey: cdk.SecretValue.unsafePlainText('REPLACE_ME_after_deploy'),
},
});
// Lambda — fetches Notion pages, uploads markdown to S3, triggers KB ingestion
this.syncLambda = new lambdaNodejs.NodejsFunction(this, 'SyncLambda', {
functionName: 'seahaven-notion-sync',
entry: path.join(__dirname, '../../lambda/notion-sync/index.ts'),
runtime: lambda.Runtime.NODEJS_22_X,
memorySize: 512,
timeout: cdk.Duration.minutes(5),
environment: {
NOTION_SECRET_ARN: this.notionSecret.secretArn,
KB_BUCKET_NAME: props.kbDocsBucket.bucketName,
KNOWLEDGE_BASE_ID: props.knowledgeBaseId,
DATA_SOURCE_ID: props.dataSourceId,
REGION: props.region,
},
});
// Allow Lambda to read the Notion secret
this.notionSecret.grantRead(this.syncLambda);
// Allow Lambda to read existing notion/ objects and write new ones
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-notion-daily-sync',
description: 'Daily Notion → KB sync at 02:00 UTC',
schedule: events.Schedule.cron({ minute: '0', hour: '2' }),
});
dailyRule.addTarget(new targets.LambdaFunction(this.syncLambda));
// Surface the secret name so operators know where to put the token
new cdk.CfnOutput(scope, 'NotionSecretName', {
value: this.notionSecret.secretName,
description: 'Set your Notion integration token here after deploy (apiKey field)',
});
}
}