Επίπεδο αποθήκευσης¶
Το επίπεδο αποθήκευσης v0.7.0 (frontend/src/storage/) δίνει στο
frontend δύο εναλλάξιμα backends πίσω από ένα ενιαίο συμβόλαιο.
Το συμβόλαιο έχει αναπτυχθεί σε 22 namespaces κατά τις Phases 7–34.
IStorageService¶
Το frontend/src/storage/types.ts ορίζει τη διεπαφή που κάθε
υλοποίηση αποθήκευσης ικανοποιεί. Αντικατοπτρίζει τα namespaces
api.* από το api/client.ts 1:1:
export interface IStorageService {
readonly mode: StorageMode;
health(): Promise<HealthInfo>;
// Core
i18n: II18nNamespace;
users: IUsersNamespace;
projects: IProjectsNamespace;
settings: ISettingsNamespace; // get/set including key_source_*
assessment: IAssessmentNamespace;
session: ISessionNamespace; // includes streamMessage()
tracking: ITrackingNamespace;
tools: IToolsNamespace;
curricula: ICurriculaNamespace;
topics: ITopicsNamespace;
lessons: ILessonsNamespace;
plugins: IPluginsNamespace;
system: ISystemNamespace;
// Phase 12+
backup: IBackupNamespace;
export: IExportNamespace;
imports: IImportsNamespace;
// Phase 22 — taxonomy
subjects: ISubjectsNamespace;
tags: ITagsNamespace;
projectTaxonomy: IProjectTaxonomyNamespace;
// Phase 29-32 — gamification + exports
gamification: IGamificationNamespace;
anki: IAnkiNamespace;
notebooklm: INotebookLmNamespace;
pronunciation: IPronunciationNamespace;
}
Κάθε σελίδα καταναλώνει IStorageService μέσω του factory
getStorage(). Οι σελίδες δεν εισάγουν ποτέ απευθείας το
api/client.ts ή τη βάση δεδομένων Dexie.
ApiStorage¶
Το storage/api-storage.ts είναι λεπτό pass-through στο api.*.
Κάθε μέθοδος αναθέτει 1:1. Η συμπεριφορά είναι πανομοιότυπη με
αυτή του v0.6.0.
DexieStorage¶
Το storage/dexie-storage.ts αποθηκεύει τα πάντα στο IndexedDB
μέσω Dexie 4.4.2. Το σχήμα στο storage/db.ts αντικατοπτρίζει
και τα 25 μοντέλα SQLAlchemy 1:1, συν τους 4 πίνακες σύνδεσης
(project_subjects / project_tags / κ.λπ.).
Υπο-modules στο storage/ φέρουν τη μεταφερμένη λογική:
| Module | Αρμοδιότητα |
|---|---|
assessment.ts |
Πακέτο 12 ερωτήσεων + υπολογιστής προφίλ |
prompts.ts |
Πίνακας system-prompt 42 κελιών |
step-evaluator.ts |
Θύρα αξιολόγησης βήματος διπλής προτροπής |
session-flow.ts |
Ενορχήστρωση έναρξης + μηνύματος |
tracking.ts |
Αθροιστής + buildCommitFromSession |
tools.ts |
rankTools + buildSpacedRecommendations |
ai-providers.ts |
HTTP clients Anthropic/OpenAI/Gemini |
Δεδομένα bundle βρίσκονται στο frontend/src/data/:
assessment-questions.json— εξαγόμενο αυτούσιο από τη λίσταQUESTIONSτου backend (12 ερωτήσεις × 4 απαντήσεις × 5 γλώσσες).session-prompts.json— εξαγόμενο αυτούσιο από το dict_PROMPTSτου backend (6 μέθοδοι × 7 βήματα × 2 γλώσσες).
Προσθήκη τρίτου storage backend¶
Υλοποίησε IStorageService με όποιο επίπεδο επιμονής θέλεις
(Supabase, Firestore, custom REST API). Καταχώρισέ το στο factory
του storage/index.ts:
Πρόσθεσε τη λειτουργία στον τύπο StorageMode:
Σύνδεσέ το στο τμήμα storage-mode του UI Ρυθμίσεων. Χωρίς άλλες
αλλαγές αρχείων — οι σελίδες εξακολουθούν να χρησιμοποιούν το
getStorage().
Άμεσες κλήσεις ΤΝ από browser¶
Το storage/ai-providers.ts υλοποιεί τρεις clients παρόχων:
- Anthropic — POST στο
https://api.anthropic.com/v1/messagesμε την επικεφαλίδαanthropic-dangerous-direct-browser-access: true. Αυτή είναι η ρητή δυνατότητα opt-in του Anthropic για κλήσεις από browser· χωρίς αυτή το CORS απορρίπτει. - OpenAI — POST στο
https://api.openai.com/v1/chat/completionsμεAuthorization: Bearer ${apiKey}. Το CORS είναι ανοιχτό από προεπιλογή. - Gemini — POST στο
https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={apiKey}. Πιστοποίηση με query-param· χωρίς πεδίο system· τα system messages ενσωματώνονται στην πρώτη σειρά χρήστη.
Και οι τρεις κανονικοποιούν τα σφάλματα σε ApiError(status, "Provider: detail")
ώστε το υπάρχον frontend toast / GitHub-Issue UX να τα αποδίδει
χωρίς διακλαδώσεις.
Γιατί cleartext API keys στη λειτουργία Dexie;¶
Στη λειτουργία Dexie το API key του χρήστη βρίσκεται στο IndexedDB
σε cleartext (UserSettings.api_key_{provider}). Αποδεκτό μοντέλο
απειλής:
- Τα δεδομένα δεν εγκαταλείπουν ποτέ τη συσκευή του χρήστη.
- Ο πάροχος ΤΝ ΕΙΝΑΙ το μόνο endpoint δικτύου που βλέπει ποτέ το κλειδί.
- Η κρυπτογράφηση στο IndexedDB θα απαιτούσε είτε προτροπή κωδικού ανά συνεδρία (εχθρικό UX) είτε σταθερό κλειδί ενσωματωμένο στην εφαρμογή (θέατρο ασφαλείας — ο εισβολέας έχει το bundle).
Η συμπεριφορά Server-mode είναι διαφορετική: τα API keys περνούν
από κρυπτογράφηση Fernet σε ηρεμία (ADAPTIVE_LEARNER_SECRET_KEY).
Το ApiStorage δεν βλέπει ποτέ το cleartext.
Από v1.20.0 / Phase 34, και οι δύο λειτουργίες εκθέτουν επίσης
μια απόδοση πηγής ανά πάροχο
(UserSettings.key_source_anthropic | openai | gemini) ώστε το UI
να αποδίδει "Key from: secrets.yaml" / "environment" / "Settings".
Στη λειτουργία Dexie η πηγή καταρρέει σε settings ή none
επειδή το sandbox browser δεν έχει πρόσβαση στο filesystem —
το secrets.yaml είναι έννοια desktop / server-mode.
Επίλυση λειτουργίας¶
Το storage/index.ts επιλύει τη λειτουργία με αυτή τη σειρά:
localStorage["adaptive-learner.storage_mode"]— επιλογή χρήστη από Ρυθμίσεις.VITE_STORAGE_MODE— προεπιλογή χρόνου build (το GH Pages το ορίζει σε"dexie").- Εναλλακτική:
"api".
Το αποτέλεσμα αποθηκεύεται για τη διάρκεια ζωής της σελίδας.
Ο κώδικας τεστ μπορεί να επαναφέρει μέσω _resetStorageCacheForTests().