I built my resume as a static site and put a visitor counter behind it. The page is one HTML file. The number on the page is a small serverless API.
Amazon S3 stores the file in a private bucket. CloudFront is the public address, and it is the only thing allowed to read the bucket. A visitor who opens the S3 URL directly is denied. HTTPS is the CloudFront certificate. I kept that hostname instead of attaching a domain I already owned.
The browser does not talk to DynamoDB. The page calls an HTTP API, API Gateway invokes a Python Lambda function, and the function adds 1 to one row in a DynamoDB table. The table key is a string, Id_string, and the row id is resume. The JavaScript looks up an element with id="visitor-count" and writes the number there. A script with no matching element calls the API and shows nothing.
I created the table, the function, and the API in the console first. Terraform came second. terraform import told Terraform that those resources already existed, so apply updated the function code instead of creating a second copy. The state file lives in a private S3 bucket. GitHub Actions cannot see a state file that exists only on my laptop.
The Python test never calls AWS. It replaces the DynamoDB table with a fake and checks that the function asks for an increment of 1 and returns that count. The first GitHub Actions run still failed. Importing the function creates a DynamoDB resource immediately, and the runner had no AWS region, so pytest failed before the fake was in place. Setting a region in the test fixed the import. The test still does not increment the live count.
Two repositories deploy two different things. A push to the API repository runs the test and then terraform apply. A push to the website repository uploads index.html and invalidates the CloudFront cache. The AWS keys for those workflows are GitHub secrets. They are not in the repository.
Top comments (0)