From 7cb308d03fa2768e3d1f954fbfe57d970be6bc61 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Wed, 10 Sep 2025 00:45:06 +0300 Subject: [PATCH] Add database documentation and setup script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add comprehensive DATABASE_SCHEMA.md with complete SQLite schemas - Document all 3 databases: activities.db, game_library.db, test_activities.db - Include recreation methods, examples, and troubleshooting - Add scripts/create_databases.py for automated database setup - Move README.md to project root for better visibility - Ensure *.db files excluded via .gitignore are fully documented 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/user/README.md => README.md | 0 docs/DATABASE_SCHEMA.md | 307 +++++++++++++++++++++++++++++++ scripts/create_databases.py | 164 +++++++++++++++++ 3 files changed, 471 insertions(+) rename docs/user/README.md => README.md (100%) create mode 100644 docs/DATABASE_SCHEMA.md create mode 100644 scripts/create_databases.py diff --git a/docs/user/README.md b/README.md similarity index 100% rename from docs/user/README.md rename to README.md diff --git a/docs/DATABASE_SCHEMA.md b/docs/DATABASE_SCHEMA.md new file mode 100644 index 0000000..f891451 --- /dev/null +++ b/docs/DATABASE_SCHEMA.md @@ -0,0 +1,307 @@ +# DATABASE SCHEMA DOCUMENTATION + +> Documentația structurii bazelor de date pentru INDEX-SISTEM-JOCURI +> +> **IMPORTANT**: Fișierele `*.db` sunt excluse din git prin `.gitignore`. Această documentație permite recrearea structurii bazelor de date. + +## Prezentare Generală + +Sistemul folosește SQLite pentru stocarea datelor, cu următoarele baze de date: + +- **`activities.db`** - Baza de date principală pentru activități educaționale +- **`game_library.db`** - Baza de date pentru biblioteca de jocuri (sistem legacy) +- **`test_activities.db`** - Baza de date pentru teste + +## 1. ACTIVITIES.DB (Baza de Date Principală) + +### Tabel: `activities` + +Tabelul principal pentru stocarea activităților educaționale (conform PRD Section 5.3). + +```sql +CREATE TABLE IF NOT EXISTS activities ( + id INTEGER PRIMARY KEY, + title TEXT NOT NULL, + description TEXT, + file_path TEXT NOT NULL, + file_type TEXT, + page_number INTEGER, + tags TEXT, + category TEXT, + age_group TEXT, + participants TEXT, + duration TEXT, + materials TEXT, + difficulty TEXT DEFAULT 'mediu', + source_text TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +**Descrierea coloanelor:** + +| Coloană | Tip | Descriere | +|---------|-----|-----------| +| `id` | INTEGER | Cheia primară, auto-increment | +| `title` | TEXT | Titlul activității (obligatoriu) | +| `description` | TEXT | Descrierea activității | +| `file_path` | TEXT | Calea către fișierul sursă (obligatoriu) | +| `file_type` | TEXT | Tipul fișierului (PDF, DOCX, etc.) | +| `page_number` | INTEGER | Numărul paginii în fișierul sursă | +| `tags` | TEXT | Tag-uri în format JSON | +| `category` | TEXT | Categoria activității | +| `age_group` | TEXT | Grupa de vârstă (ex: "8-12 ani") | +| `participants` | TEXT | Numărul de participanți (ex: "5-10 persoane") | +| `duration` | TEXT | Durata activității (ex: "15-30min") | +| `materials` | TEXT | Materialele necesare | +| `difficulty` | TEXT | Dificultatea (implicit: "mediu") | +| `source_text` | TEXT | Textul complet extras din fișier | +| `created_at` | TIMESTAMP | Data creării (implicit: now) | + +### Tabel Virtual: `activities_fts` + +Tabel pentru căutare full-text (FTS5) pentru performanță optimă. + +```sql +CREATE VIRTUAL TABLE IF NOT EXISTS activities_fts USING fts5( + title, description, source_text, + content='activities' +); +``` + +### Tabel: `search_history` + +Istoricul căutărilor pentru analiză și optimizare. + +```sql +CREATE TABLE IF NOT EXISTS search_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + query TEXT NOT NULL, + results_count INTEGER, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +### Tabel: `file_processing_log` + +Log-ul procesării fișierelor pentru urmărirea indexării. + +```sql +CREATE TABLE IF NOT EXISTS file_processing_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_path TEXT NOT NULL, + file_type TEXT, + status TEXT, + activities_extracted INTEGER DEFAULT 0, + error_message TEXT, + processed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +**Status-uri posibile:** +- `processing` - în procesare +- `completed` - finalizat cu succes +- `error` - eroare în procesare +- `skipped` - omis (ex: fișier deja procesat) + +## 2. GAME_LIBRARY.DB (Sistem Legacy) + +### Tabel: `activities` + +Varianta legacy a tabelului de activități. + +```sql +CREATE TABLE IF NOT EXISTS activities ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL, + file_path TEXT NOT NULL, + category TEXT NOT NULL, + subcategory TEXT, + age_group TEXT, + participants TEXT, + duration TEXT, + materials TEXT, + description TEXT, + tags TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +**Diferențe față de tabelul principal:** +- `id` este TEXT (nu INTEGER) +- Lipsesc câmpurile: `file_type`, `page_number`, `difficulty`, `source_text` +- `subcategory` este prezentă doar aici + +### Tabel: `search_history` + +```sql +CREATE TABLE IF NOT EXISTS search_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + query TEXT NOT NULL, + results_count INTEGER, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +## 3. RECREAREA BAZELOR DE DATE + +### Metoda 1: Folosind DatabaseManager (Recomandat) + +```python +from src.database import DatabaseManager + +# Crearea bazei de date principale +db = DatabaseManager("data/activities.db") +print("✅ Baza de date activities.db creată") + +# Crearea bazei de date de test +test_db = DatabaseManager("data/test_activities.db") +print("✅ Baza de date test_activities.db creată") +``` + +### Metoda 2: Folosind game_library_manager + +```python +from src.game_library_manager import GameLibraryManager + +# Crearea bazei legacy +manager = GameLibraryManager("data/game_library.db") +print("✅ Baza de date game_library.db creată") +``` + +### Metoda 3: SQL Direct + +```bash +# Crearea manuală cu sqlite3 +sqlite3 data/activities.db < scripts/create_activities_db.sql +``` + +## 4. POPULAREA CU DATE + +### Indexarea Automată + +```bash +# Rulează din directorul src/ +cd src/ +python indexer.py --clear-db +``` + +**Parametri disponibili:** +- `--clear-db` - șterge și recreează baza de date +- `--base-path` - calea către fișierele de indexat +- `--db-path` - calea către baza de date + +### Testarea Funcționalității + +```bash +# Testează baza de date +cd src/ +python -c "from database import test_database; test_database()" +``` + +## 5. EXEMPLE DE DATE + +### Exemplu Activitate + +```json +{ + "id": 1, + "title": "Jocul Celor 5 Simțuri", + "description": "Activitate pentru dezvoltarea percepției senzoriale", + "file_path": "/path/to/file.pdf", + "file_type": "PDF", + "page_number": 23, + "tags": "[\"senzorial\", \"educativ\", \"interior\"]", + "category": "educativ", + "age_group": "8-12 ani", + "participants": "5-10 persoane", + "duration": "15-30min", + "materials": "Materiale simple", + "difficulty": "mediu", + "source_text": "Textul complet din PDF...", + "created_at": "2025-09-09 12:00:00" +} +``` + +## 6. ÎNTREȚINERE + +### Backup-ul Bazelor de Date + +```bash +# Backup +cp data/activities.db backups/activities_$(date +%Y%m%d_%H%M%S).db + +# Restaurare +cp backups/activities_20250909_120000.db data/activities.db +``` + +### Verificarea Integrității + +```sql +-- Verifică integritatea bazei de date +PRAGMA integrity_check; + +-- Statistici +SELECT + COUNT(*) as total_activities, + COUNT(DISTINCT category) as categories, + COUNT(DISTINCT age_group) as age_groups +FROM activities; +``` + +### Rebuilding FTS Index + +```sql +-- Recreează indexul FTS în caz de probleme +INSERT INTO activities_fts(activities_fts) VALUES('rebuild'); +``` + +## 7. PERFORMANȚĂ + +### Indexuri Recomandate + +```sql +-- Indexuri pentru performanță +CREATE INDEX IF NOT EXISTS idx_activities_category ON activities(category); +CREATE INDEX IF NOT EXISTS idx_activities_age_group ON activities(age_group); +CREATE INDEX IF NOT EXISTS idx_activities_duration ON activities(duration); +CREATE INDEX IF NOT EXISTS idx_activities_file_path ON activities(file_path); +CREATE INDEX IF NOT EXISTS idx_search_history_timestamp ON search_history(timestamp); +``` + +### Optimizări + +```sql +-- Analizează și optimizează +ANALYZE; +VACUUM; +``` + +## 8. TROUBLESHOOTING + +### Probleme Comune + +1. **"Database is locked"** + ```bash + # Verifică procesele care folosesc DB + lsof data/activities.db + ``` + +2. **"No such table"** + ```python + # Recreează schema + from src.database import DatabaseManager + db = DatabaseManager("data/activities.db") + ``` + +3. **FTS nu funcționează** + ```sql + -- Verifică dacă FTS5 este disponibil + SELECT sqlite_version(), sqlite_compileoption_used('ENABLE_FTS5'); + ``` + +### Log-uri + +- Logurile aplicației: vezi console output +- Loguri indexer: vezi tabelul `file_processing_log` +- Loguri căutări: vezi tabelul `search_history` \ No newline at end of file diff --git a/scripts/create_databases.py b/scripts/create_databases.py new file mode 100644 index 0000000..515d3a4 --- /dev/null +++ b/scripts/create_databases.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +DATABASE SETUP SCRIPT - INDEX-SISTEM-JOCURI + +Script pentru recrearea bazelor de date din .gitignore +Folosește clasele DatabaseManager pentru consistență + +Usage: + python scripts/create_databases.py + python scripts/create_databases.py --clear-existing +""" + +import sys +import argparse +from pathlib import Path + +# Add src to path so we can import our modules +sys.path.append(str(Path(__file__).parent.parent / 'src')) + +from database import DatabaseManager +from game_library_manager import GameLibraryManager + +def create_main_database(db_path: str = "data/activities.db", clear: bool = False): + """Create the main activities database""" + db_file = Path(db_path) + + if clear and db_file.exists(): + print(f"🗑️ Removing existing database: {db_path}") + db_file.unlink() + + print(f"📊 Creating main database: {db_path}") + db = DatabaseManager(db_path) + + # Test the database + try: + stats = db.get_statistics() + print(f"✅ Database created successfully: {stats['total_activities']} activities") + return True + except Exception as e: + print(f"❌ Error creating database: {e}") + return False + +def create_game_library_database(db_path: str = "data/game_library.db", clear: bool = False): + """Create the legacy game library database""" + db_file = Path(db_path) + + if clear and db_file.exists(): + print(f"🗑️ Removing existing database: {db_path}") + db_file.unlink() + + print(f"📊 Creating game library database: {db_path}") + manager = GameLibraryManager(db_path) + + print(f"✅ Game library database created successfully") + return True + +def create_test_database(db_path: str = "data/test_activities.db", clear: bool = False): + """Create the test database""" + db_file = Path(db_path) + + if clear and db_file.exists(): + print(f"🗑️ Removing existing database: {db_path}") + db_file.unlink() + + print(f"📊 Creating test database: {db_path}") + db = DatabaseManager(db_path) + + # Add some test data + test_activity = { + 'title': 'Test Activity - Setup Script', + 'description': 'This is a test activity created by the setup script', + 'file_path': 'test/sample.txt', + 'file_type': 'TXT', + 'category': 'test', + 'age_group': '8-12 ani', + 'participants': '5-10 persoane', + 'duration': '15-30min', + 'materials': 'Fără materiale', + 'tags': '["test", "setup"]', + 'source_text': 'Sample test content for verification' + } + + try: + db.insert_activity(test_activity) + stats = db.get_statistics() + print(f"✅ Test database created with sample data: {stats['total_activities']} activities") + return True + except Exception as e: + print(f"❌ Error creating test database: {e}") + return False + +def ensure_data_directory(): + """Ensure the data directory exists""" + data_dir = Path("data") + if not data_dir.exists(): + print(f"📁 Creating data directory: {data_dir}") + data_dir.mkdir(parents=True) + else: + print(f"📁 Data directory exists: {data_dir}") + +def main(): + """Main setup function""" + parser = argparse.ArgumentParser(description='Create databases for INDEX-SISTEM-JOCURI') + parser.add_argument('--clear-existing', '-c', action='store_true', + help='Remove existing databases before creating new ones') + parser.add_argument('--main-only', action='store_true', + help='Create only the main activities database') + parser.add_argument('--test-only', action='store_true', + help='Create only the test database') + + args = parser.parse_args() + + print("🚀 DATABASE SETUP - INDEX-SISTEM-JOCURI") + print("=" * 50) + + # Ensure data directory exists + ensure_data_directory() + + success_count = 0 + total_count = 0 + + if args.test_only: + total_count = 1 + if create_test_database(clear=args.clear_existing): + success_count += 1 + elif args.main_only: + total_count = 1 + if create_main_database(clear=args.clear_existing): + success_count += 1 + else: + # Create all databases + databases = [ + ("Main activities", lambda: create_main_database(clear=args.clear_existing)), + ("Game library", lambda: create_game_library_database(clear=args.clear_existing)), + ("Test activities", lambda: create_test_database(clear=args.clear_existing)) + ] + + total_count = len(databases) + + for name, create_func in databases: + print(f"\n📂 Creating {name} database...") + try: + if create_func(): + success_count += 1 + except Exception as e: + print(f"❌ Failed to create {name} database: {e}") + + print("\n" + "=" * 50) + print(f"🎯 SUMMARY: {success_count}/{total_count} databases created successfully") + + if success_count == total_count: + print("✅ All databases ready!") + print("\nNext steps:") + print("1. Run indexer: cd src && python indexer.py --clear-db") + print("2. Start web app: cd src && python app.py") + else: + print("⚠️ Some databases failed to create. Check errors above.") + return 1 + + return 0 + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file