[{"uri":"https://nguyenankhang.rookwork.asia/3-blogsposted/3.1-blog1/","title":"","tags":[],"description":"","content":"Scaling Telco Automation to Millions of Devices with Managed Red Hat Ansible Automation Platform (AAP) on AWS and Red Hat OpenShift Service on AWS (ROSA) Published Date: June 30, 2026\nIf you are working in the telecommunications industry or operating networks with a massive number of edge nodes (such as home routers, modems, or broadband gateways) reaching millions of devices, rolling out configuration updates or upgrading firmware simultaneously without causing system congestion is always an extremely challenging problem.\nToday, I would like to share a very interesting architecture, adapted and detailed from the AWS Architecture Blog, which solves this ultra-large-scale challenge by combining Managed Red Hat Ansible Automation Platform (AAP) on AWS and Red Hat OpenShift Service on AWS (ROSA).\nThe Core Concept: Decoupling Control Plane and Execution Plane Traditional management systems often bundle the control plane (user interface, API) and the execution plane (running automation jobs) on the same server infrastructure. When you send updates to hundreds of thousands of devices at once, the sudden spike in CPU and memory usage can crash the entire management portal.\nThis modern architecture solves that by separating the two:\nControl Plane: Managed AAP on AWS acts as the central hub. It only handles the user interface, APIs, and overall orchestration. It dynamically syncs the device inventory from external CMDBs or Cloud Providers and retrieves playbooks from a centralized source control system like GitHub. Execution Plane: The heavy lifting of executing Ansible Playbooks is offloaded to Kubernetes pods (called Container Groups) running on the ROSA cluster. When a peak workload occurs, the execution plane can scale out dynamically to connect with edge gateways via IPv4/IPv6, while the control plane user interface remains fully responsive.\nHigh-Availability Infrastructure: Multi-Region \u0026amp; Stateless with Amazon S3 For disaster recovery, the control plane is deployed in an active-passive or active-active multi-region setup. The Ansible Playbooks, inventory details, and job execution logs are stored as stateless objects in Amazon S3, ensuring data durability and low-latency retrieval across regions.\nFacebook Post Link: AWS Study Group VN Original Article Link: Scaling telco automation to millions of devices\u0026hellip; "},{"uri":"https://nguyenankhang.rookwork.asia/4-eventparticipated/4.1-event1/","title":"","tags":[],"description":"","content":"Report on Community Day Event 23/5: Tech Trends and Practical Applications Event Overview On May 23rd, I had the opportunity to attend the AWS Community Day event. It wasn\u0026rsquo;t just a standard technical seminar; it was an inspiring celebration of technology. As an intern, this event helped me connect many dots: from network infrastructure optimization and personal knowledge management to practical applications of AI and Multi-agent systems in modern enterprises.\nHere are my key takeaways and lessons learned from the speakers at the event.\nKey Highlights \u0026amp; Lessons Learned 1. Knowledge Management \u0026amp; Personal Productivity (Speaker: Anh Tinh) The event kicked off with a talk by Anh Tinh on building a \u0026ldquo;Second Brain\u0026rdquo;, which really resonated with me.\nThe Problem: The speed of technology outpaces biological memory, easily leading to cognitive overload. The Solution: Build a structured external storage system (using Obsidian or Notion) with bi-directional linking. Personal Lesson: Instead of just bookmarking files passively, I need to create a \u0026ldquo;Personal Knowledge Graph\u0026rdquo; to quickly retrieve technical solutions and lessons from past projects. Mastering personal information management is the first step toward handling complex enterprise systems. 2. Cloud Infrastructure: From Edge to Origin (Speaker: Anh Thinh) Anh Thinh\u0026rsquo;s session, \u0026ldquo;From Edge To Origin: CloudFront as Your Foundation\u0026rdquo;, completely redefined how I view the CloudFront CDN service.\nMore than just Caching: CloudFront serves as the first layer of defense and optimization (the foundation) for the entire application. Latency Optimization: Resolving and delivering content at Edge Locations closest to users minimizes round-trip times. Edge Security: Integrating AWS WAF and Shield at the edge blocks DDoS attacks and exploit attempts before they ever reach the origin server. Origin Shield: Protects the origin from spikes, maintaining system availability during traffic surges. 3. Artificial Intelligence (AI): From Principles to Virtual Assistants (Speakers: Anh Dao Duc \u0026amp; Anh Hai Anh) The AI discussions provided a great balance between deep learning theory and practical assistants:\nHow LLMs Work: Anh Dao Duc explained the core mechanisms of Transformers, Attention, Tokenization, and inference. Understanding this helps write better prompts (Prompt Engineering) and manage compute resources efficiently.\nPractical Use: Anh Hai Anh introduced smart assistants similar to Amazon Q (Friendly AI Assistant with Amazon Quick), demonstrating how AI can automate repetitive daily tasks like code generation and document analysis.\nA quick comparison I compiled to distinguish the two aspects:\nCriteria Understanding AI (Theory \u0026amp; Architecture) Using AI (Practice \u0026amp; RAG/Agents) Technical Focus Transformer architecture, Attention mechanisms, and parameters. Prompt Engineering, RAG (Retrieval-Augmented Generation). Operational Goal Understand how the model predicts next tokens for evaluation and tuning. Integrate AI into workflows to process data and generate code. Business Value Assess model feasibility, safety, and limitations. Accelerate product delivery (Time-to-market). 4. Execution \u0026amp; Enterprise Deployment (VIB Team \u0026amp; Chi Cat Vy) These two case studies answered a key question: \u0026ldquo;How do we turn tech ideas into enterprise-grade systems?\u0026rdquo;\nUTMorpho (VIB Team): The team built UTMorpho—a flexible data and image transformation tool—in just 36 hours at the LotusHacks hackathon. The biggest lesson was agile project management under intense time pressure and leveraging existing APIs to build a quick MVP.\nMulti-Agent Systems in Credit Scoring (Chi Cat Vy): Instead of a single AI model, Vy introduced a system using multiple specialized agents (e.g., identity verification agent, risk analysis agent, and explainable AI agent - XAI). Coordinating these agents ensures high financial accuracy and meets strict transparency standards.\nPersonal Experience \u0026amp; Action Items for My Project Attending AWS Community Day was a highly valuable experience. It gave me the chance to learn from top experts, connect with the community, and see the big picture of where the industry is going.\nTo apply these insights to my own studies and ongoing development projects (like the Rookwork project), I plan to focus on three actions:\nBuild a Personal Knowledge Base: I will use Obsidian/Notion to document AWS configurations and troubleshooting steps encountered while developing Rookwork. Optimize Web Infrastructure with CloudFront: Configure CloudFront along with ACM SSL certificates and AWS WAF for the static frontend of Rookwork to ensure speed and edge security. Experiment with AI/Agent integrations: Explore building a mini-assistant or chatbot integrated within the task manager to automatically summarize issues or suggest assignee allocations. Community Day gave me a lot of motivation. Mastering technology isn\u0026rsquo;t just about reading theory—it\u0026rsquo;s about building, executing, and delivering real products!\n"},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.7-route53-s3-cloudfront-ses/5.7.1-route53/","title":"Domain &amp; AWS Route 53 Configuration","tags":[],"description":"","content":"To delegate DNS management of your custom domain purchased from Tenten.vn to AWS Route 53, perform the following delegation steps.\nStep 1: Create a Hosted Zone in Route 53 Log in to the AWS Management Console and navigate to the Route 53 service. Select Hosted zones from the left panel, and click Create hosted zone. Enter details: Domain name: Enter the exact domain name you purchased (e.g., rookwork.asia). Type: Select Public hosted zone. Click Create hosted zone. The system automatically generates 2 default records: NS (Name Server) and SOA (Start of Authority). Step 2: Retrieve Route 53 Name Servers Click on the Hosted Zone you just created. Locate the record with type NS. Copy the 4 Name Server addresses listed in the Value column (e.g., ns-xxxx.awsdns-xx.com., note to omit the trailing period when configuring on Tenten). Step 3: Configure Name Servers on Tenten.vn Log in to your customer portal on Tenten.vn. Navigate to your domain list, and select Configure Name Server (NS) for the corresponding domain name. Replace Tenten\u0026rsquo;s default name servers with the 4 NS addresses copied from Route 53 in Step 2. Save the configuration. (Note: Global DNS propagation can take anywhere from a few minutes up to 24 hours to fully update).\nOnce DNS delegation is configured, proceed to 5.7.2. Static Website Hosting with S3 to prepare hosting for your Frontend assets.\n"},{"uri":"https://nguyenankhang.rookwork.asia/","title":"Internship Report","tags":[],"description":"","content":"Internship Report Student Information: Full Name: Nguyen An Khang\nPhone Number: 0355760430\nEmail: ankhangnguyen941@gmail.com\nUniversity: Ho Chi Minh City University of Technology\nMajor: Information Technology\nClass: 22DTHG1\nInternship Company: Amazon Web Services Viet Nam Company Limited\nInternship Position: Workforce Bootcamp - First Cloud AI Journey\nInternship Duration: From 17/04/2026 to 10/07/2026\nReport Content Worklog Proposal BlogsPosted Events Participated Workshop Self-evaluation Sharing and Feedback "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.1-workshop-overview/","title":"Introduction","tags":[],"description":"","content":"Project Overview Rookwork is an integrated, multi-platform team collaboration management software (browser and desktop app) designed to facilitate real-time project management and team synchronization. The system utilizes a modern Client-Server architecture, featuring a React 19 frontend and a robust Spring Boot backend. To ensure high availability (HA), security, and seamless content delivery, the entire infrastructure is deployed on AWS Cloud. This section provides a comprehensive look at how these AWS services are architected to support the application\u0026rsquo;s core workflows, from networking and compute to database storage and shared services.\nSystem Architecture The system operates through the following main processing flows:\n1 DNS Resolution \u0026amp; CDN:\nRoute 53 resolves the domain name and routes users to the system. CloudFront distributes the static frontend from FE Static S3, combined with AWS WAF to protect against web exploits. 2 Routing \u0026amp; Compute Backend:\nAPI traffic flows through the Internet Gateway → ALB (Application Load Balancer) → load-balanced to EC2 instances placed inside Private Subnets. EC2 accesses the internet for outbound calls via the NAT Gateway (step 6.1 — Route to Internet). 3 Database \u0026amp; Storage:\nBusiness data is stored on Amazon RDS PostgreSQL, deployed in a Multi-AZ setup (step 7 — DB Replication) for disaster recovery. File attachments are written by EC2 to Amazon S3 via the S3 Gateway Endpoint using Internal Routing (steps 8 \u0026amp; 9) — bypassing the public internet and reducing internal bandwidth costs to zero. Users download files directly via Direct File Access (step 10). 4 Shared Services:\nAmazon SES delivers email notifications (e.g., workspace invitations) triggered from EC2 (steps 6.2 \u0026amp; 6.3). AWS Certificate Manager (ACM) manages SSL/TLS certificates, and AWS IAM controls system-wide permissions. After understanding the system architecture, proceed to 5.2 — Prerequisite to configure the required tools.\n"},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.1-week1/","title":"Week 1 Worklog","tags":[],"description":"","content":"Week 1 Objectives: Create and secure an AWS Free Tier account. Understand the basics of AWS services and cloud computing. Install and configure AWS CLI on local machine. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Research AWS cloud architecture and signup for AWS Free Tier. Configure MFA and IAM root user security. 04/20/2026 04/20/2026 https://000001.awsstudygroup.com/ 3 Study AWS Cloud Quest and complete the 5 required tasks to gain an additional $100 credit. 04/21/2026 04/21/2026 https://000001.awsstudygroup.com/ 4 Install AWS CLI on local development environment, verify installation. 04/22/2026 04/22/2026 https://000011.awsstudygroup.com/ 5 Configure AWS credentials (Access Key, Secret Key, default region) and run basic CLI commands. 04/23/2026 04/23/2026 https://000011.awsstudygroup.com/ Week 1 Achievements: Successfully created an AWS Free Tier account with MFA enabled. Gained $100 AWS credit by completing Cloud Quest tasks. Successfully configured and tested AWS CLI locally, accessing basic AWS services via console and CLI. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/","title":"Worklog","tags":[],"description":"","content":"On this page, you will need to introduce your worklog. How did you complete it? How many weeks did you take to complete the program? What did you do in those weeks?\nTypically, and as a standard, a worklog is carried out over about 3 months (throughout the internship period) with weekly contents as follows:\nWeek 1: AWS Account and CLI Setup\nWeek 2: AWS Networking and Core Infrastructure\nWeek 3: DNS, Remote Access, CloudFormation and VPC Peering\nWeek 4: EC2 Advanced Features, S3 Static Web \u0026amp; CloudFront\nWeek 5: AWS Backup, VM Import/Export, S3 Lifecycle and ACLs\nWeek 6: Database RDS PostgreSQL, AWS Organizations \u0026amp; Storage Gateway\nWeek 7: Backend Deployment on EC2, EFS, and Multi-Region S3\nWeek 8: AWS Security, IAM, Cognito, KMS \u0026amp; Security Hub\nWeek 9: CI/CD Integration and Frontend Deployment\nWeek 10: Amazon SES Integration and S3 Storage Operations\nWeek 11: OTP Verification, Project Invitations and Technical Blogging\nWeek 12: System Workflow, AWS Cost Analysis and Project Completion\n"},{"uri":"https://nguyenankhang.rookwork.asia/3-blogsposted/3.2-blog2/","title":"","tags":[],"description":"","content":"Introduction to the AWS WAF Traffic Overview Dashboard Published Date: July 2, 2026\nHello everyone. Today, I want to share a highly useful update that makes monitoring web application security much easier: the AWS WAF Traffic Overview Dashboard.\nFor security and operations teams, maintaining application uptime requires continuous monitoring of baseline web traffic and rapid investigation of suspicious IPs. The main challenge is scaling application delivery without needing to inflate the size of your Security Operations Center (SOC) team. To address this pain point, AWS WAF introduced a built-in traffic overview dashboard that enables quick and accurate decision-making.\nWhat Makes This Dashboard Special? The best part is that it is completely free and available by default, requiring no additional setup.\nThe dashboard provides a near real-time view of CloudWatch metrics collected by AWS WAF. You can monitor:\nTotal requests, allowed vs. blocked requests. Bot vs. non-bot traffic comparisons. The top 10 active rules triggering blocks. A dedicated \u0026ldquo;Sampled Requests\u0026rdquo; tab, displaying the last 100 requests matching specific rules and 100 requests matching default actions within the last 3 hours. It categorizes requests with detailed analysis by attack type, device type, and country of origin. For example, if your app is designed only for desktop users in Vietnam but you see a sudden spike in mobile traffic from France, you can immediately identify the anomaly and take action.\nPractical Use Cases: Pattern Analysis and System Troubleshooting Beyond just visual appeal, this dashboard helps you hunt down traffic spikes and anomalous patterns. If your baseline is normally 2,000 requests/minute and it suddenly shoots up to 10,000 requests/minute with unexpected device headers, it\u0026rsquo;s a clear signal to investigate.\nIf a specific WAF rule is blocking a massive amount of traffic, the dashboard immediately highlights the vector, showing you exactly what exploit attempt is targeting your origin.\nNext Steps After Analysis:\nFine-tune WAF rules: Adjust regex rules to eliminate false positives or prevent bypasses. Enforce Rate Limiting: Apply rate-based rules to protect database-heavy endpoints. Facebook Post Link: AWS Study Group VN Original Article Link: Introducing the AWS WAF Traffic Overview Dashboard\u0026hellip; "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.7-route53-s3-cloudfront-ses/5.7.2-s3-static-hosting/","title":"Static Website Hosting with S3","tags":[],"description":"","content":"Amazon S3 is the ideal hosting solution for static frontend React assets due to its high durability, availability, and low cost.\nStep 1: Create an Amazon S3 Bucket Open the Amazon S3 service on the AWS Console. Click Create bucket. Configure settings: Bucket name: Use your domain name (e.g., rookwork.asia or www.rookwork.asia) for easy tracking. AWS Region: Select your preferred region (e.g., ap-southeast-1 Singapore). Block Public Access settings: Select Block all public access (We keep the bucket private and only allow access through CloudFront Origin Access Control to maximize security). Click Create bucket at the bottom. Step 2: Upload Frontend Assets to S3 Open the bucket you just created. Click Upload, then click Add folder or Add files. Select all folders and files inside your local build directory dist/ (after building your React project) and select them. (Ensure the index.html file is placed directly at the bucket root directory). Click Upload to complete the file upload process to S3. After uploading Frontend assets to S3, proceed to 5.7.3. Secure Delivery via Amazon CloudFront \u0026amp; ACM to configure HTTPS delivery and CDN.\n"},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.2-prerequiste/","title":"Prerequisite","tags":[],"description":"","content":"Before starting the AWS infrastructure deployment for the Rookwork project, ensure all of the following prerequisites are in place.\n1. AWS Account An active AWS account (AWS Free Tier or a learning account is acceptable). The account must have permissions to create: VPC, EC2, RDS, S3, SES, CloudFront, WAF, Route 53, IAM, ACM. 💡 It is recommended to use an IAM User rather than the Root Account for deployments. Create an IAM User with AdministratorAccess or a custom policy scoped to the required services.\n2. Required Tools Install the following tools on your local machine:\nTool Version Purpose Java JDK 17+ Build and run Spring Boot backend Maven 3.8+ Dependency management and backend build Node.js 18+ Build React 19 frontend Yarn 1.22+ Frontend package management Docker 24+ Package the application into containers AWS CLI v2 Interact with AWS from the command line Git 2.x Source code management Verify Installation Run the following commands to confirm each tool is installed correctly:\njava --version # Java 17+ mvn --version # Maven 3.8+ node --version # Node.js 18+ yarn --version # Yarn 1.22+ docker --version # Docker 24+ aws --version # AWS CLI 2.x git --version # Git 2.x 3. Configure AWS CLI Configure the AWS CLI with your IAM User credentials:\naws configure Enter the following when prompted:\nAWS Access Key ID — from IAM Console → Security credentials AWS Secret Access Key — from IAM Console → Security credentials Default region name — e.g., ap-southeast-1 (Singapore) Default output format — json Verify Connectivity aws sts get-caller-identity 4. IAM Permissions Attach the following IAM policy to your IAM User to grant sufficient permissions for deploying Rookwork infrastructure:\n{ \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Action\u0026#34;: [ \u0026#34;ec2:*\u0026#34;, \u0026#34;rds:*\u0026#34;, \u0026#34;s3:*\u0026#34;, \u0026#34;cloudfront:*\u0026#34;, \u0026#34;wafv2:*\u0026#34;, \u0026#34;route53:*\u0026#34;, \u0026#34;ses:*\u0026#34;, \u0026#34;acm:*\u0026#34;, \u0026#34;iam:CreateRole\u0026#34;, \u0026#34;iam:AttachRolePolicy\u0026#34;, \u0026#34;iam:PassRole\u0026#34;, \u0026#34;iam:GetRole\u0026#34;, \u0026#34;iam:CreateInstanceProfile\u0026#34;, \u0026#34;iam:AddRoleToInstanceProfile\u0026#34;, \u0026#34;elasticloadbalancing:*\u0026#34;, \u0026#34;autoscaling:*\u0026#34;, \u0026#34;ecr:*\u0026#34;, \u0026#34;logs:*\u0026#34;, \u0026#34;cloudwatch:*\u0026#34; ], \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; } ] } 5. Prepare Source Code Clone the Rookwork project source code to your local machine:\n# Backend (Spring Boot) git clone https://github.com/ChauThanhDat720/rookwork-backend.git # Frontend (React 19) git clone https://github.com/ChauThanhDat720/rookwork-frontend.git Test Backend Build cd rookwork-backend mvn clean package -DskipTests Test Frontend Run cd rookwork-frontend yarn install yarn build:browser yarn start:browser 6. Verify Docker Ensure Docker is running and can pull images:\ndocker info docker pull amazoncorretto:17 Once all prerequisites are complete, you are ready to begin deploying the AWS infrastructure for Rookwork. Proceed to 5.3 — Initialize VPC, NAT Gateway and Security Groups.\n"},{"uri":"https://nguyenankhang.rookwork.asia/2-proposal/","title":"Proposal","tags":[],"description":"","content":"Rookwork - Team Collaboration Management Software 1. Project Overview In the context of the Industry 4.0 revolution and the growing trend of remote working and hybrid work, effective team management has become a critical factor for individuals, project teams, and businesses alike. Rookwork is an integrated, modern team collaboration management software designed to operate as a multi-platform application (browser and desktop app). The system uses a Client-Server architecture with a frontend built using React 19, which can be packaged as a desktop application using Electron for a seamless experience, alongside a robust backend built on Spring Boot combined with AWS services.\nNote on current status: At this stage, the primary platform being used is the web browser version (runs directly in the browser, no installation required). The desktop version (packaged with Electron) has been developed but has not been fully synchronized with the latest web version, and may therefore be missing some features or patches compared to the current web release. The long-term goal of the project remains to complete and synchronize the multi-platform desktop application as originally planned.\n2. Problem Statement Many teams still face major challenges in collaboration and project management:\nScattered tools: Many teams still manage work manually through asynchronous channels such as Excel, Google Sheets, Messenger/Zalo, and email. This makes it difficult to track progress, leads to mistakes, lacks transparency, and wastes time on unnecessary communication. Complex usability: Existing project management platforms (such as Trello, Jira, Asana, Monday.com) often have complex interfaces and workflows with multiple layers of configuration, requiring users to spend time learning before they can use them effectively. This is especially challenging for small teams, students, or beginners who need a simple, intuitive tool that is accessible from the very first use. 3. Solution Architecture (Workflow) The system operates on a distributed model within the AWS Cloud environment. The processing flow is structured as follows:\n1. Networking \u0026amp; Content Delivery Flow:\nAll requests from users are resolved via Amazon Route 53 (DNS Resolution). The static Frontend interface is fully hosted on an Amazon S3 (FE Static) bucket. To accelerate page load times and enhance security, the frontend is distributed via Amazon CloudFront, coupled with the AWS WAF firewall to prevent web exploits. 2. Routing \u0026amp; Compute Backend Flow:\nAPI traffic passes through the Internet Gateway into the Amazon VPC, and is then load-balanced by the Application Load Balancer (ALB). The Java Spring Boot Backend is deployed on Amazon EC2 virtual machines, securely placed inside Private Subnets. For EC2 instances to communicate with the internet (e.g., calling external APIs), outbound traffic is routed through a NAT Gateway. 3. Database \u0026amp; Storage Flow:\nCore business data is stored on Amazon RDS (PostgreSQL), deployed in a Multi-AZ (DB Replication) model across multiple Availability Zones for disaster recovery. Database schema changes are managed via Flyway. Attachments are securely written to S3 by EC2 instances via an internal route using the VPC S3 Gateway Endpoint. Users can subsequently download files safely via Direct File Access or CloudFront. 4. Notifications \u0026amp; Shared Services Flow:\nEvents that trigger emails (such as team invitations) prompt EC2 to directly invoke Amazon SES to deliver emails to users. SSL/TLS certificates are centrally managed by AWS Certificate Manager (ACM), tightly integrated with system permissions governed by AWS IAM. 4. Technical Implementation Technical Requirements\nBackend: Java Spring Boot, Spring Security (JWT/OAuth2), Spring Data JPA. Database: PostgreSQL, Flyway (Database Migration). Frontend: ReactJS / TypeScript. AWS Services Utilized: Network \u0026amp; Security: Amazon Route 53, Amazon CloudFront, AWS WAF, Amazon VPC (IGW, NAT Gateway, ALB, S3 Gateway Endpoint), AWS ACM, AWS IAM. Compute \u0026amp; Storage: Amazon EC2, Amazon RDS (PostgreSQL Multi-AZ), Amazon S3 (FE Static \u0026amp; File Storage). Others: Amazon SES (Email Notification). 5. Implementation Roadmap Phase 1: Design AWS Cloud architecture, configure VPC, Subnets, Route 53, and IAM. Phase 2: Build the Spring Boot Backend and PostgreSQL database (RDS Multi-AZ). Phase 3: Deploy Backend onto EC2 with ALB, and configure NAT Gateway. Phase 4: Develop Frontend, upload to S3, and configure CloudFront + WAF. Phase 5: Integrate S3 Endpoint for file storage and Amazon SES for sending emails. Phase 6: End-to-end testing, security review, and system handover. 6. Operational Costs The Rookwork system is deployed on AWS following a High Availability architecture standard with three layers of security. The platform relies on core services including an EC2 cluster running the Spring Boot backend, an Amazon RDS PostgreSQL database, and Amazon S3 for hosting the React 19 frontend and static assets.\nIn the current phase, as the system primarily serves internal testing and pre-council acceptance review with limited traffic, the estimated total infrastructure cost is maintained at an optimal level of approximately $136 USD/month (equivalent to 3.48 million VND). This budget includes:\nA Multi-AZ redundancy setup for both the backend and database tiers. A NAT Gateway to enforce network security within Private Subnets. An S3 Gateway Endpoint that reduces internal bandwidth costs to zero. If further budget reduction is required during this evaluation phase, the project can flexibly switch to a Single-AZ configuration or implement scheduled auto start/stop scripts for non-business hours.\n7. Risk Assessment Risk Matrix\nVPC routing misconfigurations preventing EC2 from accessing the internet or DB: High impact, medium probability. AWS budget overruns due to NAT Gateway uptime or Multi-AZ configurations: Medium impact, high probability (for learning accounts). Mitigation Strategy\nConfigure infrastructure using Infrastructure as Code (IaC) for easier control and rollback. Set strict AWS Budgets and configure CloudWatch to monitor network traffic. Disable DB Replication (Multi-AZ) in Dev environments to save costs. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.2-week2/","title":"Week 2 Worklog","tags":[],"description":"","content":"Week 2 Objectives: Understand core AWS global infrastructure (Regions, AZs). Master VPC networking concepts: Subnets, Route Tables, Internet Gateways, and NAT Gateways. Launch an EC2 instance within a custom VPC subnet and establish access. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Learn about AWS Regions, Availability Zones, and VPC network isolation fundamentals. 04/27/2026 04/27/2026 https://000003.awsstudygroup.com/ 3 Study subnet planning (Public/Private subnets), Route Tables, and Internet Gateway (IGW) configurations. 04/28/2026 04/28/2026 https://000003.awsstudygroup.com/ 4 Understand NAT Gateway for private subnet internet access, and configure Security Groups and Network ACLs. 04/29/2026 04/29/2026 https://000003.awsstudygroup.com/ 5 Create a custom VPC with 2 public subnets and 2 private subnets, launch an EC2 instance in the public subnet. 04/30/2026 04/30/2026 https://000092.awsstudygroup.com/ 6 Verify network security rules, test internet connectivity, and establish SSH connection to the EC2 instance. 05/01/2026 05/01/2026 https://000004.awsstudygroup.com/ Week 2 Achievements: Acquired solid knowledge of AWS VPC and custom networking architecture. Successfully built a custom isolated VPC with public and private subnets. Launched and securely remoted into an EC2 instance running inside a custom public subnet. "},{"uri":"https://nguyenankhang.rookwork.asia/3-blogsposted/3.3-blog3/","title":"","tags":[],"description":"","content":"[SERVERLESS PATTERNS] Beyond Single-Purpose vs. Lambda-lith: The Benefits of Read-Write Separation (CQRS Prelude) Published Date: July 4, 2026\nI recently read a deep-dive analysis on the AWS Compute Blog by two Principal Solutions Architects regarding architectural patterns for Serverless Microservices. It addresses the exact pain points developers face when structuring AWS Lambda functions. Here is a summary of the technical insights and architectural tradeoffs.\nWhen designing RESTful APIs with AWS Lambda and Amazon API Gateway, the classic question is: How granular should my Lambda functions be?\nDevelopers typically find themselves caught between two extremes:\n1. Single Responsibility Lambda (One Function per Endpoint) Approach: Every HTTP route and method (GET /users, POST /users, DELETE /users/{id}) maps to a separate Lambda function. Pros: Isolated source code and very small deployment bundle size, which minimizes Cold Start times. Strict application of the Principle of Least Privilege (e.g., the GET function only needs dynamodb:GetItem permissions, while the POST function requires dynamodb:PutItem). Independent memory/timeout settings. Cons: High Infrastructure-as-Code (IaC) management overhead. You can easily hit the CloudFormation 500-resource limit. Infrequently used endpoints (like DELETE) suffer from frequent cold starts. 2. The Lambda-lith (All-in-One Function) Approach: All API routes for a service are packed into a single Lambda function, often using web framework adapters like aws-serverless-express or Spring Boot. Pros: Centralized codebase, easy sharing of entities/DTOs, and reusable database connection pools. Warm start rate is close to 100%. Cons: Bloated bundle size leading to longer cold starts, over-permissioned IAM roles, and shared resource limits. The Middle Ground: Read-Write Separation (CQRS Prelude) Instead of choosing between these extremes, a highly effective pattern is separating read and write workloads into two distinct Lambda functions:\nRead Lambda: Handles all queries (GET /items, GET /items/{id}). It can be optimized for high performance, memory-efficient data retrieval, and caching. Write Lambda: Handles all commands (POST, PUT, DELETE). It can be configured with higher timeouts, database transaction support, and specialized security permissions. This approach balances bundle sizes, simplifies IAM security configurations, reduces cold starts on read endpoints, and makes local database connection pooling more manageable.\nFacebook Post Link: AWS Study Group VN Original Article Link: Comparing design approaches for building serverless microservices\u0026hellip; "},{"uri":"https://nguyenankhang.rookwork.asia/3-blogsposted/","title":"Blogs Posted","tags":[],"description":"","content":"During my internship, I compiled and published several technical knowledge-sharing posts on cloud computing and AWS for the AWS Study Group VN community. Below is the list of published blogs:\nBlog 1 - Scaling Telco Automation with AAP and ROSA on AWS Published Date: June 30, 2026 An analysis of automating configuration and firmware updates for millions of telco edge devices (routers, gateways) by decoupling the Control Plane (Managed Ansible Automation Platform) and the Execution Plane (Red Hat OpenShift Service on AWS - ROSA).\nBlog 2 - Introduction to AWS WAF Traffic Overview Dashboard Published Date: July 2, 2026 An introduction to the built-in traffic analytics dashboard in AWS WAF. The post covers how security teams can monitor baseline traffic, identify bot vs. human requests, detect spikes, and tune security rules at the edge.\nBlog 3 - Serverless Patterns: Read-Write Separation (CQRS Prelude) Published Date: July 4, 2026 An architectural breakdown of the classic debate in serverless design: Single-Purpose Lambdas vs. the Lambda-lith. The post suggests a hybrid approach by separating read and write workloads into distinct Lambda functions for optimization.\n"},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.3-s3-vpc/","title":"Initialize VPC, NAT Gateway and Security Groups","tags":[],"description":"","content":"In this step, we will set up the entire network infrastructure for the Rookwork project, consisting of 3 main parts:\nCreate the VPC using the \u0026ldquo;VPC and more\u0026rdquo; feature Create the NAT Gateway for the Private Subnet to connect to the internet Create Security Groups in a layered model for the ALB and Backend Part 1 – Initialize the VPC Step 1: Access the VPC Service Log in to the AWS Management Console, making sure you are in the Asia Pacific (Singapore) ap-southeast-1 region. Search for VPC in the top search bar → select Your VPCs → click Create VPC. Step 2: Configure the VPC with \u0026ldquo;VPC and more\u0026rdquo; For Resources to create, select VPC and more (not \u0026ldquo;VPC only\u0026rdquo;). Enter the configuration parameters according to the table below: Parameter Value Name tag auto-generation rookwork IPv4 CIDR block 10.0.0.0/16 IPv6 CIDR block No IPv6 CIDR block Tenancy Default Number of Availability Zones 2 (ap-southeast-1a and ap-southeast-1b) Number of public subnets 2 Number of private subnets 2 NAT gateways None (to be created separately in Part 2) VPC endpoints S3 Gateway DNS hostnames Enable DNS resolution Enable The right side of the screen will display a Preview of the VPC diagram containing 4 Subnets across 2 AZs.\nNAT gateways: Select None (we will create this manually in Part 2). VPC endpoints: Select S3 Gateway to create a VPC Endpoint for connecting to S3 internally without going through the internet. Keep DNS options at default: Enable DNS hostnames and Enable DNS resolution. Click Create VPC to deploy.\nPart 1 Results The system automatically generates:\n1 VPC: rookwork-vpc — CIDR 10.0.0.0/16 4 Subnets: 2 Public + 2 Private across 2 AZs 1 Internet Gateway: rookwork-igw 3 Route Tables: 1 Public + 2 Private 1 VPC Endpoint: rookwork-vpce-s3 (S3 Gateway) [!TIP] After creation, go to Your VPCs → rookwork-vpc → Resource Map tab to verify that the entire network routing is configured correctly.\nPart 2 – Create the NAT Gateway The NAT Gateway allows resources in the Private Subnet (EC2 Backend) to download packages and updates from the internet without exposing their IP addresses.\nStep 1: Create the NAT Gateway On the left-hand menu under VPC, select NAT Gateways → Create NAT gateway. Enter the configuration parameters: Parameter Value Name rookwork-nat Availability mode Regional - new VPC rookwork-vpc Connectivity type Public Elastic IP allocation Automatic Step 2: Confirm Tags and Create Ensure the tag Name = rookwork-nat is filled in correctly. Click Create NAT gateway. Step 3: Check Status Make sure the State column shows ** Available** (green). If it is still Pending, wait 1–2 minutes and refresh the page. [!NOTE] NAT Gateways are billed per hour and per GB of data processed. Remember to delete this resource after completing the lab in step 5.6 – Resource Cleanup.\nPart 3 – Set Up Security Groups Security Groups act as virtual firewalls at the instance level. We create 3 Security Groups using a layered security model:\nrookwork-alb-sg: Opens HTTP/HTTPS ports from the internet → receives user requests. backend-sg: Only accepts traffic from rookwork-alb-sg → backend has no direct internet exposure. rds-ec2-1: Only accepts PostgreSQL connections (port 5432) from ec2-rds-1 → RDS is completely isolated from the internet. Step 1: Create Security Group for ALB (rookwork-alb-sg) VPC Left-hand menu → Security Groups → Create security group. Field Value Security group name rookwork-alb-sg Description Security group for Application Load Balancer VPC rookwork-vpc Inbound rules:\nType Protocol Port Source HTTPS TCP 443 0.0.0.0/0 HTTP TCP 80 0.0.0.0/0 Outbound rules: Keep default (All traffic). Click Create security group.\nStep 2: Create Security Group for Backend (backend-sg) Click Create security group again. Field Value Security group name backend-sg Description Security group for Backend EC2 instances VPC rookwork-vpc Inbound rules: Leave empty (to be added in Step 3).\nOutbound rules: Keep default. Click Create security group.\nStep 3: Add Inbound Rules to backend-sg Once rookwork-alb-sg has been created and has a Security Group ID, return to edit backend-sg → Inbound rules → Edit inbound rules:\nType Protocol Port Source Custom TCP TCP 8080 rookwork-alb-sg (select SG ID) HTTP TCP 80 rookwork-alb-sg (select SG ID) [!IMPORTANT] For the Source, select Custom and enter the name or ID of rookwork-alb-sg instead of entering a CIDR IP. This ensures the Backend only accepts traffic from the Load Balancer, never directly from the internet.\nClick Save rules.\nStep 4: Create Security Group for RDS (rds-ec2-1) To protect the database, we create a dedicated Security Group that only allows connections from the EC2 Backend on the PostgreSQL port.\nClick Create security group once more. Field Value Security group name rds-ec2-1 Description Security group for RDS PostgreSQL VPC rookwork-vpc Inbound rules — Add 2 rules:\nType Protocol Port Source PostgreSQL TCP 5432 ec2-rds-1 (EC2 Security Group ID) PostgreSQL TCP 5432 backend-sg (Security Group ID) [!IMPORTANT] For the Source, select Custom and type the Security Group ID of ec2-rds-1 or backend-sg. This ensures the RDS only accepts database connections from the EC2 Backend and is never exposed directly to the internet.\nClick Save rules.\nSummary After completing all 3 parts, the Rookwork network infrastructure is ready:\nResource Name Status VPC rookwork-vpc Available Public Subnets rookwork-subnet-public1/2-... Available Private Subnets rookwork-subnet-private1/2-... Available Internet Gateway rookwork-igw Attached NAT Gateway rookwork-nat Available VPC Endpoint rookwork-vpce-s3 Available Security Group ALB rookwork-alb-sg Created Security Group Backend backend-sg Created Security Group RDS rds-ec2-1 Created [!TIP] Defense-in-Depth security model: ALB → Backend → RDS. Each layer only accepts incoming traffic from the preceding layer, ensuring the database is completely isolated from the internet.\n"},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.7-route53-s3-cloudfront-ses/5.7.3-cloudfront-acm/","title":"Secure Delivery via Amazon CloudFront &amp; ACM","tags":[],"description":"","content":"To enable secure HTTPS delivery for the website and optimize page loading globally, configure AWS Certificate Manager (ACM) combined with CloudFront.\nStep 1: Request SSL/TLS Certificate via ACM Search for Certificate Manager on the AWS Console. (Important) Switch region to us-east-1 (N. Virginia) (CloudFront requires SSL/TLS certificates to be provisioned in this region to be used). Click Request certificate, select Request a public certificate, and click Next. In the configuration: Fully qualified domain name: Enter your domain name (e.g., rookwork.asia and add an additional wildcard domain *.rookwork.asia). Validation method: Choose DNS validation. Click Request. The initial status will be Pending validation. Click the Certificate ID, and click Create records in Route 53 to automatically generate DNS validation records in Route 53. Wait a few minutes for the status to change to Issued. Step 2: Create a CloudFront Distribution Search for CloudFront on the AWS Console. Click Create distribution. In the configuration: Origin domain: Select your S3 bucket. Origin access: Select Origin access control settings (OAC) (recommended). Click Create control setting, leave default settings, and save. Viewer protocol policy: Select Redirect HTTP to HTTPS. Alternate domain name (CNAME): Add your domain names (e.g., rookwork.asia and www.rookwork.asia). Custom SSL certificate: Select the ACM certificate generated in Step 1. Default root object: Enter index.html. Click Create distribution. Copy the suggested Bucket Policy JSON code from the CloudFront console, and paste it into the Permissions -\u0026gt; Bucket Policy tab of your S3 Bucket to grant CloudFront access to S3 files. Step 3: Create DNS Record in Route 53 Pointing to CloudFront Return to the Route 53 service and open the Hosted Zone for your domain. Click Create record. Configure the record: Record name: Leave blank (for the apex domain rookwork.asia). Record type: Choose A - Routes traffic to an IPv4 address and some AWS resources. Alias: Enable (toggle switch to the right). Route traffic to: Choose Alias to CloudFront distribution -\u0026gt; Select the CloudFront distribution you created. Click Create records. You can now access your website securely using HTTPS through your custom domain name!\nOnce the static website is live and secure via HTTPS, proceed to 5.7.4. Private File Storage with S3 to configure private storage for the Backend application.\n"},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.3-week3/","title":"Week 3 Worklog","tags":[],"description":"","content":"Week 3 Objectives: Learn DNS principles and configure Amazon Route 53 domain hosting. Set up a Hybrid DNS configuration and deploy a Remote Desktop Gateway (RDGW). Understand AWS CloudFormation basics and VPC Peering concepts. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Learn about DNS servers, hosted zones, and Route 53 routing policies. 05/04/2026 05/04/2026 https://000010.awsstudygroup.com/ 3 Design and configure a Hybrid DNS resolving architecture using Route 53 Resolvers and create Security Groups. 05/05/2026 05/05/2026 https://000010.awsstudygroup.com/ 4 Deploy and configure a Remote Desktop Gateway (RDGW) to securely access Windows instances in a private subnet. 05/06/2026 05/06/2026 https://000093.awsstudygroup.com/ 5 Study AWS CloudFormation templates and write a basic YAML configuration to provision Security Groups and EC2. 05/07/2026 05/07/2026 https://000037.awsstudygroup.com/ 6 Establish a VPC Peering connection between two VPCs, updating Route Tables and Network ACLs accordingly. 05/08/2026 05/08/2026 https://000019.awsstudygroup.com/ Week 3 Achievements: Configured Route 53 for custom domain resolution and deployed a Hybrid DNS Resolver. Secured administrative access to internal VPC instances using RDGW. Automated infrastructure with CloudFormation and bridged two independent networks using VPC Peering. "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.4-create-ec2-private-env/","title":"Create EC2 &amp; Verify Private Environment","tags":[],"description":"","content":"Overview In this workshop, you will learn how to deploy EC2 instances securely inside private subnets within an Amazon VPC. We will set up two EC2 instances named rookwork-ec2-1 and rookwork-ec2-2 within the private subnets of your custom VPC. You will configure their network settings to ensure they remain isolated from direct public internet access, and verify the environment configuration (local IP, internet route via NAT Gateway, and installation of key dependencies such as Docker, Node.js, and Git).\nStep 1: Launch rookwork-ec2-1 Open the AWS Management Console and navigate to the EC2 Dashboard. Click on Launch instances. Under Name and tags, enter rookwork-ec2-1 in the Name field. Under Application and OS Images (Amazon Machine Image), select Amazon Linux 2023 AMI (or the AMI required for your project). Step 2: Configure Network Settings Scroll down to the Network settings section and click Edit (top-right of the box). VPC: Select your custom VPC (e.g., Rookwork-VPC). Subnet: Select a Private Subnet (e.g., rookwork-private-subnet-1). Auto-assign public IP: Select Disable (this guarantees the instance does not receive a public IP address and remains private). Firewall (security groups): Select or create a security group configured to allow inbound traffic only from the Bastion host, Application Load Balancer, or specific internal VPC ranges. Step 3: Key Pair and Storage Under Key pair (login), select your existing key pair or create a new one to securely connect to the instance later. Under Configure storage, verify the size and type of the root volume (e.g., gp3). Click Launch instance on the right panel to provision the instance. Step 4: Launch rookwork-ec2-2 Follow the same procedure as above to launch the second EC2 instance. In the Name field, enter rookwork-ec2-2. In Network settings, choose the same VPC but select the second Private Subnet (e.g., rookwork-private-subnet-2) for high availability across different Availability Zones. Keep Auto-assign public IP as Disable. Assign the same security group or a corresponding private security group. Launch the instance. Step 5: Connect and Verify the Private Environment Since both EC2 instances are in private subnets, they do not have public IP addresses and cannot be accessed directly via SSH from the public internet. We will connect to the instance using AWS Systems Manager (SSM) Session Manager.\nIn the EC2 instances list, select the instance you want to connect to (e.g., rookwork-ec2-2) and click the Connect button at the top right. Switch to the Session Manager tab and click the orange Connect button at the bottom right to establish a terminal session. Step 6: Verify Configurations and Environment Once the terminal session is successfully established, execute the following verifications:\n1. Verify Internet Connectivity (via NAT Gateway) To ensure the route table for private subnets redirects outbound traffic to a NAT Gateway (enabling packages to be updated and library downloads):\nping -c 3 google.com 2. Verify Installed Software / Dependencies Run version check commands to ensure the required runtimes and tools for the Rookwork application are installed and ready:\nDocker:\ndocker --version If not installed, run the following commands to install:\nsudo dnf update -y sudo dnf install -y docker sudo systemctl start docker sudo systemctl enable docker sudo usermod -aG docker $USER Node.js:\nnode --version If not installed, run the following commands to install via NVM:\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install 20 Git:\ngit --version If not installed, run the following command to install:\nsudo dnf install -y git "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.7-route53-s3-cloudfront-ses/5.7.4-s3-storage/","title":"Private File Storage with S3","tags":[],"description":"","content":"Apart from hosting the React Frontend application statically, the Rookwork project requires a secure, private cloud storage solution to store project-related document attachments, user-uploaded files, and profile avatars.\nWe use Amazon S3 combined with Presigned URLs to ensure all user files are stored securely.\nStep 1: Create a Private Amazon S3 Bucket Navigate to the Amazon S3 service on the AWS Management Console. Click Create bucket. Configure settings: Bucket name: Enter a globally unique name (e.g., rookwork-attachments-bucket). AWS Region: Select the same region where your EC2 and RDS instances reside (e.g., ap-southeast-1 Singapore). Block Public Access settings: Check Block all public access (It is mandatory to block all public access to prevent project attachments and member avatars from being leaked to the public internet). Keep the remaining settings at default and click Create bucket. Step 2: Configure Spring Boot Backend In the Spring Boot backend source code (rookwork-backend-sb), load Spring Cloud AWS S3 configurations using system environment variables (inside the .env file or set as environment variables on the production EC2 server):\n# AWS S3 Production Configuration spring.cloud.aws.s3.enabled=true spring.cloud.aws.region.static=${AWS_REGION:ap-southeast-1} spring.cloud.aws.credentials.access-key=${AWS_S3_ACCESS_KEY_ID} spring.cloud.aws.credentials.secret-key=${AWS_S3_SECRET_ACCESS_KEY} aws.s3.bucket-name=${AWS_S3_BUCKET:rookwork-attachments-bucket} Step 3: Implement S3 Service in Java using AWS SDK v2 In the Rookwork backend application (rookwork-backend-sb), we utilize the S3Template class (from the Spring Cloud AWS library) to upload and delete files, alongside the S3Presigner class to generate temporary pre-signed URLs (valid for 15 minutes) for secure access and download of private objects:\npackage com.example.rookwork_backend_sb.services; import io.awspring.cloud.s3.S3Template; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; import java.io.IOException; import java.io.InputStream; import java.time.Duration; import java.util.UUID; @Service @RequiredArgsConstructor public class S3Service { private final S3Template s3Template; private final S3Presigner s3Presigner; @Value(\u0026#34;${aws.s3.bucket-name}\u0026#34;) private String bucketName; /** * Uploads a file to AWS S3 and returns the generated stored name. */ public String uploadFile(MultipartFile file, UUID projectId, UUID issueId) throws IOException { String fileExtension = getFileExtension(file.getOriginalFilename()); // Generate random unique name String fileUuid = UUID.randomUUID().toString(); // Construct directory structure key: projects/{projectId}/issues/{issueId}/{uuid}{ext} String storedName = String.format(\u0026#34;projects/%s/issues/%s/%s%s\u0026#34;, projectId, issueId, fileUuid, fileExtension); try (InputStream inputStream = file.getInputStream()) { s3Template.upload(bucketName, storedName, inputStream); } return storedName; } /** * Deletes a file from AWS S3. */ public void deleteFile(String storedName) { s3Template.deleteObject(bucketName, storedName); } /** * Generates a temporary Presigned URL for viewing/downloading files. * Valid for 15 minutes. */ public String generatePresignedUrl(String storedName) { if (storedName == null || storedName.isEmpty()) { return null; } GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(storedName) .build(); GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(15)) .getObjectRequest(getObjectRequest) .build(); PresignedGetObjectRequest presignedGetObjectRequest = s3Presigner.presignGetObject(getObjectPresignRequest); return presignedGetObjectRequest.url().toString(); } /** * Uploads a user avatar to S3 under the \u0026#34;avatar\u0026#34; directory. */ public String uploadAvatar(MultipartFile file, UUID userId) throws IOException { String fileExtension = getFileExtension(file.getOriginalFilename()); // Key format: avatar/{userId}/{fileUuid}{ext} String fileUuid = UUID.randomUUID().toString(); String storedName = String.format(\u0026#34;avatar/%s/%s%s\u0026#34;, userId.toString(), fileUuid, fileExtension); try (InputStream inputStream = file.getInputStream()) { s3Template.upload(bucketName, storedName, inputStream); } return storedName; } /** * Helper to get presigned URL for avatar if it is stored on S3. * If not stored on S3 (e.g. Google URL or null), returns the original value. */ public String getAvatarUrl(String picture) { if (picture != null \u0026amp;\u0026amp; picture.startsWith(\u0026#34;avatar/\u0026#34;)) { return generatePresignedUrl(picture); } return picture; } private String getFileExtension(String filename) { if (filename != null \u0026amp;\u0026amp; filename.contains(\u0026#34;.\u0026#34;)) { return filename.substring(filename.lastIndexOf(\u0026#34;.\u0026#34;)); } return \u0026#34;\u0026#34;; } } After configuring private file storage, proceed to 5.7.5. Email Integration with Amazon SES to set up the email notifications and OTP service.\n"},{"uri":"https://nguyenankhang.rookwork.asia/4-eventparticipated/","title":"Events Participated","tags":[],"description":"","content":"During my internship, I participated in the AWS Community Day 2026 event. It was a memorable experience that provided valuable insights and inspiration regarding modern technology trends.\nEvent: Community Day 23/5 Event Name: AWS Community Day 2026\nDate \u0026amp; Time: May 23, 2026\nLocation: Ho Chi Minh City\nRole: Attendee\n"},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.4-week4/","title":"Week 4 Worklog","tags":[],"description":"","content":"Week 4 Objectives: Deep dive into EC2 advanced features (Auto Scaling, Elastic Load Balancing, EBS). Create Amazon S3 storage bucket and configure Static Website Hosting. Integrate CloudFront CDN and establish AWS Storage Gateway File Shares. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Study EC2 features: EBS volume types, instance sizing, ELB, and Auto Scaling scaling policies. 05/11/2026 05/11/2026 https://000006.awsstudygroup.com/ 3 Write an automated CloudFormation template to deploy an S3 Bucket and EC2 instance environment. 05/12/2026 05/12/2026 https://000037.awsstudygroup.com/ 4 Deploy AWS Storage Gateway on EC2 to configure File Shares mapped directly to an S3 bucket. 05/13/2026 05/13/2026 https://000024.awsstudygroup.com/ 5 Configure Static Website Hosting on S3 and distribute content through Amazon CloudFront CDN. 05/14/2026 05/14/2026 https://000057.awsstudygroup.com/ 6 Verify website availability via CloudFront URL, check cache behaviors, and ensure SSL/HTTPS delivery. 05/15/2026 05/15/2026 https://000094.awsstudygroup.com/ Week 4 Achievements: Mastered provisioning S3 and EC2 components using Infrastructure as Code (CloudFormation). Hosted a responsive static web application on S3, distributed globally via CloudFront with low latency. Bridged system storage to the cloud via AWS Storage Gateway File Shares. "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.5-create-rds/","title":"Create RDS Database","tags":[],"description":"","content":"In this section, you will launch an Amazon RDS PostgreSQL database instance, connecting it directly with the EC2 compute instance in the VPC private subnets to store data for the Rookwork project.\nBefore starting, make sure that you have created the necessary Security Groups. See the detailed instructions in Part 3 – Create Security Groups (Step 1) of article 5.3.\nStep 1: Launch Amazon RDS PostgreSQL Once the network and EC2 instance are ready, start creating the relational database instance:\nSearch for and navigate to the RDS service on the AWS Management Console. Click Databases on the left menu, then click Create database. Under Engine options, select PostgreSQL. Under Choose a database creation method, select Easy create to use recommended best-practice default configurations. Under DB instance size options, select Free tier to run a cost-efficient setup (db.t4g.micro, 2 vCPUs, 1 GiB RAM, 20 GiB Storage). DB instance identifier: Enter a unique name for your database (e.g., rookwork-db). Master username: Default is postgres. Credentials management: Choose Self managed to define and manage your master user password. Under the Set up EC2 connection - optional section: Select Connect to an EC2 compute resource. Under the EC2 instance dropdown, select your application server (e.g., rookwork-ec2-1 / i-035c5645906cef43f). Note: This option allows Amazon RDS to automatically create and assign appropriate security groups (rds-ec2-X for the database and ec2-rds-X for the EC2 instance). This automatically permits secure traffic from your EC2 instance to the RDS Database port without requiring manual routing rules. Click Create database at the bottom to start provisioning. The process will take a few minutes until the database status changes to Available. Step 2: Configure Spring Boot to Point to RDS To enable the Spring Boot application running on the EC2 instance to connect to the Amazon RDS PostgreSQL database, update the project configuration file:\nOpen the configuration file src/main/resources/application.properties (or application.yml) in your project source code. Add or update the database connection properties as follows: spring.datasource.url=jdbc:postgresql://rookwork-db.cxegees2u15z.ap-southeast-1.rds.amazonaws.com:5432/postgres spring.datasource.username=postgres spring.datasource.password=your_password_here spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect spring.jpa.show-sql=true Note: The configurations above are temporary settings for checking local connectivity. Later, we will optimize this configuration by utilizing environment variables in the CI/CD pipeline to secure sensitive connection credentials.\nStep 3: Verify the Connection from EC2 to RDS PostgreSQL Once the RDS database status changes to Available, execute the following steps from the EC2 instance to verify the connection:\nConnect to the EC2 instance (using SSM Session Manager as described in Step 5 of the previous section). Install the psql (PostgreSQL Client) utility on the EC2 instance: sudo dnf install -y postgresql15 Connect to the RDS PostgreSQL database using the following command: psql -h \u0026lt;RDS_ENDPOINT\u0026gt; -U postgres -d postgres (Replace \u0026lt;RDS_ENDPOINT\u0026gt; with the actual RDS instance Endpoint found on the AWS RDS Console details page) Enter the master user password configured in Step 2. When the command prompt switches to postgres=\u0026gt;, it proves that the EC2 instance has successfully connected to the RDS PostgreSQL database through the VPC internal network. Note: The image above illustrates a successful terminal session connection. This test and installation ensure that your application running on EC2 can successfully communicate with and securely store data in the RDS PostgreSQL database.\n"},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/","title":"Workshop","tags":[],"description":"","content":"This page summarizes the practical workshops conducted during the internship.\nContent 5.1. Introduction - Overview of system architecture and key processing flows of the project. 5.2. Prerequisite - Prerequisites and required tools to deploy the AWS infrastructure. 5.3. Initialize VPC, NAT Gateway and Security Groups - Guide on setting up the basic network infrastructure including VPC, NAT Gateway, S3 VPC Endpoint, and layered Security Groups. 5.4. Create EC2 \u0026amp; Verify Private Environment - Guide on launching EC2 instances in a private subnet, configuring network settings, and verifying connection and the internal network environment. 5.5. Create RDS Database - Guide on launching an Amazon RDS PostgreSQL database connected to EC2 and configuring Spring Boot. 5.6. Deploy Backend CI/CD with GitHub Actions - Guide on building an automated CI/CD pipeline using GitHub Actions to deploy Spring Boot to EC2. 5.7. AWS Services Integration - Guide on configuring AWS Route 53, static frontend hosting with S3 and CloudFront, private S3 Storage, and SES email notifications. 5.8. Deploy Frontend CI/CD with GitHub Actions - Guide on building an automated CI/CD pipeline using GitHub Actions for React Frontend. "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.7-route53-s3-cloudfront-ses/5.7.5-ses/","title":"Email Integration with Amazon SES","tags":[],"description":"","content":"Amazon SES is a high-performance, cost-effective cloud email service optimized for sending transactional emails in the Rookwork project.\nStep 1: Verify Domain Identity on Amazon SES Search for Amazon Simple Email Service (SES) on the AWS Console. Under the Configuration menu, click Identities, then click Create identity. Select Domain (Recommended when you own a custom domain): Domain: Enter your custom domain name (e.g., rookwork.asia). Easy DKIM: Enable and leave default settings to authenticate your identity reliably. Click Create identity. The system provides CNAME records for DKIM setup. Click Create records in Route 53 to automatically add these DNS records to your Hosted Zone. (Note) By default, new SES accounts are placed in the Sandbox environment. You must verify a separate Email address identity (such as your personal email) to act as a recipient for testing emails during development. Step 2: Create SMTP Credentials for Spring Boot On the left menu of SES, select SMTP settings. Click Create SMTP credentials. Name your IAM user and click Create. Copy and store the generated SMTP Username and SMTP Password securely. Step 3: Configure Spring Boot Backend for Email Delivery In the Rookwork backend application (rookwork-backend-sb), configure secure SMTP connection parameters using system environment variables (.env file):\nspring.mail.host=email-smtp.ap-southeast-1.amazonaws.com spring.mail.port=587 spring.mail.username=${SMTP_USERNAME} spring.mail.password=${SMTP_PASSWORD} spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true Use the JavaMailSender class to write an email service to deliver verification OTPs for registration, password recovery, and invitations to join collaborative workspaces.\nAfter completing all AWS Core services integration, proceed to 5.8. Deploy Frontend CI/CD with GitHub Actions to complete the frontend deployment automation.\n"},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.5-week5/","title":"Week 5 Worklog","tags":[],"description":"","content":"Week 5 Objectives: Configure S3 Lifecycle Rules and AWS Backup Plans. Learn on-premises virtualization using VMware Workstation and VM export procedures. Import VM to AWS, launch EC2 from imported AMI, and configure S3 Access Control Lists (ACLs). Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Configure S3 Bucket Lifecycle Rules (transition to Glacier) and set up an AWS Backup Plan with notifications. 05/18/2026 05/18/2026 https://000013.awsstudygroup.com/ 3 Perform backup restore tests to verify data recovery capability of EBS volumes. 05/19/2026 05/19/2026 https://000088.awsstudygroup.com/ 4 Install VMware Workstation, manage a local VM environment, and export the VM to OVF/OVA format. 05/20/2026 05/20/2026 https://000014.awsstudygroup.com/ 5 Upload the exported VM file to S3 and execute VM Import/Export CLI to convert it into a custom AMI. 05/21/2026 05/21/2026 https://000014.awsstudygroup.com/ 6 Deploy an EC2 instance from the imported AMI and configure granular access controls using S3 ACLs. 05/22/2026 05/22/2026 https://000069.awsstudygroup.com/ Week 5 Achievements: Implemented automated data lifecycle and recovery strategies on AWS. Migrated a local VM to AWS using VM Import/Export CLI. Successfully launched a functioning EC2 instance from an imported on-premises VM template. "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.6-backend-cicd/","title":"Deploy Backend CI/CD with GitHub Actions","tags":[],"description":"","content":"In this step, we will build an automated CI/CD pipeline using GitHub Actions to automatically package our Spring Boot application and deploy it sequentially to two EC2 instances running Docker. The deployment process utilizes AWS Systems Manager (SSM) and Amazon S3 as intermediaries.\n1. Configure GitHub Repository Secrets To ensure the security of sensitive information (such as AWS credentials, database URLs, passwords, etc.), we store these values in the GitHub Repository Secrets. These variables will be referenced directly in the pipeline YAML file without exposing them in the source code.\nGo to Settings → Secrets and variables → Actions → New repository secret on your GitHub repository and configure the following variables:\nDetails of Required Secrets: AWS \u0026amp; S3 Access Variables: AWS_ACCESS_KEY_ID \u0026amp; AWS_SECRET_ACCESS_KEY: AWS IAM credentials for the CI/CD account to upload JAR files to S3 and send run commands to SSM. S3_BUCKET: The name of the S3 Bucket acting as the intermediate storage for build .jar files. EC2 Instance ID Variables: EC2_INSTANCE_ID_1 \u0026amp; EC2_INSTANCE_ID_2: The IDs of the two EC2 instances running the backend application in the Private Subnet. Database Connection Variables (RDS): DB_URL: The JDBC connection string to the RDS PostgreSQL database. DB_USERNAME \u0026amp; DB_PASSWORD: Database login credentials. Application Configuration Variables (Rookwork): JWT_SECRET: The encryption key used to sign JSON Web Tokens (JWT) for authentication. GOOGLE_CLIENT_ID: The Client ID for Google OAuth2 authentication. AWS_S3_ACCESS_KEY_ID \u0026amp; AWS_S3_SECRET_ACCESS_KEY \u0026amp; AWS_S3_BUCKET: Separate S3 configurations for user upload storage within the application. APP_EMAIL_FROM: The sender email address used by the system for sending notifications. 2. Pipeline Workflow (.github/workflows/deploy.yml) The automation process is defined through the following main steps in the deploy job:\nStep 1: Prepare Source Code and Build JAR Checkout code: Pulls the latest source code from the GitHub repository branch. Set up JDK 21: Installs and configures Java 21 environment (Temurin distribution). Build JAR: Runs ./mvnw clean package -DskipTests to compile the source code and package it into a .jar file (skipping test execution to optimize build time). Step 2: Upload Build Artifact to Amazon S3 Configure AWS credentials: Configures AWS authentication credentials. Set version tag: Determines the version tag. If triggered by Git tags (matching v*), the tag name is used; otherwise, it defaults to latest. Copy JAR to S3: Uploads the compiled .jar file to the S3 Bucket using the AWS CLI: aws s3 cp target/*.jar s3://${{ secrets.S3_BUCKET }}/rookwork-backend-${{ steps.version.outputs.VERSION }}.jar Step 3: Deploy Sequentially to EC2 Instances via AWS SSM The CI/CD pipeline deploys to EC2-1 first, verifies that it runs successfully, and then proceeds to deploy to EC2-2. The workflow on each EC2 instance consists of:\nGenerate Environment Parameters: Uses jq to dynamically generate an ssm-params-ec2.json file containing the environment variables retrieved from GitHub Secrets. Send SSM Run Command: Sends an AWS-RunShellScript command to the target server: aws ssm send-command \\ --instance-ids \u0026#34;${{ secrets.EC2_INSTANCE_ID_1 }}\u0026#34; \\ --document-name \u0026#34;AWS-RunShellScript\u0026#34; \\ --parameters file://ssm-params-ec2-1.json Execution Commands on the EC2 Server: Downloads the .jar file from S3 to the server. Builds a new Docker Image without cache to apply the latest code: sudo docker build --no-cache -t rookwork-backend:[VERSION] . Stops and removes the existing backend container. Launches a new Docker container running on port 8080, passing all the configuration parameters for the database, JWT, and S3 storage. Monitor Deployment Status (Polling): The pipeline continuously checks the execution status of the SSM command every 15 seconds (up to 40 times ~ 10 minutes). If the status returns Success, it proceeds to EC2-2. If it fails (Failed, Cancelled, TimedOut), the pipeline prints the error logs and exits immediately. 3. Pipeline Configuration Code Below is the complete configuration code for the .github/workflows/deploy.yml file:\nname: Deploy to EC2 on: push: branches: [main] tags: - \u0026#34;v*\u0026#34; jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up JDK 21 uses: actions/setup-java@v3 with: java-version: \u0026#34;21\u0026#34; distribution: \u0026#34;temurin\u0026#34; - name: Build JAR run: ./mvnw clean package -DskipTests - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-southeast-1 - name: Set version tag id: version run: | if [[ \u0026#34;${{ github.ref }}\u0026#34; == refs/tags/* ]]; then echo \u0026#34;VERSION=${{ github.ref_name }}\u0026#34; \u0026gt;\u0026gt; $GITHUB_OUTPUT else echo \u0026#34;VERSION=latest\u0026#34; \u0026gt;\u0026gt; $GITHUB_OUTPUT fi - name: Copy JAR to S3 run: | aws s3 cp target/*.jar s3://${{ secrets.S3_BUCKET }}/rookwork-backend-${{ steps.version.outputs.VERSION }}.jar # ── Deploy EC2-1 first, wait for completion ───────────────────────────────── - name: Deploy on EC2-1 via SSM run: | set -euo pipefail jq -n \\ --arg version \u0026#34;${{ steps.version.outputs.VERSION }}\u0026#34; \\ --arg s3_bucket \u0026#34;${{ secrets.S3_BUCKET }}\u0026#34; \\ --arg db_url \u0026#34;${{ secrets.DB_URL }}\u0026#34; \\ --arg db_user \u0026#34;${{ secrets.DB_USERNAME }}\u0026#34; \\ --arg db_pass \u0026#34;${{ secrets.DB_PASSWORD }}\u0026#34; \\ --arg jwt_secret \u0026#34;${{ secrets.JWT_SECRET }}\u0026#34; \\ --arg google_id \u0026#34;${{ secrets.GOOGLE_CLIENT_ID }}\u0026#34; \\ --arg aws_key \u0026#34;${{ secrets.AWS_S3_ACCESS_KEY_ID }}\u0026#34; \\ --arg aws_secret \u0026#34;${{ secrets.AWS_S3_SECRET_ACCESS_KEY }}\u0026#34; \\ --arg aws_bucket \u0026#34;${{ secrets.AWS_S3_BUCKET }}\u0026#34; \\ --arg email_from \u0026#34;${{ secrets.APP_EMAIL_FROM }}\u0026#34; \\ \u0026#39; [ if $db_url != \u0026#34;\u0026#34; then \u0026#34;-e DB_URL=\u0026#34; + ($db_url | @sh) else empty end, if $db_user != \u0026#34;\u0026#34; then \u0026#34;-e DB_USERNAME=\u0026#34; + ($db_user | @sh) else empty end, if $db_pass != \u0026#34;\u0026#34; then \u0026#34;-e DB_PASSWORD=\u0026#34; + ($db_pass | @sh) else empty end, if $jwt_secret != \u0026#34;\u0026#34; then \u0026#34;-e JWT_SECRET=\u0026#34; + ($jwt_secret | @sh) else empty end, if $google_id != \u0026#34;\u0026#34; then \u0026#34;-e GOOGLE_CLIENT_ID=\u0026#34; + ($google_id | @sh) else empty end, if $aws_key != \u0026#34;\u0026#34; then \u0026#34;-e AWS_S3_ACCESS_KEY_ID=\u0026#34; + ($aws_key | @sh) else empty end, if $aws_secret != \u0026#34;\u0026#34; then \u0026#34;-e AWS_S3_SECRET_ACCESS_KEY=\u0026#34; + ($aws_secret | @sh) else empty end, if $aws_bucket != \u0026#34;\u0026#34; then \u0026#34;-e AWS_S3_BUCKET=\u0026#34; + ($aws_bucket | @sh) else empty end, if $email_from != \u0026#34;\u0026#34; then \u0026#34;-e APP_EMAIL_FROM=\u0026#34; + ($email_from | @sh) else empty end ] | join(\u0026#34; \u0026#34;) as $env_flags | (\u0026#34;aws s3 cp s3://\u0026#34; + $s3_bucket + \u0026#34;/rookwork-backend-\u0026#34; + $version + \u0026#34;.jar /home/ec2-user/rookwork-backend-sb/rookwork-backend.jar --no-progress \u0026amp;\u0026amp; cd /home/ec2-user/rookwork-backend-sb \u0026amp;\u0026amp; sudo docker build --no-cache -t rookwork-backend:\u0026#34; + $version + \u0026#34; . \u0026amp;\u0026amp; { sudo docker rm -f rookwork-backend 2\u0026gt;/dev/null; sudo docker run -d --restart always --name rookwork-backend -p 8080:8080 \u0026#34; + $env_flags + \u0026#34; -e JWT_EXPIRATION=604800000 -e JWT_REFRESH_EXPIRATION=2592000000 -e AWS_REGION=ap-southeast-1 rookwork-backend:\u0026#34; + $version + \u0026#34;; }\u0026#34;) as $cmd | { \u0026#34;commands\u0026#34;: [$cmd] } \u0026#39; \u0026gt; ssm-params-ec2-1.json COMMAND_ID=$(aws ssm send-command \\ --instance-ids \u0026#34;${{ secrets.EC2_INSTANCE_ID_1 }}\u0026#34; \\ --document-name \u0026#34;AWS-RunShellScript\u0026#34; \\ --region ap-southeast-1 \\ --parameters file://ssm-params-ec2-1.json \\ --query \u0026#34;Command.CommandId\u0026#34; \\ --output text) echo \u0026#34;EC2-1 SSM Command ID: $COMMAND_ID\u0026#34; # Polling up to 40 times x 15s = 10 minutes (sufficient for docker build) for i in $(seq 1 40); do STATUS=$(aws ssm get-command-invocation \\ --command-id \u0026#34;$COMMAND_ID\u0026#34; \\ --instance-id \u0026#34;${{ secrets.EC2_INSTANCE_ID_1 }}\u0026#34; \\ --query \u0026#34;Status\u0026#34; --output text 2\u0026gt;/dev/null || echo \u0026#34;Pending\u0026#34;) echo \u0026#34;[EC2-1] [$i/40] Status: $STATUS\u0026#34; if [ \u0026#34;$STATUS\u0026#34; = \u0026#34;Success\u0026#34; ]; then echo \u0026#34;EC2-1 deploy SUCCESS\u0026#34; break elif [ \u0026#34;$STATUS\u0026#34; = \u0026#34;Failed\u0026#34; ] || [ \u0026#34;$STATUS\u0026#34; = \u0026#34;Cancelled\u0026#34; ] || [ \u0026#34;$STATUS\u0026#34; = \u0026#34;TimedOut\u0026#34; ]; then echo \u0026#34;EC2-1 deploy FAILED with status: $STATUS\u0026#34; echo \u0026#34;--- EC2-1 Error Output ---\u0026#34; aws ssm get-command-invocation \\ --command-id \u0026#34;$COMMAND_ID\u0026#34; \\ --instance-id \u0026#34;${{ secrets.EC2_INSTANCE_ID_1 }}\u0026#34; \\ --query \u0026#34;{stdout:StandardOutputContent,stderr:StandardErrorContent}\u0026#34; \\ --output json || true exit 1 fi sleep 15 done if [ \u0026#34;$STATUS\u0026#34; != \u0026#34;Success\u0026#34; ]; then echo \u0026#34;EC2-1 deploy timeout after 10 minutes\u0026#34; exit 1 fi # ── Deploy EC2-2 after EC2-1 successfully completes ────────────────────────────── - name: Deploy on EC2-2 via SSM run: | set -euo pipefail jq -n \\ --arg version \u0026#34;${{ steps.version.outputs.VERSION }}\u0026#34; \\ --arg s3_bucket \u0026#34;${{ secrets.S3_BUCKET }}\u0026#34; \\ --arg db_url \u0026#34;${{ secrets.DB_URL }}\u0026#34; \\ --arg db_user \u0026#34;${{ secrets.DB_USERNAME }}\u0026#34; \\ --arg db_pass \u0026#34;${{ secrets.DB_PASSWORD }}\u0026#34; \\ --arg jwt_secret \u0026#34;${{ secrets.JWT_SECRET }}\u0026#34; \\ --arg google_id \u0026#34;${{ secrets.GOOGLE_CLIENT_ID }}\u0026#34; \\ --arg aws_key \u0026#34;${{ secrets.AWS_S3_ACCESS_KEY_ID }}\u0026#34; \\ --arg aws_secret \u0026#34;${{ secrets.AWS_S3_SECRET_ACCESS_KEY }}\u0026#34; \\ --arg aws_bucket \u0026#34;${{ secrets.AWS_S3_BUCKET }}\u0026#34; \\ --arg email_from \u0026#34;${{ secrets.APP_EMAIL_FROM }}\u0026#34; \\ \u0026#39; [ if $db_url != \u0026#34;\u0026#34; then \u0026#34;-e DB_URL=\u0026#34; + ($db_url | @sh) else empty end, if $db_user != \u0026#34;\u0026#34; then \u0026#34;-e DB_USERNAME=\u0026#34; + ($db_user | @sh) else empty end, if $db_pass != \u0026#34;\u0026#34; then \u0026#34;-e DB_PASSWORD=\u0026#34; + ($db_pass | @sh) else empty end, if $jwt_secret != \u0026#34;\u0026#34; then \u0026#34;-e JWT_SECRET=\u0026#34; + ($jwt_secret | @sh) else empty end, if $google_id != \u0026#34;\u0026#34; then \u0026#34;-e GOOGLE_CLIENT_ID=\u0026#34; + ($google_id | @sh) else empty end, if $aws_key != \u0026#34;\u0026#34; then \u0026#34;-e AWS_S3_ACCESS_KEY_ID=\u0026#34; + ($aws_key | @sh) else empty end, if $aws_secret != \u0026#34;\u0026#34; then \u0026#34;-e AWS_S3_SECRET_ACCESS_KEY=\u0026#34; + ($aws_secret | @sh) else empty end, if $aws_bucket != \u0026#34;\u0026#34; then \u0026#34;-e AWS_S3_BUCKET=\u0026#34; + ($aws_bucket | @sh) else empty end, if $email_from != \u0026#34;\u0026#34; then \u0026#34;-e APP_EMAIL_FROM=\u0026#34; + ($email_from | @sh) else empty end ] | join(\u0026#34; \u0026#34;) as $env_flags | (\u0026#34;aws s3 cp s3://\u0026#34; + $s3_bucket + \u0026#34;/rookwork-backend-\u0026#34; + $version + \u0026#34;.jar /home/ec2-user/rookwork-backend-sb/rookwork-backend.jar --no-progress \u0026amp;\u0026amp; cd /home/ec2-user/rookwork-backend-sb \u0026amp;\u0026amp; sudo docker build --no-cache -t rookwork-backend:\u0026#34; + $version + \u0026#34; . \u0026amp;\u0026amp; { sudo docker rm -f rookwork-backend 2\u0026gt;/dev/null; sudo docker run -d --restart always --name rookwork-backend -p 8080:8080 \u0026#34; + $env_flags + \u0026#34; -e JWT_EXPIRATION=604800000 -e JWT_REFRESH_EXPIRATION=2592000000 -e AWS_REGION=ap-southeast-1 rookwork-backend:\u0026#34; + $version + \u0026#34;; }\u0026#34;) as $cmd | { \u0026#34;commands\u0026#34;: [$cmd] } \u0026#39; \u0026gt; ssm-params-ec2-2.json COMMAND_ID=$(aws ssm send-command \\ --instance-ids \u0026#34;${{ secrets.EC2_INSTANCE_ID_2 }}\u0026#34; \\ --document-name \u0026#34;AWS-RunShellScript\u0026#34; \\ --region ap-southeast-1 \\ --parameters file://ssm-params-ec2-2.json \\ --query \u0026#34;Command.CommandId\u0026#34; \\ --output text) echo \u0026#34;EC2-2 SSM Command ID: $COMMAND_ID\u0026#34; for i in $(seq 1 40); do STATUS=$(aws ssm get-command-invocation \\ --command-id \u0026#34;$COMMAND_ID\u0026#34; \\ --instance-id \u0026#34;${{ secrets.EC2_INSTANCE_ID_2 }}\u0026#34; \\ --query \u0026#34;Status\u0026#34; --output text 2\u0026gt;/dev/null || echo \u0026#34;Pending\u0026#34;) echo \u0026#34;[EC2-2] [$i/40] Status: $STATUS\u0026#34; if [ \u0026#34;$STATUS\u0026#34; = \u0026#34;Success\u0026#34; ]; then echo \u0026#34;EC2-2 deploy SUCCESS\u0026#34; break elif [ \u0026#34;$STATUS\u0026#34; = \u0026#34;Failed\u0026#34; ] || [ \u0026#34;$STATUS\u0026#34; = \u0026#34;Cancelled\u0026#34; ] || [ \u0026#34;$STATUS\u0026#34; = \u0026#34;TimedOut\u0026#34; ]; then echo \u0026#34;EC2-2 deploy FAILED with status: $STATUS\u0026#34; echo \u0026#34;--- EC2-2 Error Output ---\u0026#34; aws ssm get-command-invocation \\ --command-id \u0026#34;$COMMAND_ID\u0026#34; \\ --instance-id \u0026#34;${{ secrets.EC2_INSTANCE_ID_2 }}\u0026#34; \\ --query \u0026#34;{stdout:StandardOutputContent,stderr:StandardErrorContent}\u0026#34; \\ --output json || true exit 1 fi sleep 15 done if [ \u0026#34;$STATUS\u0026#34; != \u0026#34;Success\u0026#34; ]; then echo \u0026#34;EC2-2 deploy timeout after 10 minutes\u0026#34; exit 1 fi [!TIP] The rolling update strategy ensures high availability (Zero Downtime) when updating the backend application across the EC2 instances.\n"},{"uri":"https://nguyenankhang.rookwork.asia/6-self-evaluation/","title":"Self-Assessment","tags":[],"description":"","content":"Internship Self-Evaluation During my internship at Amazon Web Services Viet Nam Company Limited from 17/04/2026 to 10/07/2026, I had the invaluable opportunity to learn, practice, and apply the knowledge acquired at Ho Chi Minh City University of Technology to a real-world enterprise environment.\nI participated in the Workforce Bootcamp - First Cloud AI Journey training program and directly developed the Rookwork project (a collaborative project \u0026amp; issue management platform integrated with AWS cloud services). Through this experience, I greatly improved my technical skills in Java Spring Boot, React, Electron packaging, AWS cloud infrastructure configuration, as well as soft skills such as reporting, team collaboration, and problem-solving.\nIn terms of work ethic, I always strived to complete assigned tasks diligently, complied with workplace regulations, adhered to schedules, and actively engaged with mentors and colleagues to improve work efficiency.\nTo objectively reflect on my internship period, I evaluate myself based on the following criteria:\nNo. Criteria Description Good Fair Average 1 Professional knowledge \u0026amp; skills Understanding of the field, applying knowledge in practice, proficiency with tools, work quality ✅ ☐ ☐ 2 Ability to learn Ability to absorb new technology, research documentation, and learn quickly ✅ ☐ ☐ 3 Proactiveness Taking initiative, seeking out tasks, and proposing suitable technical solutions ✅ ☐ ☐ 4 Sense of responsibility Completing tasks on time and ensuring overall deliverable quality ✅ ☐ ☐ 5 Discipline Adhering to schedules, organizational rules, and software development processes ✅ ☐ ☐ 6 Progressive mindset Willingness to receive feedback, accept critique, and improve oneself ✅ ☐ ☐ 7 Communication Presenting technical ideas, status reporting, and conveying work outcomes clearly ☐ ✅ ☐ 8 Teamwork Working effectively with colleagues, participating in discussions, and sharing knowledge ✅ ☐ ☐ 9 Professional conduct Respecting colleagues, partners, and maintaining a professional demeanor ✅ ☐ ☐ 10 Problem-solving skills Identifying bugs, analyzing root causes, and proposing optimal fixes ☐ ✅ ☐ 11 Contribution to project/team Submitting stable code, completing the MVP target on time and up to standard ✅ ☐ ☐ 12 Overall General evaluation of progress and value added during the entire internship period ✅ ☐ ☐ Areas for Continued Improvement To best prepare for my future career in professional software engineering, I aim to focus on improving the following areas:\nTime Management: Optimize time allocation when handling multiple parallel tasks to maintain consistently high productivity. Technical Communication: Actively engage in deeper system architecture discussions with senior engineers to accelerate knowledge acquisition. Large-scale Problem Solving: Build a comprehensive analytical mindset for tackling complex distributed systems and advanced cloud services. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.6-week6/","title":"Week 6 Worklog","tags":[],"description":"","content":"Week 6 Objectives: Understand RDS, Aurora databases, and multi-account organization structures with AWS Organizations. Deploy a PostgreSQL database instance securely inside private subnets of a VPC. Set up AWS Storage Gateway on-premises and mount File Shares on local servers. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Study RDS and Amazon Aurora relational database features, and explore AWS Organizations setup. 05/25/2026 05/25/2026 https://000115.awsstudygroup.com/ 3 Provision an Amazon RDS PostgreSQL instance within the private subnets of the custom VPC. 05/26/2026 05/26/2026 https://000005.awsstudygroup.com/ 4 Configure AWS Storage Gateway to bridge on-premises local environments and AWS cloud storage. 05/27/2026 05/27/2026 https://000024.awsstudygroup.com/ 5 Create NFS/SMB File Shares on the Storage Gateway and define appropriate S3 access permissions. 05/28/2026 05/28/2026 https://000024.awsstudygroup.com/ 6 Mount the File Share on a local on-premises server and verify real-time read/write synchronization with S3. 05/29/2026 05/29/2026 https://000024.awsstudygroup.com/ Week 6 Achievements: Deployed a highly secure, managed relational PostgreSQL database in private VPC subnets. Configured a hybrid storage architecture that maps local directories directly to Amazon S3. Gained practical experience in corporate cloud structure management using AWS Organizations. "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.7-route53-s3-cloudfront-ses/","title":"AWS Services Integration","tags":[],"description":"","content":"In this section, we configure the core AWS infrastructure services required for our application, including domain resolution (Route 53), S3 static hosting, secure HTTPS delivery (CloudFront + ACM), private file storage (S3 Storage), and email notification services (SES).\nContent 5.7.1. Domain \u0026amp; AWS Route 53 Configuration - Guide on delegating domain resolution from Tenten.vn to AWS Route 53. 5.7.2. Static Website Hosting with S3 - Guide on creating an S3 Bucket and uploading React Frontend assets. 5.7.3. Secure Delivery via Amazon CloudFront \u0026amp; ACM - Guide on requesting ACM SSL certificates, setting up CloudFront CDN, and mapping Route 53 records to CDN. 5.7.4. Private File Storage with S3 - Guide on configuring a private S3 Bucket, Spring Boot Backend, and S3 Service in Java. 5.7.5. Email Integration with Amazon SES - Guide on verifying domain identity on AWS SES, creating SMTP credentials, and sending emails. "},{"uri":"https://nguyenankhang.rookwork.asia/7-feedback/","title":"Sharing and Feedback","tags":[],"description":"","content":" Here, I would like to share my personal feedback and opinions about my experience participating in the First Cloud AI Journey (FCAJ) program. I hope these insights will help the organizers further refine and elevate the program for future cohorts.\nOverall Evaluation 1. Working and Learning Environment\nThe learning environment throughout the bootcamp is highly dynamic, friendly, and open. Members of the FCAJ community are always willing to help and share knowledge whenever I run into issues with lab assignments or project deployment. The online learning platforms and face-to-face sync sessions are well-organized and professional, providing the ideal setup for students to build their skills.\n2. Support from Mentors / Admin Team\nI am extremely grateful for the dedicated support from both our mentors and the program administration. The mentors provide exceptionally detailed guidance, explaining the underlying principles of AWS services and encouraging us to troubleshoot issues independently before offering hints. The admin team is quick to handle sandbox account issues, provide materials, and foster a warm, connected community atmosphere.\n3. Relevance of Work to Academic Major\nThis training program directly aligns with and enhances my Information Technology studies at university. The hands-on labs on AWS Cloud allowed me to solidify theoretical concepts in networking and database systems, while expanding my perspective on designing modern, cloud-native architectures.\n4. Learning \u0026amp; Skill Development Opportunities\nThroughout the program, I developed highly valuable skills. These range from mastering core AWS services (S3, CloudFront, Route 53, SES) and configuring CI/CD automation pipelines via GitHub Actions, to essential soft skills like technical writing, time management, and approaching problem-solving like a professional cloud engineer.\n5. Program Culture \u0026amp; Team Spirit\nThe program culture is incredibly positive, emphasizing equality, respect, and self-learning. During our collaborative work on the Rookwork project, teammates were always ready to share source code and assist each other in resolving configuration issues, creating a cohesive and enthusiastic team spirit.\n6. Program Policies \u0026amp; Benefits\nThe program covers all AWS sandbox practice costs, allowing students to experiment with cloud resources without financial concern. Additionally, the opportunity to attend major tech events like Community Day and participate in specialized technical seminars provides incredible value to a graduating student like myself.\nAdditional Survey Questions What did you find most satisfying during the program?\nThe opportunity to study and practice under an official cloud curriculum combined with real-world project development (Rookwork). This combination allowed me to translate academic theory into real-world applications running on the cloud, vastly boosting my confidence in my professional capabilities. What do you think the program should improve for future cohorts?\nThe organizers could set up periodic tech talk sessions with AWS Solution Architects, giving students direct access to how large-scale enterprise problems are solved and offering deeper career-planning advice. If recommending to a friend, would you suggest they participate? Why or why not?\nYes, absolutely (100% recommended). It is an excellent launchpad for any IT student who wants to approach cloud and AI technologies in a structured, practical manner under the mentorship of experienced professionals. Suggestions \u0026amp; Expectations Suggestions to improve experience: Allocate more time for live technical Q\u0026amp;A sessions so project groups have more opportunities to discuss architectural designs or error debugging with mentors. Future Expectations: Obtain AWS Certified Solutions Architect - Associate certification, seek job opportunities at AWS Vietnam or partners, and continue supporting the FCAJ community as an alumnus. Other Comments: A sincere thank you to the FCAJ organizing committee and mentors for creating such a meaningful and rewarding technical program for IT students! "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.7-week7/","title":"Week 7 Worklog","tags":[],"description":"","content":"Week 7 Objectives: Deploy the Spring Boot backend API application on EC2 and verify domain endpoints. Create Amazon EFS shared file systems and monitor instance performance with CloudWatch. Set up S3 static hosting, CloudFront, and multi-region replication. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Set up Java Runtime Environment (JRE) on EC2, upload and run the Spring Boot backend (rookwork-backend-sb). 06/01/2026 06/01/2026 3 Configure Nginx as a reverse proxy, point domain via Route 53, and verify all REST endpoints. 06/02/2026 06/02/2026 4 Create Amazon EFS (Elastic File System), mount it to EC2, and establish monitoring dashboards in CloudWatch. 06/03/2026 06/03/2026 https://000068.awsstudygroup.com/ 5 Configure S3 Bucket Static Web Hosting and CloudFront CDN distribution for the web frontend. 06/04/2026 06/04/2026 6 Set up S3 Cross-Region Replication (CRR) for disaster recovery and define object transition rules. 06/05/2026 06/05/2026 https://000069.awsstudygroup.com/ Week 7 Achievements: Deployed and exposed the Rookwork Spring Boot backend API securely through Nginx and a custom domain. Configured a distributed shared file system (EFS) and performance tracking dashboard. Hosted the frontend app on S3/CloudFront and enabled multi-region data redundancy. "},{"uri":"https://nguyenankhang.rookwork.asia/5-workshop/5.8-cicd-frontend/","title":"Deploy Frontend CI/CD with GitHub Actions","tags":[],"description":"","content":" To optimize the application delivery pipeline, we configure a Continuous Integration and Continuous Deployment (CI/CD) workflow using GitHub Actions.\nWhenever developers push new commits or merge code into the primary branch (main), the runner automatically installs NPM libraries via Yarn, compiles the React frontend assets with Node.js 22, synchronizes them to the Amazon S3 Bucket, and invalidates the CloudFront CDN cache.\nCI/CD Pipeline Workflow Code Push (main) ──► GitHub Actions Runner ──► Build Frontend (Yarn) │ ▼ Invalidate CDN Cache ◄── CloudFront ◄── Sync dist/ to S3 Bucket Step 1: Create an IAM Deployment User on AWS To maintain secure access policies, do not use your root account. Create a dedicated IAM User (e.g., github-actions-deployer) with the following minimum required policies:\nAmazonS3FullAccess (or scoped to write to your frontend S3 bucket). CloudFrontFullAccess (or scoped to create invalidations on your distribution). Upon creation, copy the Access Key ID and Secret Access Key to save in GitHub.\nStep 2: Configure GitHub Secrets Navigate to your frontend project repository on GitHub. Go to Settings -\u0026gt; Secrets and variables -\u0026gt; Actions. Click New repository secret and define the following variables: AWS_ACCESS_KEY_ID: The Access Key ID of your IAM deployment user. AWS_SECRET_ACCESS_KEY: The matching Secret Access Key. S3_BUCKET: The S3 static hosting bucket name (e.g., rookwork.asia). CF_DISTRIBUTION_ID: The distribution ID of your CDN to trigger cache resets. VITE_GOOGLE_CLIENT_ID: The Google client ID (loaded during build runtime). Step 3: Create the Workflow File In the root directory of your frontend repository, create the .github/workflows/ directory structure and create the deployment configuration file .github/workflows/deploy.yml with the following content:\nname: Deploy Frontend to S3 on: push: branches: [main] # ← CHỈ nhánh main mới trigger jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 22 cache: yarn - name: Install dependencies run: yarn install --frozen-lockfile - name: Build browser app run: yarn build:browser env: VITE_API_URL: https://api.rookwork.asia VITE_GOOGLE_CLIENT_ID: ${{ secrets.VITE_GOOGLE_CLIENT_ID }} - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-southeast-1 - name: Sync assets to S3 (cache forever) run: | aws s3 sync ./browser-app/dist s3://${{ secrets.S3_BUCKET }} \\ --delete \\ --exclude \u0026#34;index.html\u0026#34; \\ --cache-control \u0026#34;public,max-age=31536000,immutable\u0026#34; - name: Upload index.html (no cache) run: | aws s3 cp ./browser-app/dist/index.html s3://${{ secrets.S3_BUCKET }}/index.html \\ --cache-control \u0026#34;no-cache,no-store,must-revalidate\u0026#34; - name: Invalidate CloudFront cache run: | aws cloudfront create-invalidation \\ --distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \\ --paths \u0026#34;/*\u0026#34; Step 4: Verify the Pipeline Make a minor text or layout change in your local frontend codebase. Commit and push the changes to GitHub: git add . git commit -m \u0026#34;feat: test github actions pipeline\u0026#34; git push origin main Open the Actions tab in your GitHub repository, and you will see the pipeline running. Once all steps turn green, visit your custom domain (e.g., https://rookwork.asia). You will see the changes live instantly without performing manual server updates! "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.8-week8/","title":"Week 8 Worklog","tags":[],"description":"","content":"Week 8 Objectives: Master AWS Security and Access Management (IAM, Cognito, Identity Center). Encrypt data using AWS KMS keys and monitor cloud security posture using AWS Security Hub. Implement CloudFront distribution security headers and SSL/TLS certificates. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Review AWS IAM users, policies, roles, and configure AWS IAM Identity Center for Single Sign-On (SSO). 06/08/2026 06/08/2026 https://000012.awsstudygroup.com/ 3 Generate KMS keys, encrypt RDS instances and S3 buckets at rest, and review AWS Security Hub findings. 06/09/2026 06/09/2026 https://000033.awsstudygroup.com/ 4 Study Amazon Cognito User Pools and Identity Pools for user management and secure authentication. 06/10/2026 06/10/2026 https://000141.awsstudygroup.com/ 5 Configure SSL/TLS certificates via ACM on CloudFront and set up security response headers (WAF, CSP). 06/11/2026 06/11/2026 https://000026.awsstudygroup.com/ 6 Run security scans (port checks, TLS versions) to ensure the deployment meets security best practices. 06/12/2026 06/12/2026 Week 8 Achievements: Implemented security controls on AWS using IAM roles and centralized access through Identity Center. Enforced data-at-rest encryption with KMS keys across DB and storage, achieving compliance in Security Hub. Secured web communication with CloudFront HTTPS and prepared Cognito integration for user sign-in. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.9-week9/","title":"Week 9 Worklog","tags":[],"description":"","content":"Week 9 Objectives: Hold team status meetings and plan next development iterations. Deploy the Rookwork frontend application to S3 and CloudFront. Configure automated CI/CD pipelines for frontend builds. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Conduct a weekly team meeting to discuss project status, resolve blockers, and divide upcoming tasks. 06/15/2026 06/15/2026 3 Build the React frontend (rookwork-frontend) and upload the production build files to the S3 web bucket. 06/16/2026 06/16/2026 4 Write a GitHub Actions CI/CD workflow file to automate testing, building, and deploying the frontend code. 06/17/2026 06/17/2026 5 Configure secrets (AWS access keys) in GitHub and test the automated build-and-deploy pipeline. 06/18/2026 06/18/2026 Week 9 Achievements: Automated the frontend deployment process, enabling seamless delivery through Git pushes. Successfully deployed the React + Vite static web app to S3 and distributed it via CloudFront. Ensured proper project coordination and progress tracking within the team. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.10-week10/","title":"Week 10 Worklog","tags":[],"description":"","content":"Week 10 Objectives: Integrate Amazon SES (Simple Email Service) for sending transactional emails. Implement S3 file and image storage for task attachments and user avatars. Perform bug fixes on backend services and storage integrations. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Hold progress meeting and plan the email notification framework for Rookwork. 06/22/2026 06/22/2026 3 Configure SES Client and Thymeleaf email templates in the Spring Boot backend (EmailService.java). 06/23/2026 06/23/2026 4 Develop backend attachment upload APIs utilizing S3Template to store project files on S3. 06/24/2026 06/24/2026 5 Implement S3 presigned URL generation with 15 minutes expiration for secure media retrieval. 06/25/2026 06/25/2026 6 Fix issues relating to CORS, file upload limits, and exception handling for S3 network timeouts. 06/26/2026 06/26/2026 Week 10 Achievements: Integrated Amazon SES successfully to send automated emails for task assignment and comments. Created a secure, presigned S3 storage workflow for uploading and viewing documents and avatars. Resolved critical bugs in backend file handling, improving system reliability. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.11-week11/","title":"Week 11 Worklog","tags":[],"description":"","content":"Week 11 Objectives: Deploy transactional verification loops (OTP) and member invitation emails via SES. Translate and publish technical blogs on the AWS study group. Verify real-time system notifications and address final bugs. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Write and translate technical blogs sharing knowledge. Prepare drafts for 3 blogs (Ansible AAP \u0026amp; ROSA, AWS WAF Dashboard, and Serverless CQRS). 06/29/2026 06/29/2026 3 Implement sign-up verification OTP and password reset OTP workflows via Amazon SES email delivery. Simultaneously publish Blog 1: Scaling Telco Automation with AAP and ROSA on AWS on the AWS Study Group VN. 06/30/2026 06/30/2026 4 Develop project invitation flows, allowing project owners to invite new and existing users via secure links. 07/01/2026 07/01/2026 5 Verify WebSocket integrations on the frontend for instant, real-time activity and comment notifications. Simultaneously publish Blog 2: Introduction to AWS WAF Traffic Overview Dashboard on the AWS Study Group VN. 07/02/2026 07/02/2026 7 Publish Blog 3: Serverless Patterns: Read-Write Separation (CQRS Prelude) on the AWS Study Group VN. 07/04/2026 07/04/2026 Week 11 Achievements: Secured user registration and recovery flows with automated OTP email verification. Completed collaborative project invitation workflows with template-rendered emails. Fixed WebSocket connection lag, ensuring instant real-time notification delivery on the dashboard. Successfully published 3 technical blogs covering AAP/ROSA integration, AWS WAF Traffic Dashboard, and Serverless CQRS on the AWS Study Group VN. "},{"uri":"https://nguyenankhang.rookwork.asia/1-worklog/1.12-week12/","title":"Week 12 Worklog","tags":[],"description":"","content":"Week 12 Objectives: Conduct the final project review and demonstrate stable software features. Document the system\u0026rsquo;s architecture and detail data workflows. Calculate cloud hosting costs and assemble the final internship report. Tasks to be carried out this week: Day Task Start Date Completion Date Reference Material 2 Host the final team meeting, presenting the completed Rookwork platform to the mentor and advisor. 07/06/2026 07/06/2026 3 Draw and document system architecture diagrams and detailed data workflows (S3 upload, SES mailing). 07/07/2026 07/07/2026 4 Utilize the AWS Pricing Calculator to estimate monthly running costs for the project\u0026rsquo;s cloud architecture. 07/08/2026 07/08/2026 https://000034.awsstudygroup.com/ 5 Perform load tests on the backend, verify rate-limiting thresholds (Bucket4j), and compile the final Hugo report. 07/09/2026 07/09/2026 Week 12 Achievements: Successfully completed and deployed the Rookwork project management platform. Generated precise architectural documentation and budget predictions. Completed all graduation internship requirements and prepared the final report for submission. "},{"uri":"https://nguyenankhang.rookwork.asia/categories/","title":"Categories","tags":[],"description":"","content":""},{"uri":"https://nguyenankhang.rookwork.asia/tags/","title":"Tags","tags":[],"description":"","content":""}]