chore: initial project scaffold
Set up IdeaForge project structure with documentation, architecture spec, and development guidelines for both backend (Python) and frontend (Flutter).
This commit is contained in:
69
.gitignore
vendored
Normal file
69
.gitignore
vendored
Normal file
@@ -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/
|
||||||
361
CLAUDE.md
Normal file
361
CLAUDE.md
Normal file
@@ -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<List<IdeaEntity>> build() async {
|
||||||
|
return ref.read(ideaRepositoryProvider).getIdeas();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<List<IdeaEntity>> getIdeas({String? status, String? category});
|
||||||
|
Future<IdeaEntity> getIdea(int id);
|
||||||
|
Future<EvaluationResult> triggerEvaluation(int id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// data/repositories/api_idea_repository.dart (implementation)
|
||||||
|
class ApiIdeaRepository implements IdeaRepository {
|
||||||
|
ApiIdeaRepository({required this.client});
|
||||||
|
final Dio client;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<IdeaEntity>> 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
|
||||||
14
changelog.md
Normal file
14
changelog.md
Normal file
@@ -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
|
||||||
154
docs/architecture.md
Normal file
154
docs/architecture.md
Normal file
@@ -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
|
||||||
122
readme.md
Normal file
122
readme.md
Normal file
@@ -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.
|
||||||
Reference in New Issue
Block a user