Capstone - Todo Data Manager
Introduction: Building a Production CLI Todo Application
Welcome to the capstone project for Chapter 25! Everything you've learned in Lessons 1-4 comes together here. You're going to build a complete, production-quality CLI todo management application that integrates:
- Lesson 1: Console I/O with input validation (menu-driven interface)
- Lesson 2: Safe file operations (reading and writing tasks)
- Lesson 3: Cross-platform paths (organizing tasks in files)
- Lesson 4: JSON data format (persisting structured task data)
This isn't a toy project—it's a real application that demonstrates professional-level coding practices. When you're done, you'll have a program that:
- Runs without crashing, even with invalid user input
- Persists task data to disk in organized JSON files
- Handles multiple tasks with responsive performance
- Recovers gracefully from common errors (missing files, corrupted data)
- Organizes code clearly so others can read and extend it
Time Estimate: 90-120 minutes of focused development (plus extension ideas if you want to go deeper)
What You'll Build: A fully functional Todo Data Manager with these features:
- Menu-driven interface - Display options, accept user choice, execute action, return to menu
- Create tasks - Prompt for title, description, priority, and due date
- Read tasks - List existing tasks, display selected task details
- Update tasks - Modify title, description, priority, or status
- Delete tasks - Remove tasks with confirmation
- Search tasks - Find tasks by keyword across title and description
- List tasks - Show all tasks organized by priority or status
- Exit gracefully - Clean shutdown with goodbye message
Application Architecture Introduction
Before writing code, let's understand the design. A well-architected application separates concerns:
Components
Menu Loop (Lesson 1)
- Displays menu options
- Accepts user choice
- Routes to appropriate function
- Returns to menu after operation
CRUD Functions (Lessons 2-4)
get_all_tasks()→ Load all tasks from disksave_task()→ Write or update a task to disksearch_tasks()→ Find tasks by keyworddelete_task()→ Remove task file
Data Structure (Lesson 4)
{
"id": 1,
"title": "Review PR",
"description": "Check for code quality",
"due_date": "2025-01-15",
"priority": 2,
"status": "pending",
"done": false
}
File Organization (Lesson 3)
tasks/
├── tasks.json
└── backup/
└── tasks_backup.json
Why This Design?
- Separation of Concerns: Menu loop doesn't know about file operations; functions don't know about UI
- Scalability: JSON file-based storage handles 10-100 tasks without performance issues
- Maintainability: Clear functions mean future extensions are easy
- Testability: Each function can be tested independently
💬 AI Colearning Prompt
"I'm designing a todo app. Should I store all tasks in a single JSON file or separate files per task? What are the tradeoffs? How do I serialize datetime objects to JSON?"
Expected Outcome: You'll understand data persistence patterns and JSON serialization before writing code. AI can help you think through design decisions before implementation.
Setting Up Project Structure
Every good application starts with organization. Let's initialize the directory structure and prepare for task data storage.
Creating the Tasks Directory
First, we ensure the tasks/ directory exists and is ready to store our JSON data:
Loading Python environment...
Output:
✅ Todo data manager initialized!
Data file: /home/user/tasks/tasks.json
Why this matters:
- Uses pathlib (Lesson 3) to create cross-platform paths
- Creates directories only if they don't exist (idempotent)
- Resolves absolute path to show user exactly where data is stored
- Single JSON file is simpler for small-to-medium task lists
🎓 Expert Insight
In AI-native development, you don't debug path errors manually—you design paths clearly at startup. Your job: specify the directory structure. AI can help you verify it's correct with
Path.resolve(). Also, notice that we're using ISO format strings ("2025-01-15") for due_date instead of datetime objects—this makes JSON serialization automatic.
Code Example 5.1: Project Structure and Data Initialization
Before we write the full app, let's look at how to initialize the project with proper JSON validation:
Loading Python environment...
Specification Reference: Lesson 4 (JSON) with error handling from Chapter 24 exception patterns
Prompt Used: "Show me how to initialize a JSON file with validation and handle corrupted data by creating a backup"
Validation Steps:
- ✅ File doesn't exist →
initialize_tasks_file()creates empty array - ✅ File exists and is valid → Loads without error
- ✅ File corrupted → Creates backup, resets with empty array
- ✅ Task serializes to JSON correctly with all fields
Core CRUD Functions
Now let's implement the functions that handle data persistence. These are the workhorses of the application—they orchestrate file I/O, error handling, and JSON operations.
Code Example 5.2: Complete CRUD Functions
Loading Python environment...
Specification Reference: Lessons 2, 3, 4 - file I/O, pathlib directory handling, JSON serialization and deserialization
Prompts Used:
- "Write a function that loads JSON data from a file and handles FileNotFoundError and JSONDecodeError"
- "Implement save_tasks that writes a list of dictionaries to JSON with UTF-8 encoding"
- "Write a search function that finds tasks by keyword in title or description"
Validation Steps:
- ✅ Load from empty file →
get_all_tasks()returns empty list - ✅ Save new task → file updated with correct JSON structure
- ✅ Search finds matches →
search_tasks("python")returns tasks with "python" in title/description - ✅ Delete removes task →
delete_task(id)removes task and returns True - ✅ Error handling → corrupted JSON shows warning but doesn't crash
- ✅ Date strings preserved → ISO format dates survive save/load cycle
🚀 CoLearning Challenge
Ask your AI Co-Teacher:
"My todo app is slow loading 1000 tasks—it loads everything every time. How would you optimize this? Should I use a database? When should I move away from JSON files? What's the performance limit for this approach?"
Expected Outcome: You'll understand performance trade-offs and scaling patterns beyond this capstone's 10-100 task scope.
Menu Loop Implementation
The menu loop is where user interaction happens. It displays options, accepts input with validation, routes to appropriate functions, and returns to menu after each operation.
Code Example 5.3: Complete Application Menu Loop
Loading Python environment...
Specification Reference: Lessons 1, 2, 3, 4 - all I/O concepts combined with date handling
Prompts Used:
- "Write a menu loop that displays options 1-8 and validates user input"
- "Create functions for each CRUD operation with error handling"
- "Implement search that finds tasks by keyword and priority sorting"
Validation Steps:
- ✅ Menu displays and accepts 1-8 → invalid input shows error and re-prompts
- ✅ Create task → prompts for title/description/priority/due date, saves to file, returns to menu
- ✅ Read task → lists tasks, accepts selection, displays selected task, returns to menu
- ✅ Update task → allows changing title/description/priority, saves to file, returns to menu
- ✅ Delete task → requires confirmation before removing from file
- ✅ Mark complete → toggles done flag and status, returns to menu
- ✅ Search → finds tasks by keyword, shows results
- ✅ List → shows all tasks sorted by priority
- ✅ Exit → graceful shutdown with goodbye message
✨ Teaching Tip
Use Claude Code to test edge cases in your implementation:
"What happens if I create a task with an empty title? Or try to delete a task twice? What if I enter an invalid due date format? Show me each error and how my code should handle it."
Error Handling and Validation
Production-quality applications handle errors gracefully. Let's review the validation patterns used throughout:
Input Validation (Lesson 1 Pattern)
Loading Python environment...
File Operation Errors (Lesson 2 Pattern)
Loading Python environment...
Date Format Validation
Loading Python environment...
Path Safety (Lesson 3 Pattern)
Loading Python environment...
Data Validation
Loading Python environment...
Testing and Refinement
How to Test Your Application
-
Test Create: Run the app, select "Create Task", enter title/description/priority, verify file is updated
$ cat tasks/tasks.json
# Should show task with all fields -
Test Read: Select "Read Task", choose one from the list, verify it displays correctly
-
Test Update: Select "Update Task", change the title/priority, verify file is updated
-
Test Delete: Create a task, delete it, verify it's removed from file
-
Test Search: Create tasks with different keywords, search for them, verify results
-
Test Mark Complete: Create a task, mark it complete, verify "done" is True
-
Test Menu Loop: Go through several operations, verify app returns to menu each time
-
Test Error Handling:
- Enter invalid menu choice → should show error and re-prompt
- Try to read tasks when none exist → should show "No tasks found"
- Try to delete non-existent task → should handle gracefully
- Enter invalid date format → should show error
- Enter non-numeric priority → should show error
Edge Cases to Consider
- What happens if someone creates a task with special Unicode characters? (UTF-8 should preserve them)
- What if the tasks/ directory is deleted while the app is running? (mkdir will recreate it)
- What if someone has 50 tasks—does the app still respond quickly? (Yes, loading/saving JSON is efficient)
- What if you edit tasks.json manually while the app is running? (Next operation will use latest version from disk)
- What if due_date is in the past? (App accepts it—you could add validation to warn)
- What if priority is outside 1-10 range? (Validation prevents invalid entries)
🎓 Expert Insight
In AI-native development, you don't test by hand 50 times—you test strategically. Your AI can help generate test cases: "What edge cases should I test for a todo app?" Then you verify each one systematically. Notice how we validate dates using
datetime.strptime—this is where you delegate format checking to the standard library rather than writing regex patterns.
Project Deliverables
Your complete application should consist of:
-
Main Application File (e.g.,
todo_app.pyormain.py)- Imports all necessary modules (pathlib, json, datetime)
- Defines BASE_DIR and TASKS_FILE paths
- Initializes data file
- Implements all CRUD functions
- Implements menu loop with input validation
- Has
if __name__ == "__main__"guard withmain()call
-
Data Directory (
tasks/)- Automatically created when app runs
- Contains
tasks.jsonfile - Stores all tasks as JSON array
-
Working Features - All of these must function:
- Menu displays correctly and accepts valid input
- Create task saves to JSON file with all fields
- Read task loads and displays from file
- Update task modifies file and saves changes
- Delete task removes from file after confirmation
- Mark complete toggles done flag
- Search finds tasks by keyword
- List displays tasks sorted by priority
- Exit closes app gracefully
Success Criteria Checklist
Your application is complete when:
- ✅ Application runs without crashing on valid input
- ✅ All CRUD operations work correctly
- ✅ User input is validated (menu choices, required fields, date format, priority range)
- ✅ Tasks persist between sessions (data saved to JSON files)
- ✅ Search finds tasks by keyword in title or description
- ✅ Application handles errors gracefully (missing files, corrupted JSON, invalid input)
- ✅ Code is organized with functions for each operation
- ✅ Application supports 10-50 tasks at responsive speed
- ✅ Menu returns to top after each operation
- ✅ Date fields serialize correctly to/from ISO format strings
- ✅ Task status and done fields track state correctly
Try With AI
Build a production-ready todo data management application integrating all Chapter 25 I/O concepts. Focus on data persistence, JSON serialization, and error handling.
🔍 Explore Data Persistence Architecture:
"Design a todo app that persists tasks to JSON. Explain: single file vs file-per-task trade-offs, how to serialize/deserialize date strings in ISO format, JSON structure with id/title/description/due_date/priority/status/done fields, how to load all tasks on startup vs lazy loading, error handling for corrupted JSON, and how context managers ensure file operations complete safely."
What you're learning: Understanding how applications balance simplicity (single JSON file) with scalability (multiple files or databases). You'll see why ISO date format strings work better than datetime objects in JSON.
🎯 Practice CRUD with Date Handling:
"Implement todo CRUD: Create task with ISO date validation (YYYY-MM-DD), Read with context managers and JSON parsing, Update by task ID lookup, Delete with confirmation. Handle FileNotFoundError (first run), JSONDecodeError (corrupted file), ValueError (invalid date format), and show user-friendly error messages for each."
What you're learning: Building robust applications that anticipate errors and recover gracefully. Notice how we validate dates using datetime.strptime before storing—this prevents invalid dates in the JSON.
🧪 Test Persistence and Edge Cases:
"Handle edge cases: corrupted JSON (skip with warning and reset), Ctrl+C during save (context manager ensures cleanup), 100+ tasks in JSON (still fast for small lists), concurrent app instances (warning about data conflicts), past due dates (accept but could warn), and international task titles (ensure_ascii=False in json.dump)."
What you're learning: Production-quality applications anticipate failures and user mistakes. The context manager pattern (with open(...) as f:) ensures files close properly even if errors occur mid-operation.
🚀 Apply Complete Integration:
"Build full todo app: menu with 8 options (Create/Read/Update/Delete/Mark Complete/Search/List/Exit), single tasks.json file storage, ISO date serialization, priority levels (1-10 scale), task status tracking (pending/in_progress/completed), search filtering, timestamp validation, user input validation throughout, error handling for all file/format errors, and reflection showing how Chapter 25 concepts (pathlib, JSON, context managers, exception handling) integrate into working software."
What you're learning: How professional applications are built by combining foundational concepts (file I/O, JSON, paths, validation) into coherent systems. Each piece serves a purpose: pathlib for cross-platform paths, JSON for structured data, context managers for resource cleanup, exception handling for resilience.
Congratulations! You've completed the Todo Data Manager capstone, integrating all I/O concepts from Chapter 25. Your application demonstrates professional-level CLI development using Python 3.14+, pathlib, JSON serialization, file I/O, menu-driven interaction, and proper error handling. Your implementation proves you understand not just the "how" but the "why" of each design decision. You're now ready to extend this pattern to larger applications with databases, and ready for Chapter 27+ (object-oriented programming with Task classes, etc.).