commit 1fa9804be5f9d1f34a0ae4c92361c7b24917da38 Author: Kai Chappell Date: Wed Jan 28 22:13:52 2026 +0000 chore: initial project scaffold Set up IdeaForge project structure with documentation, architecture spec, and development guidelines for both backend (Python) and frontend (Flutter). diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27a386f --- /dev/null +++ b/.gitignore @@ -0,0 +1,69 @@ +# python +__pycache__/ +*.py[cod] +*$py.class +*.egg-info/ +*.egg +dist/ +build/ +.eggs/ +*.whl + +# virtual environments +.venv/ +venv/ +ENV/ + +# uv +uv.lock + +# database +*.db +*.sqlite3 +data/ + +# testing +.coverage +htmlcov/ +.pytest_cache/ +coverage.xml + +# mypy +.mypy_cache/ + +# ruff +.ruff_cache/ + +# environment +.env +.env.local + +# flutter +frontend/.dart_tool/ +frontend/.packages +frontend/.pub-cache/ +frontend/.pub/ +frontend/build/ +frontend/.flutter-plugins +frontend/.flutter-plugins-dependencies + +# code generation +frontend/**/*.g.dart +frontend/**/*.freezed.dart + +# editor +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# os +.DS_Store +Thumbs.db + +# docker +*.log + +# evaluation batches (local data) +evaluation_batches/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9919d05 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,361 @@ +# CLAUDE.md + +Guidelines for working on IdeaForge. + +## Project Overview + +IdeaForge is a full-stack idea management platform: a Flutter Web/Mobile client backed by +a Python API with integrated AI evaluation. The backend extends the existing idea-manager +project with Claude API integration and a public demo mode. + +## Project Stack + +### Backend (Python) + +- **Language:** Python 3.11+ +- **Package Manager:** uv +- **API Framework:** FastAPI 0.115+ with uvicorn +- **ORM:** SQLAlchemy 2.0+ (async) with aiosqlite +- **Database:** SQLite (file-based) +- **Validation:** Pydantic 2.10+, pydantic-settings +- **Logging:** structlog (JSON structured logs) +- **Linting:** ruff (lint + format) +- **Type Checking:** mypy (strict) +- **Testing:** pytest, pytest-asyncio, pytest-cov, httpx +- **AI Integration:** Anthropic Python SDK (Claude API) + +### Frontend (Flutter) + +- **Language:** Dart 3.6+ / Flutter 3.27+ +- **Architecture:** Feature-First with Riverpod +- **State Management:** Riverpod 3.1+ (generator syntax) +- **Navigation:** GoRouter +- **HTTP Client:** dio +- **Charts:** fl_chart (radar/spider charts for metric scores) +- **Testing:** flutter_test, mocktail +- **Linting:** flutter analyze (zero issues including info-level) + +## Commands + +### Backend + +```bash +cd backend/ +uv sync # Install dependencies +uv run alembic upgrade head # Run migrations +uv run ideaforge serve # Start API server +uv run pytest --cov=src/ideaforge # Tests (target: ≥80%) +uv run ruff check . # Linting (must return ZERO issues) +uv run ruff format --check . # Format check (ZERO changes) +uv run mypy src/ # Type checking (must pass) +``` + +### Frontend + +```bash +cd frontend/ +flutter pub get # Install dependencies +dart run build_runner build --delete-conflicting-outputs # Code generation +flutter test --coverage # Tests (target: ≥85%) +flutter analyze # Must return ZERO issues +dart format . # Must produce ZERO changes +flutter build web # Web build +``` + +## Architecture + +### Directory Structure + +``` +ideaforge/ +├── backend/ # Python API +│ ├── src/ideaforge/ +│ │ ├── __init__.py +│ │ ├── main.py # FastAPI app entry point +│ │ ├── config.py # Pydantic settings +│ │ ├── database.py # DB engine, session factory +│ │ ├── dependencies.py # FastAPI dependency injection +│ │ ├── exceptions.py # Custom exception hierarchy +│ │ ├── logging.py # structlog configuration +│ │ ├── models/ # SQLAlchemy ORM models +│ │ ├── schemas/ # Pydantic request/response schemas +│ │ ├── services/ # Business logic layer +│ │ ├── api/ # FastAPI routers +│ │ └── ai/ # Claude API integration +│ │ ├── client.py # Anthropic SDK wrapper +│ │ ├── prompts.py # Evaluation prompt templates +│ │ └── evaluator.py # AI evaluation orchestration +│ ├── alembic/ # Database migrations +│ ├── tests/ +│ ├── pyproject.toml +│ └── alembic.ini +│ +├── frontend/ # Flutter app +│ ├── lib/ +│ │ ├── main.dart +│ │ ├── src/ +│ │ │ ├── core/ # Shared utilities, theme, errors +│ │ │ ├── features/ +│ │ │ │ ├── ideas/ # Idea listing and filtering +│ │ │ │ │ ├── domain/ +│ │ │ │ │ ├── data/ +│ │ │ │ │ └── presentation/ +│ │ │ │ ├── evaluation/ # AI evaluation and scoring +│ │ │ │ │ ├── domain/ +│ │ │ │ │ ├── data/ +│ │ │ │ │ └── presentation/ +│ │ │ │ └── dashboard/ # Overview and charts +│ │ │ │ └── presentation/ +│ │ │ └── shared/ # Cross-feature widgets +│ │ └── app.dart # App root with providers and router +│ ├── test/ +│ ├── web/ +│ └── pubspec.yaml +│ +├── docs/ +├── readme.md +├── changelog.md +└── docker-compose.yml # Local development (API + DB) +``` + +### Layer Responsibilities (Backend) + +| Layer | Purpose | Dependencies | +|-------|---------|--------------| +| **models/** | SQLAlchemy ORM models | SQLAlchemy only | +| **schemas/** | Pydantic request/response validation | Pydantic only | +| **services/** | Business logic, orchestration | models, schemas | +| **ai/** | Claude API integration, prompt management | Anthropic SDK, schemas | +| **api/** | HTTP routing, request handling | services, schemas | + +**Critical:** Services NEVER import from api/. API depends on services, not the reverse. + +### Layer Responsibilities (Frontend) + +| Layer | Purpose | Dependencies | +|-------|---------|--------------| +| **domain/** | Entities, repository interfaces | None (pure Dart) | +| **data/** | DTOs, API client, repository implementations | dio, domain | +| **presentation/** | Controllers, views, widgets | Riverpod, domain | + +**Critical:** Domain layer has zero external dependencies. Data implements domain interfaces. + +## Code Patterns + +### Backend — Error Handling + +Custom exceptions inherit from a base class. Services raise domain exceptions, API routes +convert them to HTTP responses via exception handlers. + +```python +class IdeaForgeError(Exception): + def __init__(self, message: str, detail: str | None = None): + self.message = message + self.detail = detail + super().__init__(message) + +class NotFoundError(IdeaForgeError): ... +class EvaluationError(IdeaForgeError): ... +class AIServiceError(IdeaForgeError): ... +``` + +### Backend — Logging (structlog) + +Every service method logs entry, success, and failure with context. + +```python +import structlog + +logger = structlog.get_logger(__name__) + +async def evaluate_idea(self, idea_id: int) -> Evaluation: + logger.info("evaluating_idea", idea_id=idea_id) + try: + result = await self._run_evaluation(idea_id) + logger.info("idea_evaluated", idea_id=idea_id, score=result.score) + return result + except Exception as e: + logger.error("evaluation_failed", idea_id=idea_id, error=str(e)) + raise +``` + +Never use `print()`. Always include context parameters. + +### Backend — AI Integration + +```python +from anthropic import AsyncAnthropic + +class EvaluationService: + def __init__(self, session: AsyncSession, ai_client: AsyncAnthropic): + self.session = session + self.ai_client = ai_client + + async def run_ai_evaluation(self, idea_id: int) -> list[MetricScore]: + idea = await self._get_idea(idea_id) + prompt = build_evaluation_prompt(idea) + response = await self.ai_client.messages.create( + model="claude-sonnet-4-20250514", + max_tokens=4096, + messages=[{"role": "user", "content": prompt}], + ) + return parse_evaluation_response(response) +``` + +### Frontend — Riverpod Controller + +```dart +@riverpod +class IdeasController extends _$IdeasController { + @override + Future> build() async { + return ref.read(ideaRepositoryProvider).getIdeas(); + } + + Future refresh() async { + state = const AsyncLoading(); + state = await AsyncValue.guard( + () => ref.read(ideaRepositoryProvider).getIdeas(), + ); + } +} +``` + +### Frontend — Repository Pattern + +```dart +// domain/repositories/idea_repository.dart (interface) +abstract class IdeaRepository { + Future> getIdeas({String? status, String? category}); + Future getIdea(int id); + Future triggerEvaluation(int id); +} + +// data/repositories/api_idea_repository.dart (implementation) +class ApiIdeaRepository implements IdeaRepository { + ApiIdeaRepository({required this.client}); + final Dio client; + + @override + Future> getIdeas({String? status, String? category}) async { + final response = await client.get('/api/ideas', queryParameters: { + if (status != null) 'status': status, + if (category != null) 'category': category, + }); + return (response.data as List) + .map((json) => IdeaDto.fromJson(json).toEntity()) + .toList(); + } +} +``` + +## Import Ordering + +### Python + +Use ruff import sorting (isort-compatible): + +1. Standard library +2. Third-party packages +3. Local imports + +Always use absolute imports from package root. + +### Dart + +All imports in one section, sorted alphabetically, no blank lines between: + +```dart +import 'package:flutter/material.dart'; +import 'package:ideaforge/src/core/errors/failures.dart'; +import 'package:ideaforge/src/features/ideas/ideas.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +``` + +Always use package imports, never relative. + +## Type Safety + +### Python + +All functions must have complete type hints. Use modern syntax (Python 3.11+): + +```python +def process(items: list[str]) -> dict[str, int]: ... +def get_user(user_id: int | None = None) -> User | None: ... +``` + +### Dart + +Avoid `dynamic`. Prefer explicit types on public APIs. Use `required` for named parameters +that must be provided. + +## Testing + +### Backend + +```python +@pytest.mark.asyncio +async def test_evaluate_idea(client: AsyncClient): + response = await client.post("/api/ideas/1/evaluate") + assert response.status_code == 200 + data = response.json() + assert "scores" in data +``` + +### Frontend + +```dart +testWidgets('shows idea list', (tester) async { + await tester.pumpWidget( + ProviderScope( + overrides: [ideaRepositoryProvider.overrideWithValue(mockRepo)], + child: const MaterialApp(home: IdeasScreen()), + ), + ); + expect(find.text('Test Idea'), findsOneWidget); +}); +``` + +## Git + +- **Repo:** https://gitea.kschappell.com/kschappell/ideaforge +- **Branch:** main +- See workspace CLAUDE.md for commit format and signing requirements + +## Demo Mode + +The deployed instance runs in demo mode: + +- Seeded with 15-20 curated ideas across 3-4 domains +- Write operations disabled for anonymous users +- AI evaluation rate-limited (prevent abuse) +- Data resets periodically + +Configuration via environment variable: `IDEAFORGE_DEMO_MODE=true` + +## Pre-Completion Checklist + +Before marking ANY task complete: + +**Backend:** +- [ ] `uv run ruff check .` returns 0 issues +- [ ] `uv run ruff format --check .` returns 0 changes +- [ ] `uv run mypy src/` passes +- [ ] `uv run pytest` passes +- [ ] All new functions have complete type hints +- [ ] All new service methods have structlog logging +- [ ] All new exceptions inherit from `IdeaForgeError` +- [ ] No `print()` statements + +**Frontend:** +- [ ] `flutter analyze` returns 0 issues +- [ ] `dart format .` returns 0 changes +- [ ] `flutter test` passes +- [ ] New features have at least one widget test +- [ ] No AI/LLM references anywhere in the codebase + +**Both:** +- [ ] changelog.md updated +- [ ] Commit is signed +- [ ] Commit message follows `type(scope): description` format diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..f4c6ab9 --- /dev/null +++ b/changelog.md @@ -0,0 +1,14 @@ +# changelog + +All notable changes to IdeaForge. + +Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Initial project scaffold +- Project documentation (readme, CLAUDE.md, changelog) +- Backend and frontend directory structure diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..00a127b --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,154 @@ +# architecture + +## Overview + +IdeaForge is a dual-stack application: a Python FastAPI backend with SQLite storage and +Claude API integration, fronted by a Flutter Web/Mobile client. + +## System Context + +``` +┌──────────────────┐ ┌──────────────────┐ +│ Flutter Client │────────▶│ FastAPI Backend │ +│ (Web / Mobile) │◀────────│ │ +└──────────────────┘ └────────┬─────────┘ + │ + ┌───────────┼───────────┐ + │ │ │ + ┌───────▼──┐ ┌────▼─────┐ ┌──▼──────────┐ + │ SQLite │ │ Claude │ │ Seed Data │ + │ (ideas.db)│ │ API │ │ (Curated) │ + └──────────┘ └──────────┘ └─────────────┘ +``` + +## Backend Architecture + +### Layers + +``` +API Layer (FastAPI Routers) + │ + ▼ +Service Layer (Business Logic) + │ + ├──▶ AI Module (Claude API Client) + │ + ▼ +Data Layer (SQLAlchemy Models + Pydantic Schemas) + │ + ▼ +Database (SQLite via aiosqlite) +``` + +**Rules:** +- Services never import from API layer +- API and CLI both depend on services +- AI module is a peer of services, injected as needed +- All database access goes through SQLAlchemy async sessions + +### Key Modules + +| Module | Responsibility | +|--------|---------------| +| `api/ideas.py` | CRUD endpoints for ideas | +| `api/evaluations.py` | Evaluation endpoints (manual + AI) | +| `services/idea_service.py` | Idea business logic, filtering, ranking | +| `services/evaluation_service.py` | Evaluation orchestration | +| `ai/client.py` | Anthropic SDK wrapper | +| `ai/evaluator.py` | Prompt construction, response parsing | +| `ai/prompts.py` | Evaluation prompt templates | + +### AI Evaluation Flow + +``` +Client triggers evaluation + │ + ▼ +POST /api/ideas/{id}/ai-evaluate + │ + ▼ +EvaluationService.run_ai_evaluation(idea_id) + │ + ├──▶ Load idea + metrics from DB + ├──▶ Build evaluation prompt (ai/prompts.py) + ├──▶ Call Claude API (ai/client.py) + ├──▶ Parse structured response (ai/evaluator.py) + ├──▶ Store scores in DB + │ + ▼ +Return evaluation results with scores + reasoning +``` + +### Demo Mode + +When `IDEAFORGE_DEMO_MODE=true`: + +- Database seeded with curated ideas on startup +- Write endpoints return 403 for unauthenticated requests +- AI evaluation rate-limited (N requests per hour per IP) +- Data resets on restart (ephemeral SQLite) + +## Frontend Architecture + +### Feature-First Structure + +Each feature is self-contained with domain/data/presentation layers: + +``` +features/ +├── ideas/ +│ ├── domain/ # IdeaEntity, IdeaRepository (interface) +│ ├── data/ # IdeaDto, ApiIdeaRepository +│ └── presentation/ # IdeasController, IdeasScreen, IdeaCard +│ +├── evaluation/ +│ ├── domain/ # EvaluationEntity, MetricScore +│ ├── data/ # EvaluationDto, ApiEvaluationRepository +│ └── presentation/ # EvaluationController, ScoreRadarChart +│ +└── dashboard/ + └── presentation/ # DashboardScreen, RankingTable +``` + +### State Management + +Riverpod providers manage all state: + +- `ideasControllerProvider` — idea list with filters +- `ideaDetailProvider(id)` — single idea with evaluations +- `evaluationControllerProvider` — AI evaluation trigger and results + +### Key Screens + +| Screen | Path | Purpose | +|--------|------|---------| +| Ideas List | `/ideas` | Browse and filter ideas | +| Idea Detail | `/ideas/:id` | Full idea with scores and radar chart | +| Evaluate | `/ideas/:id/evaluate` | Trigger and view AI evaluation | +| Dashboard | `/dashboard` | Rankings and comparisons | + +## Database Schema + +Core tables (inherited from idea-manager): + +- `ideas` — idea content (title, description, status, category) +- `evaluation_metrics` — metric definitions with scoring guides +- `idea_evaluations` — scores linking ideas to metrics +- `tags` / `idea_tags` — tagging system + +## Deployment + +``` +┌──────────────┐ ┌──────────────┐ +│ Flutter Web │ │ FastAPI │ +│ (Static CDN) │────▶│ (Container) │ +└──────────────┘ └──────┬───────┘ + │ + ┌───────▼───────┐ + │ SQLite Volume │ + └───────────────┘ +``` + +- Backend: Docker container on Fly.io / Railway +- Frontend: Static Flutter Web build on CDN +- Database: SQLite file on persistent volume diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..9fb79c4 --- /dev/null +++ b/readme.md @@ -0,0 +1,122 @@ +# ideaforge + +A full-stack idea management platform with AI-powered evaluation. Browse, filter, and +evaluate software project ideas using quantitative metrics and automated AI scoring. + +## Architecture + +IdeaForge is a dual-stack project: + +- **Backend:** Python API (FastAPI) with SQLite storage and Claude API integration +- **Frontend:** Flutter Web/Mobile client with radar charts and real-time evaluation + +``` +┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ +│ Flutter Client │────▶│ FastAPI │────▶│ Claude API │ +│ (Web / Mobile) │◀────│ Backend │◀────│ (Evaluation)│ +└─────────────────┘ └────────┬────────┘ └──────────────┘ + │ + ┌────────▼────────┐ + │ SQLite │ + │ (ideas.db) │ + └─────────────────┘ +``` + +## Features + +- **Idea browsing** — Filter by status, category, and tags +- **Metric scoring** — 8 quantitative evaluation metrics (feasibility, market potential, + uniqueness, personal interest, learning value, time to MVP, monetisation, maintenance) +- **AI evaluation** — Trigger Claude API to score ideas against all metrics with reasoning +- **Score visualisation** — Radar/spider charts showing metric profiles +- **Comparison** — Side-by-side idea comparison with aggregate rankings +- **Demo mode** — Public instance with curated ideas (read-only, rate-limited AI) + +## Stack + +### Backend + +| Component | Technology | +|-----------|-----------| +| API Framework | FastAPI 0.115+ | +| ORM | SQLAlchemy 2.0+ (async) | +| Database | SQLite + aiosqlite | +| Validation | Pydantic 2.10+ | +| AI | Anthropic Python SDK | +| Logging | structlog | +| Migrations | Alembic | +| Package Manager | uv | + +### Frontend + +| Component | Technology | +|-----------|-----------| +| Framework | Flutter 3.27+ | +| State | Riverpod 3.1+ | +| Navigation | GoRouter | +| HTTP | dio | +| Charts | fl_chart | + +## Getting Started + +### Backend + +```bash +cd backend/ +uv sync +uv run alembic upgrade head +uv run ideaforge db init +uv run ideaforge serve +``` + +API available at [http://localhost:8000](http://localhost:8000). +Docs at [http://localhost:8000/docs](http://localhost:8000/docs). + +### Frontend + +```bash +cd frontend/ +flutter pub get +dart run build_runner build --delete-conflicting-outputs +flutter run -d chrome +``` + +## Configuration + +Backend configuration via environment variables: + +| Variable | Default | Description | +|----------|---------|-------------| +| `IDEAFORGE_DATABASE_URL` | `sqlite+aiosqlite:///data/ideas.db` | Database path | +| `IDEAFORGE_HOST` | `127.0.0.1` | API host | +| `IDEAFORGE_PORT` | `8000` | API port | +| `IDEAFORGE_ANTHROPIC_API_KEY` | — | Claude API key (required for AI eval) | +| `IDEAFORGE_DEMO_MODE` | `false` | Enable demo mode (read-only, rate-limited) | +| `IDEAFORGE_LOG_LEVEL` | `INFO` | Log level | +| `IDEAFORGE_LOG_FORMAT` | `json` | Log format (`json` or `console`) | + +## Testing + +```bash +# Backend +cd backend/ +uv run pytest --cov=src/ideaforge + +# Frontend +cd frontend/ +flutter test --coverage +``` + +## Relationship to idea-manager + +IdeaForge extends the [idea-manager](https://gitea.kschappell.com/kschappell/idea-manager) +project. The backend shares the same data model and evaluation framework, adding: + +- Claude API integration for automated evaluation +- Demo mode for public deployment +- Optimised API endpoints for the Flutter client +- Docker deployment configuration + +## License + +All rights reserved. Kai Chappell.