Mimari¶
Adaptive Learner, 4 katmanlı, eklenti güdümlü bir uygulamadır.
┌─────────────────────────────────────────────────────────────┐
│ Frontend React 19 + TypeScript 6 + Vite 8 + │
│ Vitest 4 + Dexie 4 (IndexedDB) + TipTap │
└─────────────────────────────────────────────────────────────┘
↑↓ /api/*
┌─────────────────────────────────────────────────────────────┐
│ Backend FastAPI ^0.136 + SQLAlchemy ^2.0 + │
│ Pydantic v2 + Alembic + Fernet │
└─────────────────────────────────────────────────────────────┘
↑↓ hookspecs
┌─────────────────────────────────────────────────────────────┐
│ PluginForge ^0.10.0 (external PyPI; identity-gated │
│ via target_application) │
└─────────────────────────────────────────────────────────────┘
↑↓ entry_points
┌─────────────────────────────────────────────────────────────┐
│ Plugins 10 packages under plugins/ │
│ (ai-{anthropic,openai,gemini}, assessment,│
│ session, tracking, tools, gamification, │
│ anki, notebooklm) │
└─────────────────────────────────────────────────────────────┘
Yeni özellikler, çekirdeğe dokunan şeyler dışında (kullanıcılar / projeler / ayarlar / müfredat / konular / dersler / yedek / senkronizasyon / sistem / içe aktarma) DAIMA bir eklentiye aittir.
Çift depolama (v0.7.0)¶
Frontend'in, destek deposunun seçildiği tek bir dikişi vardır:
getStorage(): IStorageService. İki uygulama tek bir sözleşmeyi
karşılar:
apiStorage(varsayılan): FastAPI arka ucuyla konuşanapi/client.tsetrafında ince bir sarmalayıcı.dexieStorage(yerel-öncelikli):storage/ai-providers.tsaracılığıyla tarayıcıdan doğrudan AI çağrıları yaparak tüm 25 SQLAlchemy modelini yansıtan tam IndexedDB yığını.
IStorageService, 22 ad alanını açığa çıkarır (users, projects,
settings, assessment, session with streaming, tracking, tools,
curricula, topics, lessons, plugins, system, backup, export,
subjects, tags, projectTaxonomy, imports, gamification, anki,
pronunciation, notebooklm). Her iki depo da her yöntemi uygular.
Factory, localStorage["adaptive-learner.storage_mode"]'u, ardından
VITE_STORAGE_MODE'u (GH Pages derlemesi tarafından ayarlanan)
okur ve varsayılan olarak api'ye döner. Modları değiştirmek
canlı takas değildir: Ayarlar sayfası seçimi kalıcı olarak
kaydeder ve yeniden yükleme gerektiğini bildiren bir bildirim
gösterir.
Üç katmanlı sırlar (v1.20.0 / Aşama 34)¶
Her AI çağrısı, services/settings.resolve_api_key aracılığıyla
zinciri yürütür:
ADAPTIVE_LEARNER_<PROVIDER>_API_KEYenv değişkeni.~/.config/adaptive_learner/secrets.yamliçindeai.<provider>.api_key.- Fernet ile şifresi çözülmüş DB sütunu.
None— AI çağrısı arayüze bir hata gösterir.
Kaynak atıfı, UserSettingsOut.key_source_* üzerinde
(env / secrets_yaml / settings / none enum) yaşar.
Ayarlar arayüzü, kaynak env veya secrets_yaml olduğunda
Kaydet / Kaldır'ı devre dışı bırakır.
Aynı zincir, sağlayıcı başına default_model geçersiz kılmalarına
da uygulanır; secrets.yaml, Aşama 34 tasarımı uyarınca
arayüz geçersiz kılmasını geçersiz kılar (dosya yapılandırması,
güç kullanıcıları için arayüzü yener).
Eklenti yapısı¶
plugins/adaptive-learner-plugin-<name>/
adaptive_learner_<name>/
plugin.py # <Name>Plugin(BasePlugin), hook implementations
routes.py # FastAPI router (delegates to service functions)
<module>.py # business logic
tests/
test_*.py # pytest tests
pyproject.toml # entry point: [project.entry-points."adaptive_learner.plugins"]
- Eklenti sınıfı
BasePlugin'den (pluginforge) miras alır. - İş mantığı, routes.py'de DEĞİL, kendi modüllerinde yaşar.
- routes.py yalnızca temsil eden FastAPI uç noktalarını içerir.
- Hook spec'leri
backend/app/hookspecs.py'de yaşar. - Eklenti bağımlılıkları sınıf özelliği olarak:
depends_on = ["session"]. - Tüm eklentiler ücretsizdir (MIT). Lisanslama altyapısı
mevcuttur ancak etkin değildir (
LICENSING_ENABLED = False).
Hook'lar (backend/app/hookspecs.py'deki 8 spec)¶
| Hook | Ne Zaman | İlk sonuç? |
|---|---|---|
get_assessment_questions(lang) |
Değerlendirme sayfası yüklemesi | evet |
calculate_profile(answers) |
Değerlendirme gönderme | evet |
create_session_prompt(...) |
Her sohbet dönüşü | evet |
ai_complete(messages, model, api_key, max_tokens) |
Standart AI çağrısı | evet (sağlayıcı, model önekine göre yönlendirir) |
ai_complete_async(...) |
Paralel döngü sınırı değerlendirmesi (v1.5.0) | evet |
ai_complete_stream(...) |
Akışlı oturum yanıtı (v1.6.0) | evet |
recommend_method_switch(...) |
Gösterge Tablosu + Oturum | evet |
on_session_complete(session, rating) |
Oturum sonu | yayın |
get_progress_summary(project_id) |
Gösterge Tablosu widget'ları | yayın |
get_tool_recommendations(profile, lang) |
Gösterge Tablosu araçları | yayın |
Veri akışı¶
UI (React) → IStorageService
→ (API mode) FastAPI router → service → SQLAlchemy → SQLite
→ (Dexie mode) Dexie table → IndexedDB
↓
AI orchestrator → resolve_api_key (env > yaml > DB)
→ pluginforge → provider plugin's ai_complete*
→ Anthropic / OpenAI / Gemini SDK
Tek yönlü. Yönlendiricilerden doğrudan DB erişimi yok (servisler SQLAlchemy işine sahiptir). Arka uçta frontend kodu yok.
Hata yönetimi¶
Frontend ApiError (status + detail) → toast for the user
API client HTTP error → converted to ApiError
Router Thin, catches nothing. Global exception handler maps.
Service Throws AdaptiveLearnerError subclasses
Plugin Throws PluginError(plugin_name, message)
External ExternalServiceError(service, message) for provider SDKs
Servisler ASLA HTTPException fırlatmaz; yönlendiriciler HİÇBİR
ŞEY yakalamaz. main.py'deki global istisna işleyicisi, alan
hatalarını HTTP durum kodlarına eşler. Tam desen için
.claude/rules/code-hygiene.md'ye bakın.
Kalıcılık¶
- Arka uç: SQLAlchemy + SQLite.
backend/migrations/versions/içinde Alembic migrasyonları. - Senkronizasyon yüzeyi: 28 tablo (v1.19.0 temeli). Yalnızca ekleme geçmişi satırları (oturumlar, mesajlar, derecelendirmeler, ilerleme commitler'i, adım değerlendirmeleri, yöntem geçişleri, içe aktarılan konuşmalar, içe aktarılan mesajlar, anki kartları, çalışma soruları) artı değiştirilebilir ayarlar + müfredat satırları.
- Yedek biçimi: JSON; API anahtarları dışa aktarmada çıkarılır; geri yükleme bir birleştirmedir.
- Test yalıtımı: üretim veri dizinleri
.adaptive-learner-productionişaretçisi taşır; bir test bunu görürse, çalıştırmapytest.exit(returncode=2)ile iptal edilir.
Tema¶
5 tema (Classic, Cool Modern, Nord, Notebook, Studio) ×
açık/koyu = 10 varyant. Tamamen CSS değişkenleri; Tailwind yok.
frontend/src/styles/global.css'de özel özellikler. Yeni UI
öğeleri değişken setini KULLANMAK ZORUNDADIR.
Mobil / PWA¶
@media (max-width: 768px), kanonik mobil geçiş noktasıdır
(hamburger çekmecesi, 44×44 dokunmatik hedefler, yığılmış düzenler).
@media (max-width: 360px), aşırı dar güvenlik ağıdır.
Masaüstü stilleri ≥769px değişmez.
Servis çalışanı (Workbox via vite-plugin-pwa): GET /api/'de
4s zaman aşımı, 24h LRU, 60 girdi sınırıyla NetworkFirst.
Mutasyona uğrayan /api/, NetworkOnly'dir.