# sendajapan/jlpt architecture

> Architecture diagram of the GitHub repository sendajapan/jlpt, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/sendajapan/jlpt
- Repository: https://github.com/sendajapan/jlpt

## Overview

1. **Repository shape**
   This is a two-client system in one repo: a Laravel 13 backend in the root and a native Android app in `/android`. The backend serves both a browser-based admin panel and a versioned REST API consumed by the mobile client.

2. **Core domain**
   The product is a JLPT vocabulary learning platform. The domain centers on categories, subcategories, vocabulary words, quizzes, user progress, favorites, unlocks, coins, avatars, reads, and profile/authentication flows.

3. **Backend application boundary**
   Laravel splits the server into two major entry points:
   - **Admin web UI** under `resources/views/admin` and `app/Http/Controllers/Admin`
   - **Mobile API** under `app/Http/Controllers/Api/V1`
   These are separate surfaces with different auth models and response styles, but they share the same domain models and services.

4. **API layer for mobile**
   The `/api/v1/` controllers expose JSON endpoints for auth, categories, subcategories, vocabulary, quiz, favorites, profile, coins, and unlocks. Requests are validated with dedicated `app/Http/Requests/Api/*` classes, and responses are shaped with `app/Http/Resources/*` plus DTOs in `app/Http/Resources` and `app/Http/Controllers/Api/V1` dependencies.

5. **Business logic layer**
   Most nontrivial logic is centralized in `app/Services`. This includes authentication, OTP, social login, avatar management, coin handling, category/subcategory/vocabulary management, favorites, word reads, and unlock logic. Controllers are thin orchestration points; services are the main business boundary.

6. **Persistence and data model**
   Eloquent models in `app/Models` map to the vocabulary and user tables defined in `database/migrations`. The schema includes both standard Laravel auth tables and platform-specific tables such as `app_users`, `vocab_categories`, `vocab_subcategories`, `vocab_words`, `avatars`, `coin_transactions`, `app_user_otps`, `app_user_word_reads`, and unlock tables. Seeders and backups indicate the database is a first-class operational dependency.

7. **Auth split by client**
   Authentication is intentionally bifurcated:
   - **Admin web** uses Laravel session auth and the built-in auth controllers/views.
   - **Android/mobile** uses **Laravel Sanctum** token auth.
   The API also supports guest login, OTP verification, email verification, password reset, and social login. `AuthInterceptor` on Android attaches the token to API calls.

8. **Async and automation**
   Audio generation is handled as a background/automation concern rather than inline request work. The backend includes a queue-backed job (`GenerateNextVocabAudioJob`), console commands for seeding and ticking audio generation, and an `AudioAutomationService`. This suggests audio assets are processed asynchronously and tracked separately from the main CRUD flows.

9. **Admin panel**
   The admin UI is a traditional server-rendered Laravel app using Blade, Alpine.js, Tailwind CSS v4, and Vite. It manages content operations for categories, subcategories, words, voices, avatars, app users, and audio automation. The admin surface is for content/operator workflows, not the mobile learning experience.

10. **Android app structure**
    The Android client is organized in a classic MVVM-style split:
    - `ui/activities`, `ui/fragments`, `ui/adapters`, `ui/views`
    - `viewmodels`
    - `data/repo`, `data/networking`, `data/local`
    - `models` for domain objects
    User-facing flows are split across onboarding, auth, dashboard/home, vocabulary browsing, quiz, progress, favorites, and profile screens.

11. **Android data flow**
    The mobile app pulls remote data through Retrofit (`ApiService`, `RetrofitClient`) and a request interceptor for auth headers. It persists token state in `TokenStore` and caches structured content in a local database (`AppDatabase`, DAOs, entities, relations). Repositories sit between ViewModels and the data sources, so UI reads are mediated through a remote/local abstraction rather than direct API calls.

12. **Mobile navigation and UI composition**
    The Android UI is built from multiple activities and fragments, with separate screens for auth, onboarding, category/subcategory browsing, word details, quiz, and profile setup. Adapters back list/grid views for categories, subcategories, words, avatars, and progress. Bottom sheets and dialogs handle focused interactions like avatar picking, DOB selection, and unlock prompts.

13. **Shared content model between backend and app**
    The backend exposes vocabulary content and user state; the Android app mirrors that with DTOs and local models. This indicates a server-authoritative content model with client-side caching for speed and offline resilience, especially for category trees, word lists, and user progress/favorites.

14. **Operational/tooling boundaries**
    Swagger/L5-Swagger documents the API, Pest covers tests, and the Laravel app uses database-backed cache/queue/session drivers. MySQL is the primary persistence layer, while `storage/public` and related assets support media such as avatars and generated audio.

15. **How to draw the architecture**
    A useful diagram should show:
    - Android client → Sanctum-protected REST API
    - Admin browser → Laravel session-auth web app
    - API/web controllers → service layer → Eloquent models/database
    - Async jobs/commands → queue/database + audio automation/storage
    - Android ViewModels → repositories → Retrofit/local DB/token store
    The important boundary is that the backend owns business rules and persistence, while the Android app owns presentation, local caching, and token-managed API access.

Main entry points: [`app/Http/Controllers/Api/V1`](https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Api/V1) (Mobile API), [`app/Services`](https://github.com/sendajapan/jlpt/tree/main/app/Services) (Services), [`app/Http/Controllers/Admin`](https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Admin) (Admin controllers), [`android/app/src/main/java/com/scholarlyapps/pathlingo/data/repo`](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/repo) (Repositories)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_backend["Laravel backend"]
  node_backend_web["Admin web<br/>server-rendered UI"]
  node_backend_admin_ctrl["Admin controllers<br/>web controllers"]
  node_backend_api_ctrl["Mobile API<br/>api controllers"]
  node_backend_api_auth["API auth<br/>auth endpoints"]
  node_backend_services["Services<br/>business logic"]
  node_backend_models["Eloquent models<br/>domain models"]
  node_backend_requests["Requests<br/>validation"]
  node_backend_resources["API resources<br/>response shaping"]
  node_backend_jobs["Audio job<br/>async job"]
  node_backend_commands["Console jobs<br/>automation commands"]
  node_backend_routes["Routes<br/>entry points"]
end

subgraph group_android["Android client"]
  node_android_app["Android app<br/>native client"]
  node_android_ui["Screens<br/>UI layer"]
  node_android_vm["ViewModels<br/>presentation logic"]
  node_android_repo["Repositories<br/>data boundary"]
  node_android_net["Network stack<br/>retrofit client"]
  node_android_local[("Local store<br/>cache/db")]
end

subgraph group_ops["Ops and data"]
  node_backend_db[("Database<br/>migrations and dumps")]
  node_backend_docs["API docs<br/>swagger spec<br/>[OpenApi.php]"]
end

node_android_app -->|"renders"| node_android_ui
node_android_ui -->|"binds to"| node_android_vm
node_android_vm -->|"uses"| node_android_repo
node_android_repo -->|"fetches"| node_android_net
node_android_repo -->|"caches"| node_android_local
node_android_net -->|"calls"| node_backend_api_ctrl
node_android_net -->|"auth flow"| node_backend_api_auth
node_backend_api_ctrl -->|"orchestrates"| node_backend_services
node_backend_api_auth -->|"orchestrates"| node_backend_services
node_backend_admin_ctrl -->|"orchestrates"| node_backend_services
node_backend_services -->|"mutates"| node_backend_models
node_backend_services -->|"persists"| node_backend_db
node_backend_requests -->|"validates"| node_backend_api_ctrl
node_backend_requests -->|"validates"| node_backend_admin_ctrl
node_backend_api_ctrl -->|"formats"| node_backend_resources
node_backend_web -->|"views"| node_backend_admin_ctrl
node_backend_jobs -->|"runs logic"| node_backend_services
node_backend_commands -->|"ticks"| node_backend_jobs
node_backend_commands -->|"operates on"| node_backend_db
node_backend_docs -.->|"documents"| node_backend_api_ctrl
node_backend_routes -->|"dispatches"| node_backend_api_ctrl
node_backend_routes -->|"dispatches"| node_backend_admin_ctrl

click node_android_app "https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo"
click node_android_ui "https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/ui"
click node_android_vm "https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/viewmodels"
click node_android_repo "https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/repo"
click node_android_net "https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/networking"
click node_android_local "https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/local"
click node_backend_web "https://github.com/sendajapan/jlpt/tree/main/resources/views/admin"
click node_backend_admin_ctrl "https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Admin"
click node_backend_api_ctrl "https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Api/V1"
click node_backend_api_auth "https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Api/V1/Auth"
click node_backend_services "https://github.com/sendajapan/jlpt/tree/main/app/Services"
click node_backend_models "https://github.com/sendajapan/jlpt/tree/main/app/Models"
click node_backend_requests "https://github.com/sendajapan/jlpt/tree/main/app/Http/Requests"
click node_backend_resources "https://github.com/sendajapan/jlpt/tree/main/app/Http/Resources"
click node_backend_jobs "https://github.com/sendajapan/jlpt/blob/main/app/Jobs/GenerateNextVocabAudioJob.php"
click node_backend_commands "https://github.com/sendajapan/jlpt/tree/main/app/Console/Commands"
click node_backend_db "https://github.com/sendajapan/jlpt/tree/main/database/migrations"
click node_backend_routes "https://github.com/sendajapan/jlpt/tree/main/routes"
click node_backend_docs "https://github.com/sendajapan/jlpt/blob/main/app/OpenApi/OpenApi.php"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_backend_web,node_backend_admin_ctrl,node_backend_api_ctrl,node_backend_api_auth,node_backend_services,node_backend_models,node_backend_requests,node_backend_resources,node_backend_jobs,node_backend_commands,node_backend_routes toneBlue
class node_android_app,node_android_ui,node_android_vm,node_android_repo,node_android_net,node_android_local toneAmber
class node_backend_db,node_backend_docs toneMint
```

## Components

### Laravel backend

Server-side web, API, domain, and async automation.

- [Admin web](https://github.com/sendajapan/jlpt/tree/main/resources/views/admin): server-rendered UI · Blade-based operator surface for managing content, avatars, users, and automation. · `resources/views/admin`
- [Admin controllers](https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Admin): web controllers · Session-authenticated controllers for admin workflows. · `app/Http/Controllers/Admin`
- [Mobile API](https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Api/V1): api controllers · Versioned REST controllers for auth, vocab content, quiz, favorites, profile, coins, and unlocks. · `app/Http/Controllers/Api/V1`
- [API auth](https://github.com/sendajapan/jlpt/tree/main/app/Http/Controllers/Api/V1/Auth): auth endpoints · Guest, login, register, OTP, password reset, verification, logout, and social login flows. · `app/Http/Controllers/Api/V1/Auth`
- [Services](https://github.com/sendajapan/jlpt/tree/main/app/Services): business logic · Central business boundary for auth, OTP, social login, content, favorites, coins, reads, and unlocks. · `app/Services`
- [Eloquent models](https://github.com/sendajapan/jlpt/tree/main/app/Models): domain models · Server domain objects for users, vocab, avatars, coins, unlocks, reads, and audio tracking. · `app/Models`
- [Requests](https://github.com/sendajapan/jlpt/tree/main/app/Http/Requests): validation · Dedicated request validation for admin and API inputs. · `app/Http/Requests`
- [API resources](https://github.com/sendajapan/jlpt/tree/main/app/Http/Resources): response shaping · JSON resource and DTO layer for mobile responses. · `app/Http/Resources`
- [Audio job](https://github.com/sendajapan/jlpt/blob/main/app/Jobs/GenerateNextVocabAudioJob.php): async job · Queue-backed vocabulary audio generation work. · `app/Jobs/GenerateNextVocabAudioJob.php`
- [Console jobs](https://github.com/sendajapan/jlpt/tree/main/app/Console/Commands): automation commands · CLI automation for seeding unlocks and ticking audio generation. · `app/Console/Commands`
- [Routes](https://github.com/sendajapan/jlpt/tree/main/routes): entry points · Web, API, auth, and console route definitions. · `routes`

### Android client

Native app with MVVM UI, repositories, and local cache.

- [Android app](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo): native client · Mobile learning client for onboarding, vocab browsing, quiz, and profile flows. · `android/app/src/main/java/com/scholarlyapps/pathlingo`
- [Screens](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/ui): UI layer · Activities, fragments, adapters, dialogs, and bottom sheets composing the app experience. · `android/app/src/main/java/com/scholarlyapps/pathlingo/ui`
- [ViewModels](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/viewmodels): presentation logic · State holders coordinating UI flows with repositories. · `android/app/src/main/java/com/scholarlyapps/pathlingo/viewmodels`
- [Repositories](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/repo): data boundary · Repository layer mediating between ViewModels, remote API, and local cache. · `android/app/src/main/java/com/scholarlyapps/pathlingo/data/repo`
- [Network stack](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/networking): retrofit client · Retrofit service, client setup, and auth interceptor for Sanctum-protected API calls. · `android/app/src/main/java/com/scholarlyapps/pathlingo/data/networking`
- [Local store](https://github.com/sendajapan/jlpt/tree/main/android/app/src/main/java/com/scholarlyapps/pathlingo/data/local): cache/db · Token storage plus Room database, DAOs, entities, and relations for offline-friendly content caching. · `android/app/src/main/java/com/scholarlyapps/pathlingo/data/local`

### Ops and data

Persistence, docs, and background processing.

- [Database](https://github.com/sendajapan/jlpt/tree/main/database/migrations): migrations and dumps · MySQL schema, migrations, backups, and seed data for auth, vocab, coins, unlocks, and audio state. · `database/migrations`
- [API docs](https://github.com/sendajapan/jlpt/blob/main/app/OpenApi/OpenApi.php): swagger spec · OpenAPI generation and published API documentation. · `app/OpenApi/OpenApi.php`

## Connections

- Android app → Screens: renders · The app is composed from activities, fragments, adapters, and dialogs.
- Screens → ViewModels: binds to · Screens delegate state and actions to ViewModels.
- ViewModels → Repositories: uses · ViewModels coordinate data through repositories.
- Repositories → Network stack: fetches · Repositories call the Retrofit API layer for remote data.
- Repositories → Local store: caches · Repositories persist tokens and structured content locally.
- Network stack → Mobile API: calls · The Android client consumes the versioned REST API.
- Network stack → API auth: auth flow · Login and token-bearing auth requests go through API auth endpoints.
- Mobile API → Services: orchestrates · Controllers stay thin and delegate business rules to services.
- API auth → Services: orchestrates · Authentication endpoints use dedicated auth and OTP services.
- Admin controllers → Services: orchestrates · Admin controllers use the same service layer for content operations.
- Services → Eloquent models: mutates · Services implement the domain logic over Eloquent models.
- Services → Database: persists · Domain changes are stored in the database schema managed by migrations.
- Requests → Mobile API: validates · Request objects protect API inputs.
- Requests → Admin controllers: validates · Request objects protect admin form inputs.
- Mobile API → API resources: formats · API responses are shaped for the mobile client via resources and DTOs.
- Admin web → Admin controllers: views · Blade templates back the admin controller workflows.
- Audio job → Services: runs logic · Queued audio generation relies on the audio automation service.
- Console jobs → Audio job: ticks · Console commands drive background audio processing and seeding tasks.
- Console jobs → Database: operates on · Automation commands seed and update persisted platform state.
- API docs → Mobile API: documents · OpenAPI docs describe the mobile REST surface.
- Routes → Mobile API: dispatches · API routes bind mobile endpoints to controllers.
- Routes → Admin controllers: dispatches · Web routes bind admin pages to controllers.
