Files
agentic-studio/zipit/projekti_clean/prompts/8_observer_readme.md.md
2026-04-12 18:48:14 +03:00

405 lines
12 KiB
Markdown

# 8 — Observer (observer) — README.md
**Malli:** `qwen-coder`
## System Prompt
```
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"
```
## Syöte
```
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
```
## API Endpoints
| Method | Path | Description |
|--------|------|-------------|
| POST | /items/ | Create |
| GET | /items/ | List all |
| GET | /items/{id} | Get by ID |
| PUT | /items/{id} | Update |
| DELETE | /items/{id} | Delete |
(Adapt paths and descriptions to match the actual code)
## Architecture
Describe the project structure and design decisions.
## Risk Assessment
| Severity | Issue |
|----------|-------|
| ... | ... |
Project code:
--- 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
description: str | None = None
due_date: date
status: str = 'pending'
class TodoResponse(TodoCreate):
id: int
class Config:
from_attributes = True
--- main.py ---
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from models import Base, engine, SessionLocal, Todo
from schemas import TodoCreate, TodoResponse
Base.metadata.create_all(bind=engine)
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/todos/", response_model=TodoResponse, status_code=201)
def create_todo(todo: TodoCreate, db: Session = Depends(get_db)):
db_todo = Todo(**todo.model_dump())
db.add(db_todo)
db.commit()
db.refresh(db_todo)
return db_todo
@app.get("/todos/", response_model=list[TodoResponse])
def list_todos(status: str | None = None, db: Session = Depends(get_db)):
if status:
query = db.query(Todo).filter_by(status=status)
else:
query = db.query(Todo)
return query.all()
@app.get("/todos/{todo_id}", response_model=TodoResponse)
def get_todo(todo_id: int, db: Session = Depends(get_db)):
todo = db.query(Todo).filter(Todo.id == todo_id).first()
if not todo:
raise HTTPException(status_code=404, detail="Not found")
return todo
@app.put("/todos/{todo_id}", response_model=TodoResponse)
def update_todo(todo_id: int, todo: TodoCreate, db: Session = Depends(get_db)):
db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
if not db_todo:
raise HTTPException(status_code=404, detail="Not found")
for key, value in todo.model_dump().items():
setattr(db_todo, key, value)
db.commit()
db.refresh(db_todo)
return db_todo
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
if not db_todo:
raise HTTPException(status_code=404, detail="Not found")
db.delete(db_todo)
db.commit()
--- pyproject.toml ---
[project]
name = "todo-sovellus"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"fastapi",
"uvicorn[standard]",
"sqlalchemy",
]
[project.scripts]
dev = "uvicorn main:app --reload"
--- test_main.py ---
from fastapi.testclient import TestClient
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:///./test_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')
Base.metadata.create_all(bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
app = FastAPI()
@app.post("/todos/", response_model=Todo, status_code=201)
def create_todo(todo: TodoCreate, db: Session = Depends(get_db)):
db_todo = Todo(**todo.model_dump())
db.add(db_todo)
db.commit()
db.refresh(db_todo)
return db_todo
@app.get("/todos/", response_model=list[Todo])
def list_todos(status: str | None = None, db: Session = Depends(get_db)):
if status:
query = db.query(Todo).filter_by(status=status)
else:
query = db.query(Todo)
return query.all()
@app.get("/todos/{todo_id}", response_model=Todo)
def get_todo(todo_id: int, db: Session = Depends(get_db)):
todo = db.query(Todo).filter(Todo.id == todo_id).first()
if not todo:
raise HTTPException(status_code=404, detail="Not found")
return todo
@app.put("/todos/{todo_id}", response_model=Todo)
def update_todo(todo_id: int, todo: TodoCreate, db: Session = Depends(get_db)):
db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
if not db_todo:
raise HTTPException(status_code=404, detail="Not found")
for key, value in todo.model_dump().items():
setattr(db_todo, key, value)
db.commit()
db.refresh(db_todo)
return db_todo
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
db_todo = db.query(Todo).filter(Todo.id == todo_id).first()
if not db_todo:
raise HTTPException(status_code=404, detail="Not found")
db.delete(db_todo)
db.commit()
client = TestClient(app)
def test_create_todo():
response = client.post("/todos/", json={"title": "Test Todo", "description": "This is a test todo.", "due_date": "2023-12-31"})
assert response.status_code == 201
data = response.json()
assert "id" in data
assert data["title"] == "Test Todo"
assert data["description"] == "This is a test todo."
assert data["due_date"] == "2023-12-31"
assert data["status"] == "pending"
def test_list_todos():
response = client.get("/todos/")
assert response.status_code == 200
data = response.json()
assert len(data) > 0
def test_get_todo_by_id():
todo_id = create_test_todo().json()["id"]
response = client.get(f"/todos/{todo_id}")
assert response.status_code == 200
data = response.json()
assert "id" in data
assert data["title"] == "Test Todo"
def test_get_nonexistent_todo():
response = client.get("/todos/999")
assert response.status_code == 404
def test_update_todo():
todo_id = create_test_todo().json()["id"]
response = client.put(f"/todos/{todo_id}", json={"title": "Updated Todo"})
assert response.status_code == 200
data = response.json()
assert "id" in data
assert data["title"] == "Updated Todo"
def test_delete_todo():
todo_id = create_test_todo().json()["id"]
response = client.delete(f"/todos/{todo_id}")
assert response.status_code == 204
def create_test_todo():
return client.post("/todos/", json={"title": "Test Todo", "description": "This is a test todo.", "due_date": "2023
--- Dockerfile ---
# Stage 1: Build
FROM python:3.12-slim as builder
WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir poetry && \
poetry config virtualenvs.create false && \
poetry install --no-interaction --no-ansi
COPY models.py schemas.py main.py test_main.py .
# Stage 2: Production
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local/share/python-poetry/cache /root/.local/share/python-poetry/cache
COPY --from=builder /app /app
RUN useradd -m appuser && \
chown -R appuser:appuser /app
USER appuser
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
EXPOSE 8000
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
## Tulos
```
VERDICT: GREEN
## Overview
This project is a simple Todo application using FastAPI for the backend and SQLite as the database. It includes CRUD endpoints for managing tasks.
## Files
| File | Purpose |
|------|---------|
| models.py | Defines the data model for the todo items using SQLAlchemy ORM. |
| schemas.py | Contains Pydantic schemas for validating request and response data. |
| main.py | The FastAPI application, defining routes and business logic. |
| pyproject.toml | Project metadata and dependencies. |
| test_main.py | Unit tests for the FastAPI endpoints. |
| Dockerfile | Docker configuration to build and run the application. |
## Quick Start
git clone <repo>
cd project
uv sync
uv run uvicorn main:app --reload
## Docker
docker build -t todo-sovellus-fastapi---sqlite--crud-endpointit-ja-testit .
docker run -p 8000:8000 todo-sovellus-fastapi---sqlite--crud-endpointit-ja-testit
## API Endpoints
| Method | Path | Description |
|--------|------|-------------|
| POST | /todos/ | Create a new todo item. |
| GET | /todos/ | List all todos or filter by status. |
| GET | /todos/{id} | Retrieve a specific todo item by ID. |
| PUT | /todos/{id} | Update an existing todo item. |
| DELETE | /todos/{id} | Delete a todo item. |
## Architecture
The project follows a clean separation of concerns:
- **models.py**: Defines the data model using SQLAlchemy ORM.
- **schemas.py**: Contains Pydantic models for data validation and serialization.
- **main.py**: Implements FastAPI routes, business logic, and database interactions.
This logical structure makes it easy to understand and maintain each component independently.
## Risk Assessment
| Severity | Issue |
|----------|-------|
| LOW | The project uses parameterized queries in the SQLAlchemy ORM which helps prevent SQL injection. However, input validation is minimal (e.g., no checks for `due_date` format). |
| MEDIUM | Error handling and database connection management are basic but adequate. Database connections are managed via context managers, which ensures proper closure of sessions. |
| LOW | The project uses consistent naming conventions for variables and functions, making the code easy to understand. However, there's room for improving documentation around API endpoints and models. |
Overall assessment: "SHIP IT"
```