Skip to content

Design Documentation

Jaewoong Choi edited this page Dec 7, 2025 · 43 revisions

Project: LingoFit


1. Document Revision History

Version Date Description
V 1.0 2025-10-05 Initial version of the design documentation.
V 1.1 2025-10-18 Iteration 2: User Interface requirements update.
V 1.2 2025-11-02 Iteration 3: User Interface requirements update.
V 1.3 2025-11-16 Iteration 3: UI/UX and API revisions following Heuristic Evaluation.
V 1.4 2025-11-30 Iteration 5: Unification of Diagram Design and Tone.
V 1.5 2025-12-07 Buffer Iteration: Update Frontend Class Diagram.

2. Git Branch Strategy

The project utilizes a Git flow-inspired branching model to ensure stable releases while allowing for parallel development of features.

%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':false, 'mainBranchName': 'main'}} }%%
gitGraph
   commit id: "Init"
   branch dev
   checkout dev
   commit
   branch dev-backend
   branch dev-frontend
   
   checkout dev-frontend
   branch frontend/feat-login
   commit
   checkout dev-frontend
   merge frontend/feat-login
   
   checkout dev-backend
   branch backend/feat-api
   commit
   checkout dev-backend
   merge backend/feat-api
   
   checkout dev
   merge dev-frontend
   merge dev-backend
   
   checkout main
   merge dev tag: "v1.0"
Loading
  • Main: The production-ready branch. Merges here represent stable, versioned releases.
  • Dev: The central integration branch. All feature branches are merged here for system-wide integration testing.
  • Integration Branches:
    • dev-frontend: Integration point for React Native/Expo features (Front directory).
    • dev-backend: Integration point for FastAPI/Docker features (Backend directory).
  • Feature Branches: (Naming convention: [domain]/feat-[name])
    • Temporary branches for individual tasks. Deleted after merging.

3. System Design

3.1 System Architecture

3.1.1 High-Level Architecture

The system is deployed on an AWS EC2 instance hosting the API server and database. It leverages external AI services for content generation and Amazon S3 for media storage.

System Architecture

3.1.2 CI/CD Pipeline

The testing and deployment process is automated using GitHub Actions.

For the CD pipeline, the workflow connects to the Amazon EC2 instance via SSH, pulls the latest code from GitHub, and builds a new Docker image. The updated image is then deployed as a FastAPI container, enabling seamless backend updates without manual intervention.

This CI/CD setup ensures continuous testing, integration, and automated deployment for the backend server hosted at 52.78.135.45:3000.

sequenceDiagram
    autonumber
    
    %% Participants
    participant Dev as Developer
    participant GH as GitHub Repo
    participant GA as GitHub Actions
    participant EC2 as AWS EC2

    Note over Dev, GH: Trigger: Push to dev-backend
    Dev->>GH: Push Code
    GH->>GA: Trigger CI Workflow
    
    %% CI Phase (Blue Tint - High Transparency for Dark Mode)
    rect rgba(33, 150, 243, 0.15)
        Note right of GA: CI Phase
        GA->>GA: Run Unit Tests (pytest)
        GA->>GA: Run Integration Tests
    end
    
    alt Tests Passed
        %% CD Phase (Orange Tint)
        rect rgba(255, 152, 0, 0.15)
            GA->>EC2: SSH Connection
            Note right of GA: CD Phase
            EC2->>GH: Pull Latest Code
            EC2->>EC2: Build New Docker Image
            EC2->>EC2: Restart FastAPI Container
        end
    else Tests Failed
        %% Failure (Red Tint)
        rect rgba(244, 67, 54, 0.15)
            GA-->>Dev: Notify Failure
        end
    end
Loading

3.1.3 Architectural Pattern: MVC

The project adheres to the Model-View-Controller (MVC) architectural pattern.

Untitled Diagram drawio

3.2 Class Diagrams and Data Model

3.2.1 Frontend Architecture (React Native)

The frontend is organized by feature-based screens which maintain local state and communicate with the backend via typed API clients.

classDiagram
  %% Core app shell
  class RootLayout {
    +setupPlayerOnce()
    +RootNavigation()
  }
  class RootNavigation {
    +Stack.Protected authGuard
  }
  class QueryProvider {
    +queryClient: QueryClient
  }
  class QueryClient

  RootLayout --> QueryProvider
  QueryProvider --> QueryClient
  RootLayout --> RootNavigation
  RootNavigation --> useUser

  %% Networking & auth
  class customFetch {
    +getBaseUrl()
    +refreshAccessToken()
    +parseErrorResponse()
  }
  class tokenManager {
    +setAccessToken()
    +getAccessToken()
    +saveRefreshToken()
    +getRefreshToken()
    +deleteRefreshToken()
  }
  customFetch --> tokenManager
  customFetch --> QueryClient : clear cache on auth failure

  %% API layer
  class AuthAPI {
    +signup()
    +login()
    +changePassword()
    +deleteAccount()
  }
  class UserAPI {
    +getMe()
    +updateInterests()
  }
  class AudioAPI { +generateAudio() }
  class AudioHistoryAPI { +getAudioHistory() }
  class VocabAPI {
    +getVocab()
    +addVocab()
    +getMyVocab()
    +deleteMyVocab()
  }
  class StatsAPI { +getStats() }
  class FeedbackAPI { +submitFeedback() }
  class InitialSurveyAPI {
    +submitLevelTest()
    +submitManualLevel()
    +mapLevelIdToCEFR()
  }

  AuthAPI --> customFetch
  UserAPI --> customFetch
  AudioAPI --> customFetch
  AudioHistoryAPI --> customFetch
  VocabAPI --> customFetch
  StatsAPI --> customFetch
  FeedbackAPI --> customFetch
  InitialSurveyAPI --> customFetch

  %% Hooks
  class useSignup
  class useLogin
  class useLogout
  class useChangePassword
  class useDeleteAccount
  useSignup --> AuthAPI
  useSignup --> tokenManager
  useSignup --> QueryClient
  useLogin --> AuthAPI
  useLogin --> UserAPI
  useLogin --> tokenManager
  useLogout --> tokenManager
  useLogout --> QueryClient
  useChangePassword --> AuthAPI
  useDeleteAccount --> AuthAPI

  class useUser
  useUser --> UserAPI

  class useGenerateAudio
  class useAudioHistory
  class useAddVocab
  class useVocab
  class useMyVocab
  class useDeleteMyVocab
  class useStats
  class useSubmitLevelTest
  class useSubmitManualLevel
  class useUpdateInterests

  useGenerateAudio --> AudioAPI
  useAudioHistory --> AudioHistoryAPI
  useAddVocab --> VocabAPI
  useVocab --> VocabAPI
  useMyVocab --> VocabAPI
  useDeleteMyVocab --> VocabAPI
  useStats --> StatsAPI
  useSubmitLevelTest --> InitialSurveyAPI
  useSubmitManualLevel --> InitialSurveyAPI
  useUpdateInterests --> UserAPI

  %% Screens
  class HomeScreen
  class HistoryScreen
  class AudioPlayerScreen
  class FeedbackScreen
  class LevelResultScreen
  class InitialSurveyScreen
  class WalkthroughScreen
  class AuthScreens

  HomeScreen --> useGenerateAudio
  HomeScreen --> useUser
  HistoryScreen --> useAudioHistory
  AudioPlayerScreen --> useAddVocab
  AudioPlayerScreen --> useVocab
  AudioPlayerScreen --> FeedbackScreen : route params
  FeedbackScreen --> FeedbackAPI
  LevelResultScreen --> FeedbackScreen : params -> results
  InitialSurveyScreen --> useSubmitLevelTest
  InitialSurveyScreen --> useSubmitManualLevel
  AuthScreens --> useSignup
  AuthScreens --> useLogin

Loading

3.2.2 Backend Service Architecture

The backend logic is structured around domain-specific services that handle business logic and external API orchestration.

classDiagram
    direction TB
    
    %% --- Style Definitions ---
    classDef serviceNode fill:#ffffff,stroke:#333,stroke-width:2px,color:#000
    classDef externalNode fill:#FFF3E0,stroke:#FB8C00,stroke-width:2px,stroke-dasharray: 5 5,color:#000

    %% --- External APIs ---
    class OpenAI:::externalNode {
        +chat.completions.create()
    }
    class ElevenLabs:::externalNode {
        +text_to_speech.convert()
    }
    class S3:::externalNode {
        +upload_fileobj()
        +generate_presigned_url()
    }

    %% --- Core Services ---
    class AudioService:::serviceNode {
        +generate_full_audio_with_timestamps()
        +generate_full_audio_streaming()
        +list_user_audio_history()
        -select_voice_algorithmically()
    }

    class VocabService:::serviceNode {
        +build_contextual_vocab()
        +process_sentence_async()
        -extract_keywords()
    }

    class LevelManagementService:::serviceNode {
        +evaluate_initial_level()
        +evaluate_session_feedback()
        +set_manual_level()
    }

    class LevelSystemService:::serviceNode {
        +initialize_level()
        +calculate_level_deltas()
        -apply_constraints()
    }

    class StatsService:::serviceNode {
        +get_user_stats()
        +update_streaks()
        +calculate_weekly_minutes()
    }

    %% --- Relationships ---
    AudioService ..> VocabService : uses
    AudioService ..> OpenAI : Script Gen
    AudioService ..> ElevenLabs : TTS Gen
    AudioService ..> S3 : Storage

    VocabService ..> OpenAI : Context Extraction
    LevelManagementService ..> LevelSystemService : delegates calculation
    LevelManagementService ..> OpenAI : Rationale Eval
Loading

3.2.3 Entity Relationship Diagram (ERD)

The database schema centers around the users table, which serves as the primary foreign key reference for learning content, history, and achievements.

erDiagram
    %% Entities
    users {
        int id PK
        string username
        float lexical_level
        float syntactic_level
        float speed_level
    }

    generated_contents {
        int generated_content_id PK
        int user_id FK
        string audio_url
        json script_data
    }

    user_interests {
        int id PK
        int user_id FK
        string interest_code
    }

    user_level_history {
        int id PK
        int user_id FK
        timestamp created_at
        json level_snapshot
    }

    study_sessions {
        int id PK
        int user_id FK
        int duration_seconds
        timestamp created_at
    }

    vocab_entries {
        int id PK
        int user_id FK
        string word
        string context_sentence
    }

    achievements {
        string code PK
        string name
        string description
    }

    user_achievements {
        int id PK
        int user_id FK
        string achievement_code FK
    }

    level_test_scripts {
        int id PK
        string content
        string target_level
    }

    %% Relationships
    users ||--o{ generated_contents : "creates"
    users ||--o{ study_sessions : "logs"
    users ||--o{ user_level_history : "tracks"
    users ||--o{ vocab_entries : "saves"
    users ||--o{ user_interests : "selects"
    users ||--o{ user_achievements : "earns"
    
    achievements ||--o{ user_achievements : "defines"
Loading

3.2.4 Data Model Description

Entity Description
User The central entity storing account credentials and current CEFR proficiency levels (Lexical, Syntactic, Speed).
GeneratedContent Stores metadata for AI-generated podcasts, including S3 audio URLs and the raw script JSON.
StudySession specific learning session, tracking duration and completion status for statistics.
UserLevelHistory A historical log of proficiency changes, used to visualize progress over time.
VocabEntry User-specific vocabulary words saved during listening sessions, including the context sentence where the word appeared.
Achievement Static definitions of available badges/milestones (e.g., "7 Day Streak").
LevelTestScript Pre-defined scripts used specifically for the initial placement test.

3.3 Implementation Details

3.3.1 Audio Personalization Pipeline

The following sequence details the lifecycle of an audio generation request, from the client's initial prompt to the final MP3 synthesis.

sequenceDiagram
    autonumber
    
    %% Participants
    participant Client
    participant Server as Audio Service
    participant Config as voices.json
    participant OpenAI as OpenAI API
    participant Eleven as ElevenLabs API
    participant S3 as Storage

    %% Flow
    Client->>Server: POST /audio/generate (token, mood, theme)
    activate Server
    
    Note right of Server: 1. Voice Selection
    Server->>Config: load_voices()
    Config-->>Server: All Voices List
    Server->>Server: select_voice(user.level)

    Note right of Server: 2. Script Generation
    Server->>OpenAI: generate_script(mood, theme, user_level)
    activate OpenAI
    OpenAI-->>Server: Generated Script (title, text)
    deactivate OpenAI

    Note right of Server: 3. Audio Synthesis
    Server->>Eleven: convert_with_timestamps(script, voice_id)
    activate Eleven
    Eleven-->>Server: Audio Stream (Base64) + Alignment
    deactivate Eleven

    Note right of Server: 4. Processing
    Server->>Server: parse_tts_by_newlines()
    Server->>S3: Save .mp3 file
    activate S3
    S3-->>Server: File URL
    deactivate S3

    Server-->>Client: 200 OK (JSON with Sentences & URL)
    deactivate Server

    %% Styling
    rect rgba(243, 229, 245, 0.4)
        Note over Client, S3: Audio Generation Context
    end
Loading

3.3.2 API Specifications

The backend exposes a RESTful API built with FastAPI. All endpoints are prefixed with /api/v1.

Auth & User Management

POST /api/v1/auth/signup - Register new user
  • Request Body:
    {
      "username": "user123",
      "password": "securePassword1!"
    }
  • Response Body (200 OK):
    {
      "access_token": "eyJhbG...",
      "refresh_token": "eyJhbG...",
      "token_type": "bearer"
    }
POST /api/v1/auth/login - User login
  • Request Body:
    {
      "username": "user123",
      "password": "securePassword1!"
    }
  • Response Body (200 OK):
    {
      "access_token": "eyJhbG...",
      "refresh_token": "eyJhbG...",
      "token_type": "bearer"
    }
POST /api/v1/auth/change-password - Change Password
  • Request Headers: Authorization: Bearer {token}
  • Request Body:
    {
      "current_password": "oldPassword",
      "new_password": "newPassword"
    }
  • Response Body (200 OK): { "message": "Password updated successfully" }
POST /api/v1/auth/refresh/access - Refresh Access Token
  • Request Body:
    {
      "refresh_token": "eyJhbG..."
    }
  • Response Body (200 OK):
    {
      "access_token": "eyJhbG...",
      "token_type": "bearer"
    }
DELETE /api/v1/auth/delete-account - Delete Account
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK): { "message": "Account deleted successfully." }
GET /api/v1/user/me - Get My Profile
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK):
    {
      "id": 1,
      "username": "user123",
      "lexical_level": 50.5,
      "syntactic_level": 40.0,
      "speed_level": 60.0
    }
PUT /api/v1/user/me/interests - Update Interests
  • Request Headers: Authorization: Bearer {token}
  • Request Body:
    {
      "interests": ["Technology", "Travel"]
    }
  • Response Body (200 OK): { "success": true }

Audio & Content

POST /api/v1/audio/generate - Generate Audio Content
  • Request Headers: Authorization: Bearer {token}
  • Request Body:
    {
      "style": "podcast",
      "theme": "sports"
    }
  • Response Body (200 OK):
    {
      "generated_content_id": 101,
      "title": "A Trip to Seoul",
      "audio_url": "[https://s3.aws.com/](https://s3.aws.com/)...",
      "sentences": [
        { "id": 1, "start_time": 0.0, "text": "Hello there." }
      ]
    }
GET /api/v1/audio/content/{id} - Get Audio Content By ID
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK):
    {
      "generated_content_id": 101,
      "title": "A Trip to Seoul",
      "audio_url": "[https://s3.aws.com/](https://s3.aws.com/)...",
      "sentences": [
        { "id": 1, "start_time": 0.0, "text": "Hello there." }
      ]
    }
GET /api/v1/audio/history - Get User History
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK):
    [
      {
        "generated_content_id": 101,
        "title": "A Trip to Seoul",
        "created_at": "2025-10-10T10:00:00"
      }
    ]
GET /api/v1/audio/files/{filename} - Serve Audio File
  • Summary: Directly serves the static MP3 file from storage (used by the player).

Vocabulary

GET /api/v1/vocabs/me - Get My Vocabulary
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK):
    [
      {
        "id": 5,
        "word": "Serendipity",
        "meaning": "Finding something good without looking for it.",
        "example_sentence": "It was pure serendipity..."
      }
    ]
GET /api/v1/vocabs/{id} - Get Vocabs from Script
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK): ["serendipity", "tranquility", "ephemeral"]
GET /api/v1/vocabs/{id}/sentences/{idx} - Get Contextual Word
  • Query Params: ?word=target
  • Response Body (200 OK):
    {
      "word": "target",
      "part_of_speech": "noun",
      "meaning": "The definition in this specific context."
    }
POST /api/v1/vocabs/{id}/sentences/{idx} - Save Word
  • Request Body: { "word": "target" }
  • Response Body (201 Created): { "success": true }
DELETE /api/v1/vocabs/me/{entry_id} - Delete Vocab Entry
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK): { "success": true }

Level System & Survey

POST /api/v1/level-system/level-test - Evaluate Level Test
  • Request Body:
    {
      "tests": [ { "script_id": "A1_01", "understanding": 80 } ]
    }
  • Response Body (200 OK):
    {
      "lexical_level": 30.0,
      "syntactic_level": 25.0,
      "speed_level": 40.0
    }
POST /api/v1/level-system/session-feedback - Submit Feedback
  • Request Body:
    {
      "generated_content_id": 101,
      "pause_cnt": 2,
      "rewind_cnt": 1,
      "vocab_lookup_cnt": 3,
      "vocab_save_cnt": 1,
      "understanding_difficulty": 3,
      "speed_difficulty": 2
    }
  • Response Body (200 OK):
    {
      "lexical_level_delta": +1.5,
      "syntactic_level_delta": +1.0,
      "speed_level_delta": -1.0
    }
POST /api/v1/level-system/manual-level - Set Manual Level
  • Request Body: { "level": "B1" }
  • Response Body (200 OK): { "success": true }
GET /api/v1/initial-survey/{level}/{number} - Get Survey Audio
  • Summary: Retrieves the static audio file for the initial placement test questions.

Statistics

GET /api/v1/stats - Get User Statistics
  • Request Headers: Authorization: Bearer {token}
  • Response Body (200 OK):
    {
      "streak": { "current": 5, "best": 12 },
      "total_minutes": 120,
      "level_history": [...]
    }

3.3.3 Structured Error Response List

The API returns errors in a consistent JSON format to ensure predictable client handling.

Standard Error Format:

{
  "status_code": 400,
  "custom_code": "USERNAME_EXISTS",
  "detail": "The username you provided is already taken."
}

Global Error Codes:

Status Custom Code Detail
400 USERNAME_EXISTS Username already exists.
401 INVALID_CREDENTIALS Invalid username or password.
401 AUTH_TOKEN_EXPIRED Authentication token has expired.
401 INVALID_TOKEN Token is invalid.
401 INVALID_TOKEN_TYPE Invalid token type.
401 INVALID_AUTH_HEADER Invalid authorization header.
404 USER_NOT_FOUND The requested user does not exist.
404 GENERATED_CONTENT_NOT_FOUND The requested generated content does not exist.
404 LEVEL_TEST_SCRIPT_NOT_FOUND The requested level test script does not exist.
404 SENTENCE_INDEX_OUT_OF_RANGE The sentence index is out of range.
404 WORD_NOT_FOUND_IN_SENTENCE The word was not found in the sentence.
404 NO_VOCAB_ENTRIES_FOUND No vocabulary entries found for user.
422 INVALID_USERNAME_FORMAT Username must be 6~16 characters long and contain only letters and numbers.
422 INVALID_PASSWORD_FORMAT Password must be 8~32 characters long and include at least one letter and one number.
422 WORD_ALREADY_EXISTS Word already exists in vocabulary list.
500 ACCOUNT_DELETION_FAILED Server failed to delete account.
500 VOCAB_SAVE_FAILED Failed to save vocabulary entry.
500 DATABASE_CONNECTION_ERROR Database connection error occurred.
503 SCRIPT_GENERATION_FAILED Failed to generate script from external API.
503 TTS_GENERATION_FAILED Failed to generate audio from external API.
503 OPEN_AI_API_ERROR OpenAI API error occurred.

4. Testing Plan

4.1 Overview

The project employs a comprehensive testing strategy that separates concerns between isolated Unit Tests and system-wide Integration Tests. This separation ensures individual components function correctly while verifying that the entire stack (Frontend $\leftrightarrow$ Backend $\leftrightarrow$ AI Services) operates seamlessly.

flowchart LR
    %% Definitions
    subgraph Trigger [Trigger]
        PR["Pull Request / Push"]
    end

    subgraph Test_Suite [Test Execution Suite]
        direction TB
        Unit["Unit Tests\n(Isolated Logic)"]
        Integration["Integration Tests\n(API & DB Flows)"]
        E2E["Acceptance Tests\n(User Stories)"]
    end

    subgraph Reporting [Analysis & Reporting]
        Coverage{Codecov Analysis}
        Pass[Merge Allowed]
        Fail[Block Merge]
    end

    %% Flow
    PR --> Unit
    Unit --> Integration
    Integration --> E2E
    E2E --> Coverage
    
    Coverage -- "Coverage > 80%" --> Pass
    Coverage -- "Coverage < 80%" --> Fail

    %% Styling
    classDef process fill:#ffffff,stroke:#333,stroke-width:2px,color:#000
    classDef success fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px,color:#000
    classDef fail fill:#FFEBEE,stroke:#C62828,stroke-width:2px,color:#000

    class PR,Unit,Integration,E2E,Coverage process
    class Pass success
    class Fail fail
Loading

4.2 Backend Testing (FastAPI)

4.2.1 Test Strategy & Structure

A split-layer testing strategy is adopted using pytest. The test suite is physically separated into two distinct directories to enforce separation of concerns:

  • Unit Tests (tests/unit/):

    • Focus: Verification of individual functions and classes in isolation.
    • Constraint: These tests do not interact with the database, external APIs (OpenAI/ElevenLabs), or the file system. All external dependencies are mocked.
    • Goal: Immediate feedback on business logic correctness (e.g., token validation logic, text parsing regex).
  • Integration Tests (tests/integration/):

    • Focus: Verification of complete workflows and component interaction.
    • Scope: These tests instantiate a test database container, execute real HTTP requests against the FastAPI endpoints, and validate the resulting state changes in the database.
    • Goal: Validation of the API contract and correct interoperability between services (Auth, DB, S3).

4.2.2 Tools & Libraries

Tool Role Usage
pytest Test Runner The primary framework for discovering and executing tests.
pytest-asyncio Async Support Essential for testing FastAPI's asynchronous async def endpoints.
httpx HTTP Client Used to simulate real user requests (GET, POST) against the API during integration tests.
Codecov Reporting Visualizes coverage data in PRs to prevent coverage regression.

4.2.3 Current Coverage Report

The project has achieved the 90% coverage target for the backend. Key core modules such as auth, audio, and stats maintain near-perfect coverage. Below is the latest report.



4.3 Frontend Testing (React Native)

4.3.1 Test Strategy & Structure

The frontend employs a layered testing strategy organized by test type and co-located with source files. Tests are structured to validate user-facing behavior while maintaining confidence in implementation details.

  • Unit Tests (co-located in tests/ directories):

    • Focus: Verification of individual functions, utilities, and custom hooks in isolation.
    • Constraint: All external dependencies (APIs, storage, native modules) are mocked.
    • Goal: Fast feedback on business logic correctness (e.g., token management, validation logic, utility functions).
  • Component Tests (co-located in tests/ directories):

    • Focus: UI rendering and User Interaction.
    • Method: React Testing Library is used to query elements by accessibility roles (e.g., getByRole('button')) rather than implementation details (IDs or class names). This ensures resilience against refactoring.
    • Scenarios: Verification of loading states, error message rendering, and button press handlers.
  • Integration Flows (tests/integration/):

    • Focus: Complete user workflows and cross-component interaction.
    • Scope: Tests render entire screens with necessary providers and validate end-to-end feature correctness.
    • Goal: Validation of API contract and cross-component integration.

4.3.2 Frontend Integration Tests

The frontend has 9 integration test suites located in frontend/__tests__/integration/.


No. Test Suite File Description Key Features Tested
1 Audio History (audioHistory.integration.test.tsx) Tests the audio playback history functionality. * Loading state display
* Successful audio history list rendering
* Empty state when no history exists
2 Authentication Routing (auth-routing.integration.test.tsx) Tests navigation logic based on user authentication state. * Redirect to initial survey when user hasn't completed initial level test
* No redirect when initial level test is completed
* No redirect for unauthenticated users
* No redirect during loading state
* Dynamic redirect after user data loads
3 Feedback (feedback.integration.test.tsx) Tests the post-session feedback screen. * Title and section display
* Understanding difficulty level options (매우 낮음 to 매우 높음)
* Submit button rendering
* Speed options appearing after selecting understanding level
4 Initial Survey (initialSurvey.integration.test.tsx) Tests the initial level assessment flow. * Survey start and level selection (A1-C2)
* Navigation between survey steps (back button)
* Validation preventing navigation without level selection
5 Login (login.integration.test.tsx) Tests user authentication. * Successful login with token storage and navigation to home
* Error display on invalid credentials
* Input validation before submission
* Form disabled state during mutation
* Navigation to signup screen
6 Profile (profile.integration.test.tsx) Tests the user profile screen. * Loading state
* Display of logout button, account deletion, privacy, help, and about options
7 Signup (signup.integration.test.tsx) Tests user registration. * Successful signup and navigation to login
* Password mismatch validation
* Required field validation
* API error handling
* Navigation back to login
* Incomplete form button disabling
8 Stats (stats.integration.test.tsx) Tests the statistics/progress screen. * Loading state
* Level information display (어휘력, 문법)
* Streak information (연속 학습일, 누적 학습일)
* Total study time
* Weekly activity chart with days of week
* Achievements/badges section
* Error state handling
9 Vocabulary (vocab.integration.test.tsx) Tests the vocabulary list feature. * Loading state
* Successful vocab list display
* Empty state messaging
* Error state with retry functionality
* Vocab details display (word, meaning, example sentences)

4.3.3 Tools & Libraries

Tool Role Usage
Jest Test Runner The standard JavaScript testing framework, configured with jest-expo.
React Testing Library Component Testing Provides helpers to render components and simulate user events (press, type).
@testing-library/jest-native Native Matchers Adds custom matchers for React Native (e.g., toHaveTextContent, toBeDisabled).
@tanstack/react-query State Management Testing QueryClient instances are created per test with retry: false for deterministic behavior.

4.3.4 Current Coverage Report

The project has achieved 96% overall coverage, exceeding the 80% target set in project requirements: image

4.3.5 Running Tests:

Running Tests

# Run all tests
npm test

# Generate coverage report
npm run test:coverage

# Run unit tests only (excludes integration)
npm run test:unit

# Run integration tests only
npm run test:integration

CI/CD Integration: Tests run automatically on pull requests via GitHub Actions with coverage validation.


4.4 Acceptance Testing

Acceptance tests act as the final quality gate. These validate that the system satisfies the core business requirements defined in the Product Requirements Document (PRD).

Feature ID User Story Acceptance Criteria
AT-01 Personalized Recommendations User receives audio content matching their exact Interest tags.
AT-02 History Tracking Completed sessions appear in the "History" tab with correct timestamps.
AT-03 Vocabulary Extraction Tapping a word in the player adds it to the Vocab list with context.
AT-04 Daily Suggestions App suggests new content every 24 hours based on user level.
AT-05 Learning Dashboard Statistics page updates "Minutes Listened" immediately after a session.