Add database documentation and setup script
- 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 <noreply@anthropic.com>
This commit is contained in:
307
docs/DATABASE_SCHEMA.md
Normal file
307
docs/DATABASE_SCHEMA.md
Normal file
@@ -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`
|
||||||
164
scripts/create_databases.py
Normal file
164
scripts/create_databases.py
Normal file
@@ -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())
|
||||||
Reference in New Issue
Block a user