For the AWS Builder Center’s July Weekend Challenge, I built WeekWrap - an AI-native work log app where Bedrock is a functional part of what the app does at runtime, not a development aid.

The contest theme was:

Create a personal AI-powered productivity tool - something that genuinely helps you get more done. Here are some ideas to spark your creativity:

  • Task prioritizer - let AI sort your to-do list by urgency and impact
  • Email summarizer - condense your inbox into actionable highlights
  • Meeting prep bot - auto-generate agendas and talking points
  • Habit tracker - use AI to surface insights about your daily routines
  • Deploy using AWS Free Tier services - for new accounts, access up to $200 in Free Tier credits covering Amazon Bedrock, Nova models, Amplify, Lambda, and more

WeekWrap made the top 50 qualifying submissions, and the AWS Builder Jacket showed up at my door not long after - not going to pretend that didn't make my day!

AWS Builder Jacket received for placing in the first 50 qualifying challenge submissions

Why I built it

Shipping products was never the hard part - reconstructing them at the end of the year is. Notes scattered everywhere, wins undocumented, no line from daily work to annual goals until someone asks. WeekWrap fixes that.

The idea is simple - log a short note about what I did, and the app structures it into a tagged accomplishment mapped to one of my annual goals. At review time, hit Generate and get a first-draft narrative grouped by goal. No more blank-page problem.


What I built

WeekWrap is a personal work log with three functions:

  • Log - type a raw note (“shipped the migration script, unblocked the team for two weeks”) and Bedrock structures it into a specific accomplishment with topic tags and a goal mapping
  • Goals - set your annual goals once; every entry gets mapped to the closest one automatically
  • Rollup - pick a date range, generate a self-review narrative grouped by goal, copy it straight into your performance doc

Log tab - logging a work note and viewing structured entries

The Log tab after submitting a note. Bedrock has structured the raw input into a one-sentence accomplishment, tagged it, and mapped it to a goal. The entry appears below the input immediately.

Goals tab - setting annual goals

The Goals tab. Annual goals saved here are what Bedrock maps every new entry against. Add or remove goals at any time - the next entry you log picks up the updated list.

Rollup tab - generated self-review narrative

The Rollup tab after hitting Generate - Bedrock Nova Micro has written a first-draft self-review narrative from the stored entries, grouped by goal. Copy it straight into a performance doc.



How I built it

The idea is to build this in a weekend on free tier only. That ruled out ALB, API Gateway, and Fargate. The stack:

Backend: FastAPI (Python) wrapped with mangum to run as a Lambda handler, exposed via a Lambda Function URL. No API Gateway needed - Function URLs support CORS natively and are free within Lambda’s free tier. The app has no auth - it is public by design, scoped to personal use at a URL.

Storage: Two DynamoDB tables on on-demand billing - weekwrap-entries for logged notes and weekwrap-goals for the user’s annual goals. Both use a single-table-style pk/sk pattern: entries keyed on USER#default with an ISO timestamp sort key, goals keyed on GOALS#default with GOAL#001, GOAL#002 sort keys.

AI: Amazon Bedrock with two Nova models:

  • amazon.nova-lite-v1:0 for structured extraction - takes the raw note and returns a JSON object with accomplishment, tags, and goal_id
  • amazon.nova-micro-v1:0 for the rollup narrative - cheaper model, sufficient for prose generation from structured input

Both calls go through the Bedrock Converse API, which gives a consistent interface across models. An extraction prompt asks Nova Lite to return JSON only. Nova occasionally wraps output in markdown code fences, so the handler strips those before json.loads().

Frontend: Vanilla HTML/CSS/JS - no framework, no build step. Three tabs (Log, Goals, Rollup) in a single index.html, stored in S3 and served over HTTPS via CloudFront. S3 static website hosting is HTTP-only, so CloudFront sits in front of it as a CDN layer - users get HTTPS, CloudFront fetches from S3 over HTTP internally. The Function URL is injected at deploy time.

IaC: CDK v2 Python. One stack (WeekWrapStack) provisions everything - Lambda, Function URL, two DynamoDB tables, S3 bucket with frontend deployment. The CDK patterns here - bootstrapping, stack structure, IAM scoping - follow the same approach as my AWS CDK series.


AWS services used

ServiceRole
Lambda (Python 3.12)Backend - FastAPI app via mangum
Lambda Function URLHTTP endpoint with CORS, no API Gateway
DynamoDB (on-demand)weekwrap-entries and weekwrap-goals tables
S3 (static website hosting)Frontend - HTML/CSS/JS
CloudFrontHTTPS CDN in front of S3 - fixes HTTP-only limitation of S3 website endpoints
Amazon Bedrock - Nova LiteStructured JSON extraction from raw notes
Amazon Bedrock - Nova MicroSelf-review narrative generation
IAMTask role scoped to the two DynamoDB tables and two Bedrock model ARNs
CDK v2 PythonIaC - single stack deploys everything

Everything except Bedrock inference tokens is within the AWS Free Tier. The Nova model costs per 1,000 tokens are low enough that personal use stays under a dollar a month.


Architecture overview

  • The frontend is stored in S3 and served over HTTPS via CloudFront - S3 website endpoints are HTTP-only, so CloudFront provides the HTTPS termination
  • All API calls go directly from the browser to the Lambda Function URL over HTTPS - no API Gateway, no load balancer
  • Lambda handles every route: DynamoDB reads/writes for entries and goals, and synchronous Bedrock calls for the two AI steps
  • The two DynamoDB tables are independent; entries accumulate, goals are overwritten on each save
Browser
   |
   |-- HTTPS --> CloudFront --> S3 bucket (static frontend)
   |
   '-- HTTPS --> Lambda Function URL
                        |
                        +-- DynamoDB (entries + goals)
                        +-- Bedrock Nova Lite  (POST /entries)
                        +-- Bedrock Nova Micro (POST /rollup)

What I learned

  1. Use the Bedrock Converse API, not invoke_model. I started sketching with invoke_model using an Anthropic-specific body format, then switched to Nova models. The Converse API is model-agnostic - the same bedrock.converse() call works for Nova Lite, Nova Micro, and any other model that supports it. Switching models is a one-line environment variable change.
  2. Nova models handle structured JSON extraction cleanly. The extraction prompt asks for JSON only, and Nova Lite returns it reliably. The code-fence stripping is a minor defensive measure, not something that fires often.
  3. Lambda Function URLs remove a lot of friction for personal tools. No API Gateway stage to manage, no extra cost, CORS configuration is a first-class option on the Function URL construct. If you don’t need WAF or usage plans, Function URLs save you the API Gateway setup entirely.
  4. IAM ARNs for Nova foundation models differ from inference profiles. Cross-region inference profiles (used with some Claude models) have an ARN that includes the account ID. Nova foundation model ARNs don’t - they follow the pattern arn:aws:bedrock:*::foundation-model/amazon.nova-lite-v1:0 with a double colon and no account segment. Getting this wrong produces a silent IAM deny at runtime.
  5. mangum makes Lambda + FastAPI seamless. Wrap the FastAPI app with Mangum(app, lifespan="off") and the handler just works. Local dev runs with uvicorn main:app, Lambda runs with main.handler - same code, no adapter logic to maintain.
  6. S3 static website hosting is HTTP-only - add CloudFront if you need HTTPS. After publishing the post I found the app was unreachable on mobile. The S3 website endpoint (s3-website-*.amazonaws.com) does not support HTTPS, and modern mobile browsers increasingly block plain HTTP. The fix is a CloudFront distribution pointing at the S3 website domain as an HTTP origin, with REDIRECT_TO_HTTPS as the viewer protocol policy. Two extra CDK constructs, five minutes of deploy time, and mobile works. CloudFront is within the free tier (1 TB transfer + 10 M requests/month).

Notes

  1. All AWS services used are within the Free Tier at personal usage volumes. Bedrock Nova inference costs are minimal - under $1/month for typical daily logging.
  2. The two-model split (Nova Lite for extraction, Nova Micro for narrative) keeps costs lower than using a single larger model for both tasks.