A comprehensive French language learning platform built end-to-end with Mistral Vibe and Mistral API, combining immersive AI conversation practice with structured grammar lessons, a searchable reference guide, and interactive exercises.
Users start at a modern central navigation hub that provides access to all application features. From there, they can:
Conversation Practice: Select a scenario (e.g., ordering at a café, asking for directions, job interview in French), then conduct an immersive conversation entirely in French with an AI tutor. At the end of the session, they receive a structured feedback report scoring their grammar, vocabulary, and fluency, with one prioritized focus area for improvement.
Grammar Mastery: Study through:
- Grammar Lessons: 20+ interactive lessons covering core French grammar topics
- Grammar Reference Guide: 50+ searchable reference entries for quick lookup of grammar terms and concepts
- Grammar Exercises: 5 interactive exercises with 5 types (fill-in-the-blank, multiple-choice, translation, conjugation, sentence transformation) for practicing grammar skills
The landing page also features a Quick Access section showing recent sessions with resume capability.
- Explore Features: The landing page displays cards for all major features - click any to get started
- Start Conversation Practice: Click "Conversation Practice" or "Get Started" to select from 10 built-in scenarios
- Browse Grammar Lessons: Click "Grammar Lessons" to browse, search, and filter 20+ interactive lessons
- Search Grammar Reference: Click "Grammar Reference" to access 50+ searchable reference entries
- Practice Exercises: Click "Grammar Exercises" to practice with fill-in-the-blank, multiple-choice, translation, conjugation, and sentence transformation exercises
- Resume Recent Session: Use the Quick Access section to resume any of your last 5 sessions
- Select a Scenario: Choose from 10 built-in conversation scenarios
- Select Difficulty: Choose your difficulty level (Beginner, Intermediate, or Advanced) to tailor the AI's responses to your proficiency
- Start Chatting: Type messages in French and get responses from the AI tutor
- End Session: Click "End Session" to receive detailed feedback
- Review Feedback: See scores for grammar, vocabulary, fluency, and overall performance with specific corrections
- Review Session Details: Navigate to
/sessions/{id}to view full conversation transcript alongside feedback - Navigate Back: Use the Back button to return to scenario selection or start a new session
Each scenario supports three difficulty levels that affect the AI's system prompt:
- Beginner: Simpler vocabulary, slower pace, more helpful hints
- Intermediate: Standard prompts (default, backward compatible)
- Advanced: More complex vocabulary, faster pace, native idioms and expressions
- Ordering at a Café - Practice ordering coffee and pastries
- Asking for Directions - Navigate Parisian landmarks
- Job Interview - Software engineering interview simulation
- Hotel Check-in - Check into a hotel and ask about amenities
- Shopping for Clothes - Shop and try on clothes
- Doctor's Visit - Describe symptoms and get medical advice
- Train Travel - Buy tickets and check schedules
- Dining at a Restaurant - Order a full meal
- Apartment Rental - Negotiate and ask about rentals
- Museum Visit - Ask about exhibits and tickets
- Central Navigation Hub: Modern landing page with feature cards for all application functionality and Quick Access to recent sessions
- Conversation Practice: AI stays strictly in character and responds only in French
- Session Management: Conversation history stored in SQLite with resume capability
- Structured Feedback: Grammar, vocabulary, and fluency scores with example corrections and explanations
- Session Detail View: Full conversation transcript alongside feedback
- Clean, Responsive Interface: Single-page application with modern UI/UX
- Grammar Lessons: 20+ interactive lessons covering core French grammar topics (Phase 2)
- Grammar Reference Guide: 50+ searchable reference entries for quick lookup of grammar terms and concepts (Phase 2)
- Grammar Exercises: 5 interactive exercises with 5 types: fill-in-the-blank, multiple-choice, translation, conjugation, and sentence transformation (Phase 2)
- Real-time answer validation with immediate feedback
- Score tracking across exercise sessions
- Filterable by type, topic, and difficulty level
- Vocabulary Flashcards: Interactive flashcard component with flip animation for vocabulary study (Phase 3, Issue #69)
- Click/tap to flip between French (front) and English + example (back)
- Swipe gesture support for mobile devices
- Smooth CSS flip animation
- Spaced Repetition Review: ReviewSession component for managing vocabulary card reviews (Phase 3, Issue #69)
- Fetch and display cards due for review using SM-2 spaced repetition algorithm
- Rating buttons: Again (1), Hard (2), Good (3), Easy (4) for SM-2 algorithm
- Progress tracking through review session
- Session summary with rating distribution statistics
- Auto-advance to next card after rating submission
-
Clone the repository and navigate to the project directory:
cd french-language-coach -
Create a virtual environment (recommended):
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install backend dependencies:
pip install -r requirements.txt
-
Set up the frontend (React SPA):
cd frontend npm install cd ..
-
Create a
.envfile from the template:cp .env.example .env
-
Get a Mistral API key from https://console.mistral.ai/ and add it to
.env:MISTRAL_API_KEY=your_api_key_here -
Run the backend server:
uvicorn main:app --reload
-
In a separate terminal, start the frontend development server:
cd frontend npm run dev -
Open your browser to http://localhost:5173 (Vite dev server with HMR)
To run Storybook for component development:
-
In a separate terminal, start Storybook:
cd frontend npm run storybook -
Open your browser to http://localhost:6006 to view component documentation
Alternative (Production Mode):
- Build the frontend:
cd frontend npm run build - Run the backend server (serves the built React app from /static):
uvicorn main:app
- Open your browser to http://localhost:8000
- Backend: Python + FastAPI
- Frontend: React 19 + TypeScript + Vite, React Router v6
- Storybook: Component documentation at http://localhost:6006
- Database: SQLite via SQLAlchemy (async)
- AI: Mistral API (model:
mistral-large-latest) - Package management: pip + requirements.txt (backend), npm (frontend)
The application follows a clean separation of concerns with the following layers:
┌──────────────────────────────────────────────────────────────┐
│ Frontend (React SPA) │
│ React 19 + TypeScript + Vite + React Router v6 │
│ Storybook for component documentation │
│ ┌───────────────┐ ┌────────────────┐ ┌──────────────┐ │
│ │ pages/ │ │ components/ │ │ hooks/ │ │
│ │ - Route comps│ │ - UI comps │ │ - Custom │ │
│ │ │ │ - Stories │ │ hooks │ │
│ └───────────────┘ └────────────────┘ └──────────────┘ │
│ ┌───────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ utils/ │ │ types/ │ │ .storybook/ │ │
│ │ - API client │ │ - TS types │ │ - Config │ │
│ │ - Mocks │ │ │ │ │ │
│ └───────────────┘ └──────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ FastAPI Backend │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ routers/ │ │ services/ │ │ models/ │ │
│ │ - REST API │──▶│ - Mistral │──▶│ - Sessions │ │
│ │ - Endpoints │ │ - Chat │ │ - Messages │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ schemas/ │ │ scenarios.py │ │
│ │ - Pydantic │ │ - Prompts │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌─────────────────────────────┐
│ SQLite Database │ │ Mistral API (External) │
│ - Session storage │ │ - Chat completions │
│ - JSON fields │ │ - Feedback generation │
│ │ │ │
└─────────────────────────-┘ └─────────────────────────────┘
french-language-coach/
├── main.py # FastAPI app entry point, mounts static files, includes routers
├── config.py # Settings loaded from .env (MISTRAL_API_KEY, DATABASE_URL)
├── database.py # SQLite + SQLAlchemy async engine and session setup
├── models/
│ ├── session.py # SQLAlchemy ORM model for a conversation session
│ ├── deck.py # SQLAlchemy ORM model for vocabulary decks (Phase 3)
│ ├── card.py # SQLAlchemy ORM model for vocabulary cards with spaced repetition (Phase 3)
│ └── card_review.py # SQLAlchemy ORM model for card review tracking (Issue #59, Phase 3)
├── schemas/
│ ├── session.py # Pydantic schemas for API request/response
│ ├── grammar_lesson.py # Pydantic models for grammar lesson validation (Phase 2)
│ ├── grammar_reference.py # Pydantic models for grammar reference entry validation (Phase 2)
│ ├── grammar_exercise.py # Pydantic models for grammar exercise validation (Phase 2)
│ ├── vocabulary_card.py # Pydantic models for vocabulary card schema (Issue #49, Phase 3)
│ ├── vocabulary.py # Pydantic schemas for vocabulary router endpoints (Phase 3)
│ └── card_review.py # Pydantic schemas for card review endpoints (Issue #59, Phase 3)
├── services/
│ └── mistral.py # Mistral API client: chat completion + feedback generation
├── routers/
│ ├── __init__.py
│ ├── sessions.py # POST /sessions (start), GET /sessions/{id}, DELETE /sessions/{id}
│ ├── messages.py # POST /sessions/{id}/messages (send a message, get AI reply)
│ ├── feedback.py # POST /sessions/{id}/feedback (generate end-of-session report)
│ ├── grammar.py # GET /grammar/lessons/, /grammar/reference/, /grammar/exercises/ endpoints (Phase 2)
│ ├── grammar_progress.py # GET /grammar/progress/, POST /grammar/progress/ endpoints (Phase 2)
│ ├── vocabulary.py # GET /vocabulary/decks/, POST /vocabulary/decks/, GET /vocabulary/decks/{id}/cards/, POST /vocabulary/review/, GET /vocabulary/due/ (Phase 3)
│ └── card_review.py # POST /card-review/ endpoint for spaced repetition tracking (Issue #59, Phase 3)
├── scenarios.py # Static list of 10 built-in conversation scenarios with system prompts
├── data/
│ ├── grammar_lessons/ # Grammar lesson JSON files for Phase 2 (20+ lessons)
│ ├── grammar/reference/ # Grammar reference entry JSON files for Phase 2 (50+ entries)
│ ├── grammar/exercises/ # Grammar exercise JSON files for Phase 2 (5 exercises: fill-in-the-blank, multiple-choice, translation, conjugation, sentence-transformation)
│ └── vocabulary_cards/ # Vocabulary card JSON files organized by thematic decks (Phase 3, Issue #51)
├── scripts/
│ ├── validate_grammar_lessons.py # Validation script for grammar lessons
│ └── validate_grammar_reference.py # Validation script for grammar reference entries
├── frontend/ # React SPA frontend (Vite + TypeScript)
│ ├── src/
│ │ ├── components/ # Reusable UI components + Storybook stories
│ │ │ ├── FeatureCard.tsx # Feature navigation card for landing page (Issue #177)
│ │ │ ├── FeatureCard.stories.tsx
│ │ │ ├── FeatureCard.test.tsx
│ │ │ ├── QuickAccessSession.tsx # Compact session card for landing page (Issue #177)
│ │ │ ├── QuickAccessSession.stories.tsx
│ │ │ ├── QuickAccessSession.test.tsx
│ │ │ ├── DifficultySelector.tsx
│ │ │ ├── DifficultySelector.stories.tsx
│ │ │ ├── DifficultySelector.test.tsx
│ │ │ ├── ChatInterface.tsx
│ │ │ ├── ChatInterface.stories.tsx
│ │ │ ├── FeedbackView.tsx
│ │ │ ├── FeedbackView.stories.tsx
│ │ │ ├── SessionDetail.tsx
│ │ │ ├── SessionDetail.stories.tsx
│ │ │ ├── ScenarioSelector.tsx
│ │ │ ├── ScenarioSelector.stories.tsx
│ │ │ ├── ChatHeader.tsx
│ │ │ ├── ChatHeader.stories.tsx
│ │ │ ├── MessageBubble.tsx
│ │ │ ├── MessageBubble.stories.tsx
│ │ │ ├── ScoreCard.tsx
│ │ │ ├── ScoreCard.stories.tsx
│ │ │ ├── CorrectionItem.tsx
│ │ │ ├── CorrectionItem.stories.tsx
│ │ │ ├── ScenarioCard.tsx
│ │ │ ├── ScenarioCard.stories.tsx
│ │ │ ├── LessonCard.tsx # Lesson card for browser (Phase 2)
│ │ │ ├── LessonCard.stories.tsx
│ │ │ ├── LessonSearch.tsx # Search/filter controls (Phase 2)
│ │ │ ├── LessonSearch.stories.tsx
│ │ │ ├── LessonBrowser.tsx # Main lessons browser (Phase 2)
│ │ │ ├── LessonBrowser.stories.tsx
│ │ │ ├── ReferenceSearch.tsx # Search and filter for grammar reference (Phase 2)
│ │ │ ├── ReferenceCard.tsx # Card component for reference entries (Phase 2)
│ │ │ ├── Exercise.tsx # Main exercise component (Phase 2)
│ │ │ ├── ExerciseTypes/ # Type-specific exercise components (Phase 2)
│ │ │ │ ├── FillInTheBlankExercise.tsx
│ │ │ │ ├── MultipleChoiceExercise.tsx
│ │ │ │ ├── TranslationExercise.tsx
│ │ │ │ ├── ConjugationExercise.tsx
│ │ │ │ └── SentenceTransformationExercise.tsx
│ │ │ ├── Flashcard.tsx # Vocabulary flashcard with flip animation (Phase 3, Issue #69)
│ │ │ ├── ReviewSession.tsx # Spaced repetition review session (Phase 3, Issue #69)
│ │ │ └── index.ts
│ │ ├── pages/ # Page-level components (React Router routes)
│ │ │ ├── IndexPage.tsx # Modern landing page with central navigation hub (Issue #177)
│ │ │ ├── ScenarioPage.tsx # Scenario selection interface (Issue #177)
│ │ │ ├── HomePage.tsx # Legacy scenario selection page (kept for backward compatibility)
│ │ │ ├── ChatPage.tsx
│ │ │ ├── FeedbackPage.tsx
│ │ │ ├── SessionDetailPage.tsx
│ │ │ ├── LessonPage.tsx # Grammar lessons browser (Phase 2)
│ │ │ ├── LessonDetailPage.tsx # Individual lesson viewer (Phase 2)
│ │ │ ├── ReferencePage.tsx # Grammar reference search page (Phase 2)
│ │ │ ├── ExerciseBrowserPage.tsx # Exercise listing/browsing page (Phase 2)
│ │ │ └── ExercisePage.tsx # Individual exercise page (Phase 2)
│ │ ├── hooks/ # Custom React hooks
│ │ │ ├── useSessions.tsx
│ │ │ └── index.ts
│ │ ├── utils/ # Utility functions
│ │ │ ├── api.ts
│ │ │ └── storybookMocks.tsx
│ │ ├── types/ # TypeScript type definitions
│ │ │ └── index.ts
│ │ ├── styles/ # CSS files
│ │ │ └── global.css
│ │ ├── .storybook/ # Storybook configuration
│ │ │ ├── main.ts
│ │ │ └── preview.tsx
│ │ ├── App.tsx # Main app with React Router
│ │ └── main.tsx # App entry point
│ ├── public/ # Static assets
│ ├── vite.config.ts # Vite configuration
│ ├── package.json # Frontend dependencies
│ ├── tsconfig.json # TypeScript configuration
│ └── README.md # Frontend setup documentation
├── static/ # Static files for development (will be replaced by React build in production)
│ ├── index.html # Legacy single-page app (development fallback)
│ ├── style.css # Legacy styles
│ └── app.js # Legacy frontend logic
├── .env.example # Template: MISTRAL_API_KEY=, DATABASE_URL=
├── .gitignore # Python, .env, __pycache__, *.db
├── requirements.txt # fastapi, uvicorn, sqlalchemy, aiosqlite, mistralai, python-dotenv, pydantic
├── tests/ # pytest tests for backend
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures and configuration
│ ├── test_scenarios.py # Tests for difficulty levels in scenarios
│ └── test_schemas.py # Tests for Pydantic schemas
└── README.md
| Method | Endpoint | Description |
|---|---|---|
| GET | /sessions/ |
List all sessions with pagination. Query parameters: page (default 1), per_page (default 10, max 100), scenario_id (filter by scenario), date_from (filter by start date), date_to (filter by end date), min_score (filter by minimum overall score). Returns summary: id, scenario_id, scenario_name, difficulty, created_at, ended_at, overall_score, is_locked, locked_at, locked_by |
| POST | /sessions/ |
Create a new conversation session. Optional difficulty parameter: beginner, intermediate (default), or advanced |
| GET | /sessions/{id} |
Get session details and messages. Returns difficulty field, is_locked, locked_at, locked_by |
| DELETE | /sessions/{id} |
Delete a session. Returns 204 on success, 404 if not found. Returns 400 if session is locked (prevents deletion of sessions in use) |
| POST | /sessions/{id}/lock |
Lock a session to prevent deletion while in use. Accepts optional X-Client-ID header for lock ownership. Auto-unlocks after 10 minutes (TTL). Returns lock status. |
| POST | /sessions/{id}/unlock |
Unlock a session to allow deletion. Requires matching X-Client-ID header unless lock has expired. Returns lock status. |
| POST | /sessions/{id}/messages |
Send a message, get AI reply. Uses session's difficulty level for system prompt |
| POST | /sessions/{id}/feedback |
Generate end-of-session feedback |
| GET | /grammar/lessons/ |
List all grammar lessons with pagination and filtering. Query parameters: page (default 1), per_page (default 10, max 100), topic (filter by grammatical topic), difficulty (filter by level: beginner, intermediate, advanced). Returns summary: id, title, topic, difficulty |
| GET | /grammar/lessons/{id} |
Get a specific grammar lesson by ID. Returns full lesson content including sections with titles, content, and examples. Returns 404 if lesson not found |
| GET | /grammar/reference/ |
Search grammar reference entries with pagination and filtering. Query parameters: page (default 1), per_page (default 10, max 100), q (search query - case-insensitive partial match on term, definition, examples, common_pitfalls), category (filter by grammatical category), difficulty (filter by level: beginner, intermediate, advanced). Returns full reference entries |
| GET | /grammar/progress/ |
List lesson progress records with optional filtering. Query parameters: lesson_id (filter by lesson ID), user_id (filter by user ID), completed (filter by completion status: true/false). Returns list of progress records with id, user_id, lesson_id, completed, score, last_accessed, time_spent, created_at, updated_at. user_id is nullable for Phase 1.5 |
| POST | /grammar/progress/ |
Record a new lesson progress entry. Required: lesson_id (string, e.g., "articles"). Optional: user_id (integer, nullable), completed (boolean, default false), score (integer 0-100, default 0), time_spent (integer seconds >=0, default 0). Returns 201 with created progress record. Returns 422 for invalid score (<0 or >100) or time_spent (<0). Validates: score must be 0-100, time_spent must be >=0 |
| GET | /grammar/exercises/ |
List grammar exercises with optional filtering and pagination. Query parameters: page (default 1), per_page (default 10, max 100), exercise_type (filter by type: fill-in-the-blank, multiple-choice, translation, conjugation, sentence-transformation), topic (filter by topic substring), difficulty (filter by level: beginner, intermediate, advanced). Returns paginated list of exercises with full content |
| GET | /grammar/exercises/{id} |
Get a specific grammar exercise by ID. Returns full exercise content including all type-specific fields. Returns 404 if exercise not found |
| GET | /vocabulary/decks/ |
List all vocabulary decks with pagination. Query parameters: page (default 1), per_page (default 10, max 1000). Returns list of decks with id, name, description, created_at, updated_at, card_count |
| GET | /vocabulary/decks/{id} |
Get a specific vocabulary deck by ID. Returns deck details including id, name, description, created_at, updated_at, card_count. Returns 404 if deck not found |
| POST | /vocabulary/decks/ |
Create a new vocabulary deck. Required: name. Optional: description. Returns 201 with created deck details |
| GET | /vocabulary/decks/{id}/cards/ |
List all cards in a specific deck with pagination. Query parameters: page (default 1), per_page (default 10, max 1000). Returns paginated list of cards with all fields including spaced repetition data |
| POST | /vocabulary/decks/{id}/cards/ |
Create a new card in a specific deck. Required: card_id, front, back. Optional: example, tags, context, difficulty (1-5, default 1). Initial spaced repetition values: interval=1, ease_factor=2.5, next_review_date=today+1. Returns 201 with created card details |
| POST | /vocabulary/review/ |
Submit a card review to update spaced repetition scheduling on the Card model. Required: card_id, deck_id, ease (1-4 where 1=Again, 2=Hard, 3=Good, 4=Easy). Uses SM-2 algorithm to calculate new interval and ease factor. Returns success status with next_review_date, new_interval, new_ease_factor |
| GET | /vocabulary/due/ |
Get all cards due for review (next_review_date <= today) with pagination. Query parameters: page (default 1), per_page (default 10, max 1000). Returns paginated list of due cards with id, deck_id, deck_name, card_id, front, back, next_review_date |
| POST | /card-review/ |
Submit a card review to track spaced repetition state in CardReview model (Issue #59). Required: card_id, rating (0-3 where 0=Fail/Again, 1=Hard, 2=Good, 3=Easy). Optional: user_id (nullable for Phase 1.5). Uses SM-2 algorithm with rating mapping. Returns success status with next_due_date, interval, ease_factor, reps, lapses |
| Path | Component | Description |
|---|---|---|
/ |
IndexPage | Modern landing page with central navigation hub (Issue #177) |
/scenarios |
ScenarioPage | Scenario selection interface |
/chat/:sessionId |
ChatPage | Interactive chat interface for a session |
/feedback/:sessionId |
FeedbackPage | Feedback report display for a completed session |
/sessions/:sessionId |
SessionDetailPage | Full session details with transcript and feedback |
/lessons |
LessonPage | Browse, search, and filter all grammar lessons (Phase 2) |
/lessons/:lessonId |
LessonDetailPage | View full content of a specific grammar lesson (Phase 2) |
/reference |
ReferencePage | Search and filter grammar reference entries (Phase 2) |
/exercises |
ExerciseBrowserPage | Browse and filter all grammar exercises (Phase 2) |
/exercises/:exerciseId |
ExercisePage | Practice a specific grammar exercise (Phase 2) |
/review |
ReviewSession | Start vocabulary card review session with spaced repetition (Phase 3, Issue #69) |
/vocabulary |
VocabularyPage | Browse all vocabulary decks (Phase 3, Issue #67) |
/vocabulary/decks/:deckId |
DeckDetailPage | View deck details, progress, and card preview (Phase 3, Issue #201) |
/vocabulary/decks/:deckId/cards |
DeckCardsPage | Browse all cards in a specific deck with pagination (Phase 3, Issue #201) |
- User selects scenario → POST /sessions/ creates session record
- User sends message → POST /sessions/{id}/messages/ → Mistral chat API → AI response stored in session
- User requests feedback → POST /sessions/{id}/feedback/ → Mistral chat API with feedback prompt → structured JSON feedback stored in session
- Frontend displays conversation history and feedback report
The application implements a session locking mechanism to prevent accidental deletion of sessions currently in use:
- Automatic Locking: Sessions are automatically locked when loaded in the ChatInterface (on mount)
- Automatic Unlocking: Sessions are automatically unlocked when the user leaves the ChatInterface (on unmount)
- Cross-Tab Safety: Locking works across browser tabs via backend state
- TTL Auto-Unlock: Abandoned locks automatically expire after 10 minutes to prevent deadlocks
- Delete Protection: Sessions can only be deleted when not locked (regardless of completion status)
- Continue Session: Incomplete sessions can be resumed from the SessionDetail view via "Continue Session" button
This allows users to:
- Delete incomplete sessions (previously blocked)
- Continue incomplete sessions from SessionDetail
- Prevent accidental deletion of sessions currently in use
The application integrates with the Mistral API in two key ways:
For each scenario, a system prompt instructs the model to:
- Respond only in French (never break into English)
- Stay in character as a native French speaker
- Use natural, authentic language
Example scenario prompt (from scenarios.py):
"Tu es un serveur/une serveuse natif(ve) dans un café parisien.
Réponds UNIQUEMENT en français. Reste absolument dans ton rôle..."
The conversation history (user + assistant messages) is sent to mistral-large-latest via the chat API, and the assistant's response is returned and stored.
When a user ends a session, the full conversation history is sent with a separate system prompt that instructs Mistral to analyze the conversation and return a strictly JSON response with this structure:
{
"grammar_score": 0-100,
"vocabulary_score": 0-100,
"fluency_score": 0-100,
"overall_score": 0-100,
"strengths": ["string", ...],
"focus_area": "string",
"example_corrections": [
{"original": "string", "corrected": "string", "explanation": "string"}
]
}The response_format={"type": "json_object"} parameter ensures Mistral returns valid JSON that can be directly parsed and stored in the database.
Mistral's models have demonstrably stronger French language quality than most alternatives. Mistral trains its models with native French fluency — giving Mistral Large demonstrated benchmark advantages in French language comprehension and generation compared to models trained primarily on English. For a French language coaching application, this is not a minor detail: it means more natural phrasing, better idiomatic corrections, and more culturally authentic conversation scenarios.
This project is also built entirely using Mistral Vibe, Mistral's AI-assisted coding environment, making it an end-to-end demonstration of the Mistral developer ecosystem.
| # | Source | Link | What It Indicates |
|---|---|---|---|
| 1 | Mistral AI Official Blog – "Au Large" | https://mistral.ai/news/mistral-large | Primary source from Mistral AI documenting native multilingual capacities and benchmark comparisons (HellaSwag, Arc Challenge, MMLU) vs. LLaMA 2 70B, Mixtral 8x7B in French, German, Spanish, and Italian. |
| 2 | Prompt Engineering Guide – Mistral Large | https://www.promptingguide.ai/models/mistral-large | Independent summary confirming Mistral Large outperforms Mixtral 8x7B and LLaMA 2 70B across all tested languages including French. Notes it falls behind GPT-4 on some tasks but leads comparable-tier models. |
| 3 | Built In – Mistral AI: Models, Capabilities and Latest Developments | https://builtin.com/articles/mistral-ai | Third-party technology publication confirming Mistral's native fluency in French, Spanish, German, and Italian, with a nuanced understanding of grammar and cultural context — contrasted with models that are only proficient in a single language. |
| 4 | Anthem Creation – Mistral Large vs. ChatGPT (Oct 2024) | https://anthemcreation.com/en/artificial-intelligence/mistral-large-cat-gpt-functioning-benefits-modele-francais/ | Documents Mistral Large's GLUE French reading comprehension score of 89.4 (top of evaluated French language models at time of publication) and notes it outperforms ChatGPT on French NLP tasks specifically. |
| 5 | Cocondesnèiges.fr – Mistral AI Review (Apr 2026) | https://cocondesneiges.fr/en/ai/mistral-ai-review/ | Recent (April 2026) independent review confirming superior French language quality vs. American competitors, noting more natural text with fewer anglicised phrasings. Also notes GPT-4o retains a slight edge on complex reasoning. |
This project was developed using Mistral Vibe, an AI coding agent that provides:
- Intelligent code generation and completion
- Context-aware suggestions based on the codebase
- Multi-file refactoring assistance
- Debugging and error resolution support
This project follows Structured Prompt Driven Development (SPDD) methodology as described by Wei Zhang and Jessie Jie Xia (hosted on Martin Fowler's website). SPDD provides a systematic approach to integrating AI coding assistants into the software development lifecycle while maintaining human oversight and quality standards.
SPDD aims to harness the productivity gains of AI coding assistance while mitigating risks through structured prompts, clear context boundaries, and human-in-the-loop validation. It ensures that AI-generated code aligns with project architecture, quality standards, and business requirements.
By adopting SPDD, we achieve:
- Consistency: AI assistance follows predictable patterns
- Quality: Structured prompts yield higher-quality outputs
- Maintainability: Clear documentation of AI interactions for future reference
- Traceability: Every AI-generated artifact has a clear lineage
The REASONS canvas (from the SPDD methodology) guides our AI-assisted development:
- Requirements: Clear acceptance criteria defined in each GitHub issue
- Examples: Concrete test cases and expected behaviors
- Architecture: Existing codebase structure and design patterns
- Standards: Coding conventions, testing requirements (80% coverage)
- Omissions: Explicitly out-of-scope items documented
- Notes: Implementation hints and context
- Solutions: Reference implementations and patterns
- Issue Definition: Each feature starts with a well-structured GitHub issue containing acceptance criteria
- Context Gathering: Agent reviews relevant code, documentation, and existing patterns
- Prompt Engineering: Structured prompts include: goal, constraints, examples, and validation criteria
- Iterative Development: Agent generates code, human reviews, refine, repeat
- Validation: All acceptance criteria verified, tests pass at 80%+ coverage
- Documentation: Code changes documented, reasoning captured
All AI-assisted development artifacts are captured in the spdd/ directory. This includes:
- Analysis Documents (
spdd/analysis/): Structured REASONS canvas analysis for each task - Prompt Documents (
spdd/prompt/): Exact prompts sent to AI assistants with context and constraints - Templates (
spdd/template/): Reusable templates for creating artifacts
This ensures:
- Traceability: Every AI-generated change can be traced to its source prompt
- Reproducibility: Prompts can be re-run to verify outputs
- Transparency: The development process is visible and auditable
- Knowledge Preservation: Design decisions and context are retained for future developers
See spdd/README.md for complete details on artifact structure and naming conventions.
Issue #46 - ReferenceSearch and Exercise Components:
- Analysis:
spdd/analysis/FLC-024-202606041500-[Analysis]-issue-46-reference-search-exercise.md - Prompt:
spdd/prompt/FLC-024-202606041530-[Feat]-issue-46-reference-search-exercise.md
Issue #69 - Flashcard and ReviewSession Components:
- Analysis:
spdd/analysis/FLC-039-202606161000-[Analysis]-issue-69-flashcard-review-session.md - Prompt:
spdd/prompt/FLC-039-202606161015-[Feat]-issue-69-flashcard-review-session.md
Note: We are currently using Mistral Vibe directly without the open-spdd utility. If we adopt open-spdd in the future, this workflow will be updated accordingly.
This project uses GitHub Flow with Issue-Based Branching: one dedicated branch per GitHub issue, created from main, merged back via Pull Request. All development follows this pattern for traceability and isolation.
- Branch naming:
{type}/issue-{number}-{description}(e.g.,feature/issue-42-grammar-lessons) - Workflow: Branch from
main→ Develop → PR tomain→ Review → Merge → Cleanup - Full documentation: See GIT-WORKFLOW.md for complete details including examples, worktree usage, and troubleshooting
- No user authentication
- Single-user only (all sessions stored in one database)
- Requires Mistral API key (paid service)
This project has test suites for both the backend and frontend components.
The backend uses pytest with pytest-asyncio for testing FastAPI endpoints, services, and schemas.
Prerequisites:
- Python virtual environment activated
- Backend dependencies installed (
pip install -r requirements.txt)
To run all backend tests:
pytestTo run with verbose output:
pytest -vTo run a specific test file:
pytest tests/test_sessions_listing.pyTo run with test coverage:
pytest --cov=. --cov-report=term-missingAvailable backend test files:
tests/test_scenarios.py- Tests for scenario difficulty levelstests/test_schemas.py- Tests for Pydantic schemastests/test_sessions_listing.py- Tests for session listing and filtering endpointstests/test_session_deletion.py- Tests for session deletion endpointtests/test_grammar_lesson_schema.py- Tests for grammar lesson schema (Issue #28)tests/test_grammar_lessons_issue_30.py- Tests for 20+ grammar lessons (Issue #30)tests/test_grammar_reference.py- Tests for 50+ grammar reference entries (Issue #32)tests/test_grammar_router.py- Tests for grammar router endpoints (Issue #36)tests/test_grammar_exercise_schema.py- Tests for grammar exercise schema (Issue #34, #46)tests/test_vocabulary_simple.py- Tests for vocabulary router endpoints (Issue #55)tests/test_card_review.py- Tests for card review model, schemas, and endpoint (Issue #59)
The frontend uses Vitest for most unit and component testing, and Jest for specific tests (e.g., MSW-related tests).
Prerequisites:
- Frontend dependencies installed (
cd frontend && npm install)
To run all frontend tests:
cd frontend
npm run testTo run tests with UI mode:
cd frontend
npm run test:uiTo run tests with coverage:
cd frontend
npm run test:coverageTo run Storybook interaction tests:
cd frontend
npm run test:storybookThe project also uses Jest for certain tests, particularly those involving MSW (Mock Service Worker).
To run Jest tests:
cd frontend
npm run test:jestTo run Jest tests with coverage:
cd frontend
npm run test:jest:coverageTo run Jest tests in watch mode:
cd frontend
npm run test:jest:watchNote: Frontend test scripts are defined in
frontend/package.json. If Vitest is not yet configured, you can add it with:cd frontend && npm install -D vitest @testing-library/react @testing-library/jest-domJest Coverage Note: Due to TypeScript compilation errors in some source files, Jest coverage collection currently excludes certain directories (styles, mocks, hooks, pages, utils, types, ExerciseTypes) and files (main.tsx, App.tsx, setupTests.ts, testSetup.ts). These exclusions are configured in
frontend/jest.config.cjsand can be reduced as TypeScript errors are fixed.
Available frontend test files:
frontend/src/sample.jest.test.tsx- Jest setup verification testsfrontend/src/components/Flashcard.jest.test.tsx- Tests for Flashcard component (Issue #69)frontend/src/components/ReviewSession.jest.test.tsx- Tests for ReviewSession component (Issue #69)
This project uses GitHub Actions for Continuous Integration with the following workflows:
- pytest-tests.yml - Runs backend pytest tests when backend files change
- jest-tests.yml - Runs frontend Jest tests when frontend files change
- vitest-tests.yml - Runs frontend Vitest tests when frontend files change
- cypress-tests.yml - Runs end-to-end Cypress tests when frontend files change
All test workflows use path-based filtering to run only when relevant files are modified, improving CI efficiency.
status-gateway.yml - The All Clear Gateway Job (see Issue #190)
This workflow always runs on PRs to main and checks the status of all test workflows that were triggered:
- Purpose: Solve the problem where path-based workflow filtering causes workflows to be skipped, and GitHub treats missing required checks as failures
- Pattern: Method 1 - The "All Clear" Gateway Job (industry best practice)
- Usage: In branch protection rules, require only the
status-gatewayworkflow, not the individual conditional workflows
How it works:
- Runs on every PR to main (no path filtering)
- Uses the GitHub API to query all workflow runs for the current PR's head commit
- Filters to only the test workflows (pytest, jest, vitest, cypress)
- If no test workflows ran (e.g., docs-only PR), succeeds with message
- If workflows are still in progress, reports pending status
- If any triggered workflow failed, fails with details
- If all triggered workflows passed, succeeds
For branch protection: Configure your branch protection rule to require only the Status Gateway / Status Check Gateway check.
MIT License