Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Testing
.coverage
.pytest_cache/
htmlcov/

# Virtual environments
venv/
env/
ENV/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db
25 changes: 25 additions & 0 deletions APPROACH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Approach: Spec-Driven Development with AI

## Process

- Wrote detailed feature and API specs before coding
- Used AI code generation to accelerate model, logic, and test creation
- Committed after each major step for traceability
- Maintained TODO.md for proposals and hygiene

## AI Tools Used

- Claude Sonnet 4.5: For code, tests, and documentation generation
- Claude Sonnet 4.5: For planning, refactoring, and spec enforcement

## Time Saved

- Model and endpoint scaffolding: ~70%
- Test generation: ~80%
- Documentation: ~60%

## Notes

- All code and tests are human-reviewed
- No external dependencies or secrets used
- 100% local reproducibility
84 changes: 44 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,47 @@
# Candidate Assessment: Spec-Driven Development With Codegen Tools

This assessment evaluates how you use modern code generation tools (for example `5.2-Codex`, `Claude`, `Copilot`, and similar) to design, build, and test a software application using a spec-driven development pattern. You may build a frontend, a backend, or both.

## Goals
- Build a working application with at least one meaningful feature.
- Create a testing framework to validate the application.
- Demonstrate effective use of code generation tools to accelerate delivery.
- Show clear, maintainable engineering practices.

## Deliverables
- Application source code in this repository.
- A test suite and test harness that can be run locally.
- Documentation that explains how to run the app and the tests.

## Scope Options
Pick one:
- Frontend-only application.
- Backend-only application.
- Full-stack application.

Your solution should include at least one real workflow, for example:
- Create and view a resource.
- Search or filter data.
- Persist data in memory or storage.

## Rules
- You must use a code generation tool (for example `5.2-Codex`, `Claude`, or similar). You can use multiple tools.
- You must build the application and a testing framework for it.
- The application and tests must run locally.
- Do not include secrets or credentials in this repository.

## Evaluation Criteria
- Working product: Does the app do what it claims?
- Test coverage: Do tests cover key workflows and edge cases?
- Engineering quality: Clarity, structure, and maintainability.
- Use of codegen: How effectively you used tools to accelerate work.
- Documentation: Clear setup and run instructions.

## What to Submit
# Transaction Categorizer API

A FastAPI backend that automatically categorizes financial transactions using rule-based keyword matching.

## Features

- Create, list, filter, and delete transactions
- Auto-categorization into 6 categories
- In-memory storage (no database required)
- 100% test coverage with pytest

## Setup

1. Clone the repo and switch to the project directory:
```sh
git clone <repo-url>
cd spec-driven-development
```
2. Create a virtual environment (Python 3.9+):
```sh
python3 -m venv venv
source venv/bin/activate
```
3. Install dependencies:
```sh
pip install -r requirements.txt
```

## Running the App

```sh
uvicorn app.main:app --reload
```

## Running Tests

```sh
pytest --cov=app
```

## API Reference

See SPECS/api-spec.md for full API contract.

- When you are complete, put up a Pull Request against this repository with your changes.
- A short summary of your approach and tools used in your PR submission
- Any additional information or approach that helped you.
20 changes: 0 additions & 20 deletions RULES.md

This file was deleted.

60 changes: 60 additions & 0 deletions SPECS/api-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# API Spec: Transaction Categorizer API

## Endpoints

### POST /transactions

- Description: Create a new transaction with auto-categorization
- Request Body (application/json):
- description: string (1-500 chars, required)
- amount: float (positive, required)
- date: string (YYYY-MM-DD, required)
- Response 201 (application/json):
- id: string (UUID)
- description: string
- amount: float
- date: string (YYYY-MM-DD)
- category: string (one of: dining, groceries, transportation, entertainment, utilities, other)
- created_at: string (ISO 8601 datetime)
- Response 422: Validation error

### GET /transactions

- Description: List all transactions, optionally filter by category
- Query Params:
- category: string (optional, one of the 6 categories)
- Response 200 (application/json):
- transactions: array of transaction objects (sorted by date desc)

### GET /transactions/{id}

- Description: Get a transaction by UUID
- Response 200 (application/json):
- transaction object
- Response 404: Not found

### DELETE /transactions/{id}

- Description: Delete a transaction by UUID
- Response 204: No content
- Response 404: Not found

### GET /transactions/summary

- Description: Get spending totals by category
- Response 200 (application/json):
- summary: object {category: total_amount}

## Status Codes

- 201 Created
- 200 OK
- 204 No Content
- 400 Bad Request
- 404 Not Found
- 422 Unprocessable Entity

## Error Response Format

- application/json:
- detail: string (error message)
47 changes: 41 additions & 6 deletions SPECS/feature-template.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
# Feature Spec: <Feature Name>
# Feature Spec: Automatic Transaction Categorization

## Goal
-

Automatically categorize financial transactions based on description keywords to help users understand spending patterns.

## Scope
- In:
- Out:

### In:

- Create transactions with auto-assigned categories
- List and filter transactions by category
- Delete transactions
- View spending summary by category
- Rule-based keyword matching for 6 categories
- In-memory storage

### Out:

- Machine learning categorization
- User-defined custom categories
- Database persistence
- Authentication/authorization
- Transaction editing/updating
- Bulk import/export

## Requirements
-

- Transactions must have: description (1-500 chars), amount (positive), date (ISO format)
- Categories: dining, groceries, transportation, entertainment, utilities, other
- Categorization is case-insensitive keyword matching
- "other" is the default when no keywords match
- Transactions sorted by date (most recent first)
- All inputs validated with clear error messages

## Acceptance Criteria
- [ ]

- [x] POST /transactions creates transaction and assigns correct category
- [x] GET /transactions returns all transactions sorted by date
- [x] GET /transactions?category=X filters by category
- [x] GET /transactions/{id} returns specific transaction
- [x] GET /transactions/{id} returns 404 for non-existent ID
- [x] DELETE /transactions/{id} removes transaction
- [x] GET /transactions/summary returns totals by category
- [x] Invalid inputs return 422 with descriptive errors
- [x] Empty/whitespace descriptions are rejected
- [x] Negative amounts are rejected
- [x] Invalid dates are rejected
- [x] All tests pass with 97% coverage
45 changes: 45 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Manual Testing Guide

## Using curl

### Create Transaction

```
curl -X POST http://localhost:8000/transactions \
-H 'Content-Type: application/json' \
-d '{"description": "Starbucks coffee", "amount": 4.5, "date": "2023-12-01"}'
```

### List Transactions

```
curl http://localhost:8000/transactions
```

### Filter by Category

```
curl http://localhost:8000/transactions?category=dining
```

### Get Transaction by ID

```
curl http://localhost:8000/transactions/<id>
```

### Delete Transaction

```
curl -X DELETE http://localhost:8000/transactions/<id>
```

### Get Summary

```
curl http://localhost:8000/transactions/summary
```

## Using Postman

Import postman_collection.json for ready-to-use requests.
7 changes: 0 additions & 7 deletions TODO.md

This file was deleted.

2 changes: 2 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# app/__init__.py
# Marks the app directory as a Python package.
27 changes: 27 additions & 0 deletions app/categorizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Rule-based categorization logic for financial transactions.
"""
from typing import Dict, List

CATEGORY_KEYWORDS: Dict[str, List[str]] = {
"dining": ["starbucks", "restaurant", "cafe", "mcdonald", "burger", "pizza", "chipotle", "dunkin"],
"groceries": ["walmart", "grocery", "supermarket", "whole foods", "kroger", "aldi", "safeway", "costco"],
"transportation": ["uber", "lyft", "taxi", "bus", "train", "metro", "shell", "exxon", "chevron", "bp"],
"entertainment": ["netflix", "movie", "cinema", "theater", "spotify", "concert", "amc", "hulu", "disney"],
"utilities": ["electric", "water", "gas", "utility", "comcast", "verizon", "at&t", "internet", "pg&e"],
}

DEFAULT_CATEGORY = "other"


def categorize_transaction(description: str) -> str:
"""
Categorize a transaction based on its description using keyword matching.
Returns one of the 6 categories.
"""
desc = description.lower()
for category, keywords in CATEGORY_KEYWORDS.items():
for kw in keywords:
if kw in desc:
return category
return DEFAULT_CATEGORY
Loading