constructor()

in cdk/lib/editorial-collaboration.ts [23:132]


	constructor(scope: App, id: string, props: EditorialCollaborationProps) {
		super(scope, id, props);

		const { domainName, stage } = props;

		const appName = 'editorial-collaboration';
		const appPort = 3000;

		const dbUsername = 'editorial_collaboration';
		const dbPort = 5432;

		const guEc2App = new GuEc2App(this, {
			access: { scope: AccessScope.PUBLIC },
			app: appName,
			applicationPort: appPort,
			certificateProps: {
				domainName,
			},
			monitoringConfiguration: { noMonitoring: true },
			scaling: {
				minimumInstances: 1,
				maximumInstances: 2,
			},
			userData: {
				distributable: {
					fileName: 'main.js',
					executionStatement: `
# add user
groupadd ${appName}
useradd -r -s /usr/bin/nologin -g ${appName} ${appName}
# write out systemd file
cat >/etc/systemd/system/${appName}.service <<EOL
[Service]
ExecStart=/usr/bin/node /${appName}/main.js
Restart=always
StandardOutput=journal
StandardError=journal
Environment=STAGE=${stage}
User=${appName}
Group=${appName}
[Install]
WantedBy=multi-user.target
EOL
# RUN
systemctl enable ${appName}
systemctl start ${appName}
					`,
				},
			},
			applicationLogging: { enabled: true, systemdUnitName: appName },
			instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MICRO),
			imageRecipe: 'editorial-tools-jammy-node20-ARM',
		});

		// Add the domain name
		new GuCname(this, 'DnsRecord', {
			app: appName,
			domainName: domainName,
			ttl: Duration.hours(1),
			resourceRecord: guEc2App.loadBalancer.loadBalancerDnsName,
		});

		const dbAccessSecurityGroup = new GuSecurityGroup(this, 'DBSecurityGroup', {
			app: appName,
			description: 'Allow traffic from EC2 instance to DB',
			vpc: guEc2App.vpc,
			allowAllOutbound: false,
		});

		dbAccessSecurityGroup.connections.allowFrom(
			guEc2App.autoScalingGroup,
			Port.tcp(dbPort),
			'Allow connections from EC2 instance to DB',
		);

		new GuDatabaseInstance(this, 'Database', {
			app: `${appName}-db`,
			databaseName: 'collaboration',
			instanceIdentifier: `${appName}-${stage}-db`,
			instanceType: 'db.t4g.micro',
			engine: rds.DatabaseInstanceEngine.postgres({
				version: rds.PostgresEngineVersion.VER_16_2,
			}),
			vpc: guEc2App.vpc,
			subnetGroup: new SubnetGroup(this, 'DBSubnetGroup', {
				vpc: guEc2App.vpc,
				vpcSubnets: {
					subnets: GuVpc.subnetsFromParameter(this),
				},
				description: 'Subnet for editorial collaboration database',
			}),
			port: dbPort,
			preferredMaintenanceWindow: 'Mon:06:30-Mon:07:00',
			credentials: rds.Credentials.fromGeneratedSecret(dbUsername, {
				secretName: `/${stage}/flexible/editorial-collaboration/db`,
			}),
			iamAuthentication: true,
			storageType: rds.StorageType.GP2, // SSD
			allocatedStorage: 150,
			storageEncrypted: true,
			multiAz: stage === 'PROD',
			publiclyAccessible: false,
			removalPolicy: RemovalPolicy.RETAIN,
			securityGroups: [dbAccessSecurityGroup],
			devXBackups: { enabled: true },
			allowMajorVersionUpgrade: false,
			autoMinorVersionUpgrade: true,
			deleteAutomatedBackups: false,
		});
	}