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

12 KiB

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

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 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"