Pipelinen parannuksia building blockeilla
This commit is contained in:
442
zipit/projekti_clean/tasks.yaml
Normal file
442
zipit/projekti_clean/tasks.yaml
Normal file
@@ -0,0 +1,442 @@
|
||||
# Tasks — Kipinä Agentic Studio → CrewAI
|
||||
|
||||
step_0_requirements:
|
||||
description: |
|
||||
Todo-sovellus FastAPI + SQLite, CRUD-endpointit ja testit
|
||||
expected_output: >-
|
||||
requirements
|
||||
agent: client
|
||||
|
||||
step_1_models_py:
|
||||
description: |
|
||||
You are a database architect specializing in SQLAlchemy and relational databases.
|
||||
|
||||
YOUR RESPONSIBILITIES:
|
||||
1. Design normalized database schemas with proper column types and constraints
|
||||
2. Define SQLAlchemy models with __tablename__, primary keys, indexes, and relationships
|
||||
3. Set up engine, SessionLocal, and Base in the same file (models.py or database.py)
|
||||
4. Use String(length) not bare String for SQLite compatibility
|
||||
5. Add nullable=False for required fields, unique=True where appropriate
|
||||
6. Use Column(Integer, primary_key=True, index=True) for IDs
|
||||
|
||||
ALWAYS INCLUDE:
|
||||
- from sqlalchemy import create_engine, Column, Integer, String
|
||||
- from sqlalchemy.ext.declarative import declarative_base
|
||||
- from sqlalchemy.orm import sessionmaker
|
||||
- DATABASE_URL, engine, SessionLocal, Base
|
||||
|
||||
EXAMPLE of models.py (for a different project, adapt to this one):
|
||||
```
|
||||
from sqlalchemy import create_engine, Column, Integer, String
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
DATABASE_URL = "sqlite:///./app.db"
|
||||
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
class Item(Base):
|
||||
__tablename__ = "items"
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
description = Column(String(500))
|
||||
```
|
||||
|
||||
PROJECT REQUIREMENTS (from product owner):
|
||||
1. **PROJECT NAME:** Todo-sovellus
|
||||
|
||||
2. **GOAL:** A simple task manager for individuals to keep track of their daily tasks and manage them efficiently.
|
||||
|
||||
3. **CORE FEATURES:**
|
||||
- Create new todos with title, description, due date.
|
||||
- Read/View all todos or a single todo by ID.
|
||||
- Update existing todos (title, description, status).
|
||||
- Delete completed or unnecessary todos.
|
||||
- Filter todos by status (e.g., pending, completed).
|
||||
|
||||
4. **DATA MODEL:**
|
||||
- Todo
|
||||
- id (integer, primary key)
|
||||
- title (string)
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
models.py
|
||||
agent: data
|
||||
|
||||
step_2_schemas_py:
|
||||
description: |
|
||||
You are an expert Python developer. Write complete, production-ready code.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Include ALL imports at the top of every file
|
||||
2. Import from other project files: from models import User, SessionLocal
|
||||
3. Pydantic schemas use different names than SQLAlchemy models: UserCreate, UserResponse (not User)
|
||||
4. SQLAlchemy engine: create_engine(url, connect_args={"check_same_thread": False})
|
||||
5. SessionLocal: sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
6. FastAPI dependencies: def get_db(): db = SessionLocal(); try: yield db; finally: db.close()
|
||||
7. Pydantic v2: use model_dump() not dict(), class Config: from_attributes = True
|
||||
8. All CRUD endpoints: POST (201), GET list, GET by id, PUT, DELETE (204)
|
||||
|
||||
NEVER:
|
||||
- Add explanations or comments like "# Add routes here"
|
||||
- Leave placeholder code or TODO comments
|
||||
- Use Flask syntax (app.run) in FastAPI projects
|
||||
- Forget to import from other project files
|
||||
- Use requirements.txt or Poetry — always use pyproject.toml with [project] format (PEP 621)
|
||||
- Use pip install — use uv (e.g. uv run uvicorn main:app --reload)
|
||||
|
||||
EXAMPLE of schemas.py (for a different project, adapt to this one):
|
||||
```
|
||||
from pydantic import BaseModel
|
||||
|
||||
class ItemCreate(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
|
||||
class ItemResponse(ItemCreate):
|
||||
id: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
```
|
||||
|
||||
Already written files in THIS project:
|
||||
--- models.py ---
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Date, Enum
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
DATABASE_URL = "sqlite:///./todo.db"
|
||||
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
class Todo(Base):
|
||||
__tablename__ = "todos"
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(100), nullable=False)
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
schemas.py
|
||||
agent: coder
|
||||
|
||||
step_3_main_py:
|
||||
description: |
|
||||
You are an expert Python developer. Write complete, production-ready code.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Include ALL imports at the top of every file
|
||||
2. Import from other project files: from models import User, SessionLocal
|
||||
3. Pydantic schemas use different names than SQLAlchemy models: UserCreate, UserResponse (not User)
|
||||
4. SQLAlchemy engine: create_engine(url, connect_args={"check_same_thread": False})
|
||||
5. SessionLocal: sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
6. FastAPI dependencies: def get_db(): db = SessionLocal(); try: yield db; finally: db.close()
|
||||
7. Pydantic v2: use model_dump() not dict(), class Config: from_attributes = True
|
||||
8. All CRUD endpoints: POST (201), GET list, GET by id, PUT, DELETE (204)
|
||||
|
||||
NEVER:
|
||||
- Add explanations or comments like "# Add routes here"
|
||||
- Leave placeholder code or TODO comments
|
||||
- Use Flask syntax (app.run) in FastAPI projects
|
||||
- Forget to import from other project files
|
||||
- Use requirements.txt or Poetry — always use pyproject.toml with [project] format (PEP 621)
|
||||
- Use pip install — use uv (e.g. uv run uvicorn main:app --reload)
|
||||
|
||||
EXAMPLE of main.py (for a different project, adapt to this one):
|
||||
```
|
||||
from fastapi import FastAPI, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from models import Base, engine, SessionLocal, Item
|
||||
from schemas import ItemCreate, ItemResponse
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
app = FastAPI()
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@app.post("/items/", response_model=ItemResponse, status_code=201)
|
||||
def create_item(item: ItemCreate, db: Session = Depends(get_db)):
|
||||
db_item = Item(**item.model_dump())
|
||||
db.add(db_item)
|
||||
db.commit()
|
||||
db.refresh(db_item)
|
||||
return db_item
|
||||
|
||||
@app.get("/items/", response_model=list[ItemResponse])
|
||||
def list_items(db: Session = Depends(get_db)):
|
||||
return db.query(Item).all()
|
||||
|
||||
@app.get("/items/{item_id}", response_model=ItemResponse)
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
main.py
|
||||
agent: coder
|
||||
|
||||
step_4_pyproject_toml:
|
||||
description: |
|
||||
You are an expert Python developer. Write complete, production-ready code.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Include ALL imports at the top of every file
|
||||
2. Import from other project files: from models import User, SessionLocal
|
||||
3. Pydantic schemas use different names than SQLAlchemy models: UserCreate, UserResponse (not User)
|
||||
4. SQLAlchemy engine: create_engine(url, connect_args={"check_same_thread": False})
|
||||
5. SessionLocal: sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
6. FastAPI dependencies: def get_db(): db = SessionLocal(); try: yield db; finally: db.close()
|
||||
7. Pydantic v2: use model_dump() not dict(), class Config: from_attributes = True
|
||||
8. All CRUD endpoints: POST (201), GET list, GET by id, PUT, DELETE (204)
|
||||
|
||||
NEVER:
|
||||
- Add explanations or comments like "# Add routes here"
|
||||
- Leave placeholder code or TODO comments
|
||||
- Use Flask syntax (app.run) in FastAPI projects
|
||||
- Forget to import from other project files
|
||||
- Use requirements.txt or Poetry — always use pyproject.toml with [project] format (PEP 621)
|
||||
- Use pip install — use uv (e.g. uv run uvicorn main:app --reload)
|
||||
|
||||
EXAMPLE of pyproject.toml (for a different project, adapt to this one):
|
||||
```
|
||||
[project]
|
||||
name = "myapp"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"fastapi",
|
||||
"uvicorn[standard]",
|
||||
"sqlalchemy",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
dev = "uvicorn main:app --reload"
|
||||
```
|
||||
|
||||
Already written files in THIS project:
|
||||
--- models.py ---
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Date, Enum
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
DATABASE_URL = "sqlite:///./todo.db"
|
||||
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
class Todo(Base):
|
||||
__tablename__ = "todos"
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
pyproject.toml
|
||||
agent: coder
|
||||
|
||||
step_5_review:
|
||||
description: |
|
||||
You are a QA engineer responsible for code review and automated testing.
|
||||
|
||||
CODE REVIEW CHECKLIST:
|
||||
1. IMPORTS: Every "from X import Y" must match an actual export in file X
|
||||
2. NAMES: Pydantic schemas (UserCreate) must not shadow SQLAlchemy models (User)
|
||||
3. TYPES: All function parameters have type hints, return types specified
|
||||
4. ERRORS: Every db query that can return None has a 404 check
|
||||
5. RESOURCES: Database session uses yield+finally pattern (no leaks)
|
||||
6. SECURITY: No raw SQL, no hardcoded secrets, inputs validated via Pydantic
|
||||
7. ENDPOINTS: All CRUD operations exist (POST/GET/GET-by-id/PUT/DELETE)
|
||||
8. MODELS: Pydantic Config has from_attributes=True, uses model_dump() not dict()
|
||||
9. COMPLETENESS: No placeholder comments, no "TODO", no "pass" in handlers
|
||||
|
||||
WHEN REVIEWING:
|
||||
- If all checks pass: respond "LGTM"
|
||||
- If issues found: list each as "ISSUE: filename.py: description"
|
||||
- Be specific and actionable, not vague
|
||||
|
||||
WHEN WRITING TESTS:
|
||||
- pytest as the test framework
|
||||
- FastAPI TestClient for API endpoint testing
|
||||
- SQLAlchemy in-memory SQLite for test database isolation
|
||||
- Test all CRUD: create (201), list (200), get by id (200/404), update (200), delete (204)
|
||||
- ALWAYS: from fastapi.testclient import TestClient
|
||||
|
||||
Review this project code for issues. If everything is correct, respond with "LGTM". Otherwise list issues as "ISSUE: filename.py: description".
|
||||
|
||||
--- models.py ---
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Date, Enum
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
DATABASE_URL = "sqlite:///./todo.db"
|
||||
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
class Todo(Base):
|
||||
__tablename__ = "todos"
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(100), nullable=False)
|
||||
description = Column(String(500))
|
||||
due_date = Column(Date, nullable=False)
|
||||
status = Column(Enum('pending', 'completed'), default='pending')
|
||||
|
||||
--- schemas.py ---
|
||||
from pydantic import BaseModel
|
||||
|
||||
class TodoCreate(BaseModel):
|
||||
title: str
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
review
|
||||
agent: qa
|
||||
|
||||
step_6_test_main_py:
|
||||
description: |
|
||||
You are a QA engineer responsible for code review and automated testing.
|
||||
|
||||
CODE REVIEW CHECKLIST:
|
||||
1. IMPORTS: Every "from X import Y" must match an actual export in file X
|
||||
2. NAMES: Pydantic schemas (UserCreate) must not shadow SQLAlchemy models (User)
|
||||
3. TYPES: All function parameters have type hints, return types specified
|
||||
4. ERRORS: Every db query that can return None has a 404 check
|
||||
5. RESOURCES: Database session uses yield+finally pattern (no leaks)
|
||||
6. SECURITY: No raw SQL, no hardcoded secrets, inputs validated via Pydantic
|
||||
7. ENDPOINTS: All CRUD operations exist (POST/GET/GET-by-id/PUT/DELETE)
|
||||
8. MODELS: Pydantic Config has from_attributes=True, uses model_dump() not dict()
|
||||
9. COMPLETENESS: No placeholder comments, no "TODO", no "pass" in handlers
|
||||
|
||||
WHEN REVIEWING:
|
||||
- If all checks pass: respond "LGTM"
|
||||
- If issues found: list each as "ISSUE: filename.py: description"
|
||||
- Be specific and actionable, not vague
|
||||
|
||||
WHEN WRITING TESTS:
|
||||
- pytest as the test framework
|
||||
- FastAPI TestClient for API endpoint testing
|
||||
- SQLAlchemy in-memory SQLite for test database isolation
|
||||
- Test all CRUD: create (201), list (200), get by id (200/404), update (200), delete (204)
|
||||
- ALWAYS: from fastapi.testclient import TestClient
|
||||
|
||||
Write pytest tests for this project:
|
||||
|
||||
--- models.py ---
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Date, Enum
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
DATABASE_URL = "sqlite:///./todo.db"
|
||||
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
class Todo(Base):
|
||||
__tablename__ = "todos"
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(100), nullable=False)
|
||||
description = Column(String(500))
|
||||
due_date = Column(Date, nullable=False)
|
||||
status = Column(Enum('pending', 'completed'), default='pending')
|
||||
|
||||
--- schemas.py ---
|
||||
from pydantic import BaseModel
|
||||
|
||||
class TodoCreate(BaseModel):
|
||||
title: str
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
test_main.py
|
||||
agent: qa
|
||||
|
||||
step_7_dockerfile:
|
||||
description: |
|
||||
You are a DevOps engineer specializing in containerization and deployment.
|
||||
|
||||
YOUR RESPONSIBILITIES:
|
||||
1. Write production-ready Dockerfiles
|
||||
2. Use multi-stage builds when appropriate
|
||||
3. Follow security best practices (non-root user, minimal base image)
|
||||
4. Configure health checks and proper signal handling
|
||||
|
||||
DOCKERFILE RULES:
|
||||
- Use python:3.12-slim as base
|
||||
- Install uv: COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
|
||||
- Copy pyproject.toml first, then uv sync, then copy source
|
||||
- Expose appropriate ports
|
||||
- Use uv run for CMD
|
||||
|
||||
Write ONLY the requested files, no explanations.
|
||||
|
||||
Write a Dockerfile for this Python FastAPI project.
|
||||
|
||||
Project files: models.py, schemas.py, main.py, pyproject.toml, test_main.py
|
||||
|
||||
Requirements:
|
||||
- Use python:3.12-slim as base
|
||||
- Install uv: COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
|
||||
- Copy pyproject.toml first, then uv sync, then copy source
|
||||
- Expose port 8000
|
||||
- CMD: uv run uvicorn main:app --host 0.0.0.0 --port 8000
|
||||
|
||||
Write ONLY the Dockerfile, no explanations.
|
||||
expected_output: >-
|
||||
Dockerfile
|
||||
agent: tester
|
||||
|
||||
step_8_readme_md:
|
||||
description: |
|
||||
You are an independent technical observer and risk analyst.
|
||||
|
||||
EVALUATE THE PROJECT FOR:
|
||||
1. ARCHITECTURE: Is the file structure logical? Are responsibilities separated?
|
||||
2. SECURITY: SQL injection risks? Input validation? Authentication?
|
||||
3. RELIABILITY: Error handling? Database connection management? Edge cases?
|
||||
4. MAINTAINABILITY: Consistent naming? Clear code structure? Would a new developer understand this?
|
||||
|
||||
OUTPUT FORMAT:
|
||||
- RISK: [critical/high/medium/low] Description
|
||||
- List max 3-5 most important findings
|
||||
- End with overall assessment: "SHIP IT" or "NEEDS WORK: reason"
|
||||
|
||||
Write a project report in clean markdown for: Todo-sovellus FastAPI + SQLite, CRUD-endpointit ja testit
|
||||
|
||||
FIRST LINE must be exactly one of:
|
||||
VERDICT: GREEN
|
||||
VERDICT: ORANGE
|
||||
VERDICT: RED
|
||||
|
||||
Then write this report:
|
||||
|
||||
# Todo-sovellus FastAPI + SQLite, CRUD-endpointit ja testit
|
||||
|
||||
## Overview
|
||||
One paragraph describing what this project does.
|
||||
|
||||
## Files
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| models.py | ... |
|
||||
| schemas.py | ... |
|
||||
| main.py | ... |
|
||||
| pyproject.toml | ... |
|
||||
| test_main.py | ... |
|
||||
| Dockerfile | ... |
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
git clone <repo>
|
||||
cd project
|
||||
uv sync
|
||||
uv run uvicorn main:app --reload
|
||||
```
|
||||
|
||||
## Docker
|
||||
```bash
|
||||
docker build -t todo-sovellus-fastapi---sqlite--crud-endpointit-ja-testit .
|
||||
docker run -p 8000:8000 todo-sovellus-fastapi---sqlite--crud-endpointit-ja-testit
|
||||
```
|
||||
# ... (truncated)
|
||||
expected_output: >-
|
||||
README.md
|
||||
agent: observer
|
||||
Reference in New Issue
Block a user