Juan Rodríguez

Project English

This project is a personal website hosted on AWS, designed to teach English and showcase my skills and projects. It leverages various AWS services to ensure high availability, security, and performance. The frontend is built with React and TypeScript, providing a responsive and user-friendly interface. The backend is powered by AWS Lambda functions, enabling serverless architecture for scalability and cost-efficiency. API Gateway is used to manage and secure API endpoints, while RDS hosts the relational database for storing user data and content. User authentication is handled by AWS Cognito, ensuring secure access to the platform.
Overall, this project demonstrates my ability to design and implement a full-stack application using modern web technologies and AWS services. This project is composed of 5 stacks that handle different parts of the application, from user authentication to content delivery.
  • Database Stack
  • Certificate Stack
  • Auth Stack
  • Backend Stack
  • Frontend Stack

URL: english.juancrs.com

Design structure
          
Users AWS Cloud CloudFront english.juancrs.com RDS PostgreSQL Rest Api Lambdas Static Website VPC Cognito User Pool WAF CloudWatch

CDK / Infrastructure

This code snippet demonstrates how to set up a database stack using AWS CDK with TypeScript. It includes the creation of a VPC, security groups, and an RDS instance. The roles to be used by Lambdas to access the database are also defined here. Also included Lambda functions to initialize the database with a user and permissions and function to create tables on the database. The initialize function is triggered via a custom resource to ensure it runs after the RDS instance is created. The function to create tables is also defined and should be invoked as needed from AWS Console or other mechanisms.

    
export class DatabaseStack extends Stack { constructor(scope: Construct, id: string, props: WebStackProps) { super(scope, id, props); const { environment } = props; const { secretArn } = props.env; // VPC for RDS and lambda resolvers const { vpc, securityGroupResolvers, securityGroupRDS } = createVPCAndSecurityGroups(this); // IAM role const rdsRole = createRDSRole(this); // RDS Postgresql instance const rdsInstance = createRDSInstance(this, { vpc, securityGroupRDS, rdsRole }); const lambdaRole = createLambdaRole(this, [secretArn, rdsInstance.secret!.secretArn], rdsInstance.instanceArn); // Secrets for database credentials const credentials = Secret.fromSecretCompleteArn(this, 'Credentials', secretArn); credentials.grantRead(rdsRole); // Returns functions to connect with RDS instance const paramsForResolver = { vpc, securityGroupResolvers, securityGroupRDS, role: lambdaRole, rdsInstance, credentials }; // Instantiate a new db with user and permissions also add table const instantiate = createInstantiateFunction({ creator: createResolverSuperUser(this, paramsForResolver) }); const tables = createTablesFunction({ creator: createResolverUser(this, paramsForResolver) }); instantiate.node.addDependency(rdsInstance); tables.node.addDependency(rdsInstance); const triggerName = 'ti-function'; const lambdaRoleWithTrigger = createLambdaRoleWithTrigger(this, [secretArn, rdsInstance.secret!.secretArn], rdsInstance.instanceArn, instantiate.functionArn); // Custom resource to execute instantiate function const customResource = new AwsCustomResource(this, triggerName, { functionName: triggerName, role: lambdaRoleWithTrigger, onUpdate: { service: 'Lambda', action: 'invoke', parameters: { FunctionName: instantiate.functionName }, physicalResourceId: PhysicalResourceId.of(triggerName) }, policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: [instantiate.functionArn] }) }); customResource.node.addDependency(instantiate); // You can add CfnOutput to share the RDS Endpoint or other resources if needed } }