← Week 2: DynamoDB Internals

Day 14: Challenge — Single-Table DynamoDB Schema

Phase 5 · Aug 25, 2026

← Week 2: DynamoDB Internals

Challenge Overview

Design and implement a single-table DynamoDB schema for a task management application.

Entities: User, Project, Task, Comment, Tag
Access patterns:

  1. Get user profile
  2. Get all projects for a user
  3. Get all tasks in a project (sorted by due date)
  4. Get all tasks assigned to a user
  5. Get all comments on a task
  6. Get all tasks with a given tag
  7. Get overdue tasks for a user
← Week 2: DynamoDB Internals

Table Design

PK              SK                      GSI1-PK         GSI1-SK
USER#u1         PROFILE                 -               -
USER#u1         PROJECT#p1              -               -
USER#u1         ASSIGNED#t5             USER#u1         DUE#2026-08-20
PROJECT#p1      METADATA                -               -
PROJECT#p1      TASK#t1#DUE#2026-08-25  PROJECT#p1      DUE#2026-08-25
PROJECT#p1      TASK#t2#DUE#2026-08-30  PROJECT#p1      DUE#2026-08-30
TASK#t1         COMMENT#c1              -               -
TAG#rust        TASK#t1                 TAG#rust        TASK#t1
← Week 2: DynamoDB Internals

Implementation in Rust

// Access pattern 3: all tasks in a project sorted by due date
async fn get_project_tasks(
    db: &Client,
    project_id: &str,
) -> Result<Vec<Task>, AppError> {
    let result = db.query()
        .table_name("task-manager")
        .key_condition_expression("PK = :pk AND begins_with(SK, :prefix)")
        .expression_attribute_values(":pk", av!(project_id))
        .expression_attribute_values(":prefix", av!("TASK#"))
        .send()
        .await?;

    result.items.unwrap_or_default()
        .iter()
        .map(Task::from_dynamo_item)
        .collect()
}
← Week 2: DynamoDB Internals

Access Pattern 7: Overdue Tasks

Overdue tasks = tasks assigned to user + due date < today.

Using GSI1 (USER#alice, DUE#2026-08-24):

let today = Utc::now().format("DUE#%Y-%m-%d").to_string();

let result = db.query()
    .table_name("task-manager")
    .index_name("gsi1")
    .key_condition_expression("gsi1pk = :user AND gsi1sk < :today")
    .expression_attribute_values(":user", av!("USER#alice"))
    .expression_attribute_values(":today", av!(today))
    .send().await?;
← Week 2: DynamoDB Internals

Week 2 Recap

Topic Key insight
Data model PK+SK design; LSI vs GSI
Capacity RCU/WCU math; provisioned vs on-demand
Consistency Eventually consistent (cheap) vs strongly consistent
Transactions TransactWriteItems (100 items, atomic)
Streams CDC for projections; 24-hour retention
Single-table Collocate by partition for multi-entity queries

Next week: Container orchestration — ECS, EKS, and service discovery.