diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4b725dd --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +ENVIRONMENT=development +DATABASE_PATH=archivium.db +ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da56cb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,67 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +env/ + +# Database +*.db +*.sqlite +*.sqlite3 + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Environment +.env +.env.local +.env.*.local + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# OS +.DS_Store +Thumbs.db + +# Node/Frontend +node_modules/ +npm-debug.log +yarn-error.log +dist/ +build/ + +# Lock files (optional - uncomment if you want to enforce exact versions) +# package-lock.json +# pnpm-lock.yaml + diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/Editor.iml b/.idea/Editor.iml deleted file mode 100644 index d8b3f6c..0000000 --- a/.idea/Editor.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 1d3ce46..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 3206d78..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2d9281f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,83 @@ +# Changelog + +## [0.1.1] - 2026-04-09 + +### Changed +- Reorganized project structure: moved all modules to `src/` folder +- Refactored endpoints into separate router modules: + - `src/routers/init.py` - System initialization endpoint + - `src/routers/login.py` - Authentication endpoint + - `src/routers/status.py` - Status check endpoint +- Reduced `main.py` from 100+ lines to 35 lines (only app configuration) +- Updated all internal imports to use relative imports within `src/` + +### Project Structure +``` +archivium-backend/ +├── main.py # Entry point (35 lines) +├── src/ +│ ├── __init__.py +│ ├── config.py # Configuration +│ ├── models.py # Database models +│ ├── schemas.py # Request/response schemas +│ ├── database.py # Database setup +│ ├── security.py # Password hashing +│ └── routers/ +│ ├── __init__.py +│ ├── init.py # POST /api/init +│ ├── login.py # POST /api/login +│ └── status.py # GET /api/status +├── pyproject.toml +├── requirements.txt +└── README.md +``` + +--- + +## [0.1.0] - 2026-04-09 + +### Changed +- Removed excessive Polish comments and restructured code for readability +- Refactored monolithic `main.py` into modular structure: + - `config.py` - Environment configuration and CORS settings + - `models.py` - SQLAlchemy ORM models + - `schemas.py` - Pydantic request/response schemas with validation + - `database.py` - Database initialization and session management + - `security.py` - Password hashing and recovery key generation + - `main.py` - FastAPI application and endpoint handlers +- Added official Python docstrings for public functions and classes only +- Improved project metadata with description and version in FastAPI app + +### Security Improvements +- Restricted CORS to explicit allowed origins instead of wildcard ("*") +- Limited allowed HTTP methods to POST and GET only +- Restricted allowed headers to Content-Type only +- Added password validation (minimum 8 characters, maximum 128) +- Improved error handling with try-except for password verification +- Database operations now properly managed with dependency injection + +### Added +- `pyproject.toml` for modern Python package management (compatible with uv) +- `requirements.txt` for traditional pip/env management +- Proper dependency pinning with specific versions +- Database initialization on startup event +- Dependency injection for database sessions via `Depends(get_db)` +- Recovery key generation moved to dedicated security module +- Startup lifecycle event to ensure schema creation + +### Dependencies +- fastapi>=0.104.0 +- uvicorn[standard]>=0.24.0 +- pydantic>=2.5.0 +- sqlalchemy>=2.0.0 +- passlib[argon2]>=1.7.4 + +### Notes +- SQLite remains in use for development (no encryption at rest) +- For production deployment, consider: + - Using PostgreSQL or equivalent encrypted database + - Setting ENVIRONMENT=production env var + - Configuring CORS_ORIGINS for specific domains + - Enabling HTTPS/SSL + - Implementing rate limiting + - Adding request logging and monitoring diff --git a/README.md b/README.md new file mode 100644 index 0000000..1c7a486 --- /dev/null +++ b/README.md @@ -0,0 +1,334 @@ +# 📚 Archivium - System Zarządzania Archiwum + +**Archivium** to integrowany system do szyfrowania, przechowywania i wyszukiwania archiwów z bezpiecznym uwierzytelnianiem i interfejsem edytora tekstu. + +## 🏗️ Architektura projektu + +``` +archivium/ +├── backend/ +│ ├── app/ # Nowoczesny backend FastAPI +│ │ ├── src/ +│ │ │ ├── config.py # Konfiguracja +│ │ │ ├── models.py # Modele bazy +│ │ │ ├── schemas.py # Walidacja +│ │ │ ├── database.py # Zarządzanie BD +│ │ │ ├── security.py # Hashing hasła +│ │ │ └── routers/ # Endpointy API +│ │ │ ├── init.py +│ │ │ ├── login.py +│ │ │ └── status.py +│ │ ├── main.py # Punkt wejścia (35 linii) +│ │ └── pyproject.toml +│ │ +│ └── legacy/ # Stare moduły bazy danych +│ ├── relational_database.py +│ └── vector_database.py +│ +├── frontend/ # React aplikacja (edytor tekstu) +│ ├── public/ +│ ├── src/ +│ └── package.json +│ +├── launcher.py # Uruchamiacz całej aplikacji +├── requirements.txt # Zależności Python +├── README.md # Ta dokumentacja +├── CHANGELOG.md # Historia zmian +└── .git/ # Repozytorium Git +``` + +## 🚀 Szybki start + +### Uruchomienie całej aplikacji (jedno polecenie) + +```bash +python launcher.py +``` + +To uruchomi: +- ✅ Backend FastAPI (port 8000) +- ✅ Frontend React (port 3000) +- ✅ Otworzy przeglądarkę na http://localhost:3000 + +### Ręczne uruchomienie poszczególnych części + +**Backend:** +```bash +cd backend/app +python main.py +``` + +**Frontend:** +```bash +cd frontend +npm install +npm start +``` + +## 📡 API Endpoints + +### 1. Inicjalizacja systemu +```http +POST /api/init +Content-Type: application/json + +{ + "password": "twoje_bezpieczne_haslo_8znaków_min" +} +``` + +**Response:** +```json +{ + "status": "success", + "recovery_key": "a1b2c3d4e5f6...", + "message": "System initialized. Save recovery key in safe place." +} +``` + +### 2. Logowanie - hasłem głównym +```http +POST /api/login +Content-Type: application/json + +{ + "password": "twoje_haslo", + "is_recovery": false +} +``` + +**Response:** +```json +{ + "status": "success", + "message": "Successfully authenticated" +} +``` + +### 3. Logowanie - kluczem awaryjnym +```http +POST /api/login +Content-Type: application/json + +{ + "password": "a1b2c3d4e5f6...", + "is_recovery": true +} +``` + +**Response:** +```json +{ + "status": "success", + "message": "Authenticated with recovery key. Please change password." +} +``` + +### 4. Sprawdzenie statusu +```http +GET /api/status +``` + +**Response:** +```json +{ + "is_initialized": true +} +``` + +## 🔐 Bezpieczeństwo + +### Zaimplementowane zabezpieczenia: +- ✅ **Hashing haseł** - Argon2 (type="ID") +- ✅ **Losowe klucze awaryjne** - 32 znaki hex +- ✅ **CORS** - ograniczony do zaufanych domen +- ✅ **Walidacja danych** - Pydantic +- ✅ **Dwie ścieżki dostępu** - hasło główne + klucz awaryjny + +### Zmienne środowiskowe (.env) +```bash +ENVIRONMENT=development # development | production +DATABASE_PATH=archivium.db # lokalizacja bazy +ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173 +``` + +### Rekomendacje produkcyjne: +1. Użyj **PostgreSQL** zamiast SQLite +2. Włącz **HTTPS/SSL** +3. Dodaj **rate limiting** +4. Włącz **logging i monitoring** +5. Regularne **backupy** bazy danych +6. Przechowuj sekrety w zmiennych środowiskowych + +## 📚 Szczegółowa dokumentacja struktury + +### Backend - Endpointy (src/routers/) + +**init.py** - `POST /api/init` +- Inicjalizuje system +- Generuje recovery key (32 znaki) +- Hashuje hasło główne z Argon2 + +**login.py** - `POST /api/login` +- Logowanie hasłem głównym lub kluczem awaryjnym +- Weryfikuje hash haseł +- Zwraca status autoryzacji + +**status.py** - `GET /api/status` +- Sprawdza czy system zainicjalizowany +- Zwraca boolean `is_initialized` + +### Backend - Core modules (src/) + +**config.py** - Konfiguracja +- CORS configuration +- DATABASE_PATH z zmiennych środowiskowych +- ALLOWED_ORIGINS + +**models.py** - SQLAlchemy ORM +- SecurityConfig model +- Tabela `security_config` +- Przechowuje hashe haseł i kluczy + +**schemas.py** - Pydantic validation +- InitRequest - walidacja do /api/init +- LoginRequest - walidacja do /api/login + +**database.py** - Zarządzanie bazą +- SQLite setup +- Session management +- `init_db()` - inicjalizuje schemat +- `get_db()` - dependency injection dla sessionów + +**security.py** - Funkcje bezpieczeństwa +- `hash_password(password: str) -> str` +- `verify_password(password: str, hash_value: str) -> bool` +- `generate_recovery_key() -> str` + +**main.py** - FastAPI aplikacja (35 linii!) +- Konfiguracja CORS middleware +- Include routery +- Startup event dla init_db() + +## 🛠️ Development + +### Instalacja dependencies + +```bash +# Backend +pip install -r requirements.txt + +# Lub z uv: +cd backend/app && uv sync + +# Frontend +cd frontend && npm install +``` + +### Testowanie API + +```bash +# Curl - Inicjalizacja +curl -X POST http://localhost:8000/api/init \ + -H "Content-Type: application/json" \ + -d '{"password": "TestPassword123"}' + +# Curl - Logowanie +curl -X POST http://localhost:8000/api/login \ + -H "Content-Type: application/json" \ + -d '{"password": "TestPassword123", "is_recovery": false}' + +# Status +curl http://localhost:8000/api/status +``` + +### Dokumentacja interaktywna + +Gdy serwer działa, otwórz: **http://localhost:8000/docs** +- Swagger UI do testowania API +- Automatyczna dokumentacja OpenAPI +- Try it out - testuj bezpośrednio z przeglądarki + +## 📝 Historia zmian + +Pełna historia zmian w [CHANGELOG.md](CHANGELOG.md) + +### v0.1.1 - Monorepo Integration +- Reorganizacja całego projektu do struktury monorepo +- Backend w `backend/app/` (35 linii main.py!) +- Launcher do uruchamiania całej aplikacji +- Integracja z starym kodem z `Database/` i `TextEditor/` +- Kompletna dokumentacja + +### v0.1.0 - Refactorization +- Refaktoryzacja kodu, usunięcie komentarzy +- Modularyzacja na src/ +- Bezpieczeństwo (CORS, Argon2, walidacja) + +## 🐛 Troubleshooting + +### Problem: Port 8000 już w użyciu +```bash +# Zmień w backend/app/main.py lub użyj: +cd backend/app && uv run uvicorn main:app --port 8001 +``` + +### Problem: Frontend nie łączy się z backendem +Sprawdź w `backend/app/src/config.py`: +```python +ALLOWED_ORIGINS = ["http://localhost:3000"] +``` + +### Problem: Baza danych uszkodzona +```bash +rm archivium.db # Usuń stary plik +python launcher.py # Przeinicjalizuj +``` + +### Problem: npm start nie działa +```bash +cd frontend +rm -rf node_modules package-lock.json +npm install +npm start +``` + +## 👥 Współpraca (Git) + +```bash +# Clone repozytorium +git clone http://gitea.archvium.eu:30230/SzymonS/Kod.git + +# Stwórz feature branch +git checkout -b feature/my-feature + +# Commit +git add . +git commit -am "Add new feature" + +# Push +git push origin feature/my-feature +``` + +## 📦 Zależności + +### Backend (Python) +- **FastAPI** (0.104.0+) - Framework +- **SQLAlchemy** (2.0.0+) - ORM +- **Pydantic** (2.5.0+) - Walidacja +- **Passlib[argon2]** (1.7.4+) - Hashing +- **Uvicorn** (0.24.0+) - ASGI server + +### Frontend (Node.js) +- **React** - UI framework +- Inne (patrz: `frontend/package.json`) + +Pełna lista: [requirements.txt](requirements.txt) + +## 📞 Support + +Kontakt: SzymonS @ gitea.archvium.eu + +--- + +**Ostatnia aktualizacja:** April 9, 2026 diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..8f67450 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,35 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +from src.config import ALLOWED_ORIGINS +from src.database import init_db +from src.routers import init, login, status + +app = FastAPI( + title="Archivium Local Backend", + description="Local archive encryption and authentication system", + version="0.1.0", +) + +app.add_middleware( + CORSMiddleware, + allow_origins=ALLOWED_ORIGINS, + allow_credentials=True, + allow_methods=["POST", "GET"], + allow_headers=["Content-Type"], +) + +app.include_router(init.router) +app.include_router(login.router) +app.include_router(status.router) + + +@app.on_event("startup") +def startup(): + """Initialize database on startup.""" + init_db() + + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="127.0.0.1", port=8000) diff --git a/backend/app/pyproject.toml b/backend/app/pyproject.toml new file mode 100644 index 0000000..42b944e --- /dev/null +++ b/backend/app/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "archivium-backend" +version = "0.1.0" +description = "Local archive encryption and authentication system" +requires-python = ">=3.9,<3.13" +dependencies = [ + "fastapi>=0.104.0", + "uvicorn[standard]>=0.24.0", + "pydantic>=2.5.0", + "sqlalchemy>=2.0.0", + "passlib[argon2]>=1.7.4", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.0.0", + "pytest-asyncio>=0.21.0", + "httpx>=0.25.0", +] diff --git a/backend/app/src/__init__.py b/backend/app/src/__init__.py new file mode 100644 index 0000000..ea83667 --- /dev/null +++ b/backend/app/src/__init__.py @@ -0,0 +1 @@ +"""Archivium Backend Application.""" diff --git a/backend/app/src/config.py b/backend/app/src/config.py new file mode 100644 index 0000000..5de5b9b --- /dev/null +++ b/backend/app/src/config.py @@ -0,0 +1,10 @@ +import os + +DB_PATH = os.getenv("DATABASE_PATH", "archivium.db") + +ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000,http://localhost:5173").split(",") + +if os.getenv("ENVIRONMENT") == "development": + ALLOWED_ORIGINS = ["http://localhost:3000", "http://localhost:5173"] +elif os.getenv("ENVIRONMENT") == "production": + ALLOWED_ORIGINS = os.getenv("CORS_ORIGINS", "").split(",") diff --git a/backend/app/src/database.py b/backend/app/src/database.py new file mode 100644 index 0000000..d51db8c --- /dev/null +++ b/backend/app/src/database.py @@ -0,0 +1,28 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker, Session + +from .config import DB_PATH +from .models import Base + +DATABASE_URL = f"sqlite:///{DB_PATH}" + +engine = create_engine( + DATABASE_URL, + connect_args={"check_same_thread": False}, +) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + + +def init_db(): + """Initialize database schema.""" + Base.metadata.create_all(bind=engine) + + +def get_db(): + """Provide database session for dependency injection.""" + db = SessionLocal() + try: + yield db + finally: + db.close() diff --git a/backend/app/src/models.py b/backend/app/src/models.py new file mode 100644 index 0000000..9f540ae --- /dev/null +++ b/backend/app/src/models.py @@ -0,0 +1,13 @@ +from sqlalchemy import Column, Integer, String +from sqlalchemy.orm import declarative_base + +Base = declarative_base() + + +class SecurityConfig(Base): + """Storage for password and recovery key hashes.""" + __tablename__ = "security_config" + + id = Column(Integer, primary_key=True, index=True) + password_hash = Column(String, nullable=False) + recovery_key_hash = Column(String, nullable=False) diff --git a/backend/app/src/routers/__init__.py b/backend/app/src/routers/__init__.py new file mode 100644 index 0000000..21109f0 --- /dev/null +++ b/backend/app/src/routers/__init__.py @@ -0,0 +1 @@ +"""Routers for Archivium Backend.""" diff --git a/backend/app/src/routers/init.py b/backend/app/src/routers/init.py new file mode 100644 index 0000000..12fca20 --- /dev/null +++ b/backend/app/src/routers/init.py @@ -0,0 +1,39 @@ +import os +from fastapi import APIRouter, HTTPException, Depends +from sqlalchemy.orm import Session + +from ..database import get_db +from ..models import SecurityConfig +from ..schemas import InitRequest +from ..security import hash_password, generate_recovery_key +from ..config import DB_PATH + +router = APIRouter(prefix="/api", tags=["init"]) + + +@router.post("/init") +def initialize_system(request: InitRequest, db: Session = Depends(get_db)): + """Initialize system with master password and generate recovery key.""" + if os.path.exists(DB_PATH): + raise HTTPException( + status_code=400, + detail="System already initialized", + ) + + recovery_key = generate_recovery_key() + hashed_password = hash_password(request.password) + hashed_recovery = hash_password(recovery_key) + + db.add( + SecurityConfig( + password_hash=hashed_password, + recovery_key_hash=hashed_recovery, + ) + ) + db.commit() + + return { + "status": "success", + "recovery_key": recovery_key, + "message": "System initialized. Save recovery key in safe place.", + } diff --git a/backend/app/src/routers/login.py b/backend/app/src/routers/login.py new file mode 100644 index 0000000..a1ca6be --- /dev/null +++ b/backend/app/src/routers/login.py @@ -0,0 +1,50 @@ +import os +from fastapi import APIRouter, HTTPException, Depends +from sqlalchemy.orm import Session + +from ..database import get_db +from ..models import SecurityConfig +from ..schemas import LoginRequest +from ..security import verify_password +from ..config import DB_PATH + +router = APIRouter(prefix="/api", tags=["login"]) + + +@router.post("/login") +def login(request: LoginRequest, db: Session = Depends(get_db)): + """Authenticate with master password or recovery key.""" + if not os.path.exists(DB_PATH): + raise HTTPException( + status_code=404, + detail="System not initialized", + ) + + config = db.query(SecurityConfig).first() + if not config: + raise HTTPException( + status_code=500, + detail="System configuration error", + ) + + if request.is_recovery: + if not verify_password(request.password, config.recovery_key_hash): + raise HTTPException( + status_code=401, + detail="Invalid recovery key", + ) + return { + "status": "success", + "message": "Authenticated with recovery key. Please change password.", + } + + if not verify_password(request.password, config.password_hash): + raise HTTPException( + status_code=401, + detail="Invalid password", + ) + + return { + "status": "success", + "message": "Successfully authenticated", + } diff --git a/backend/app/src/routers/status.py b/backend/app/src/routers/status.py new file mode 100644 index 0000000..edad17f --- /dev/null +++ b/backend/app/src/routers/status.py @@ -0,0 +1,12 @@ +import os +from fastapi import APIRouter + +from ..config import DB_PATH + +router = APIRouter(prefix="/api", tags=["status"]) + + +@router.get("/status") +def get_status(): + """Check if system is initialized.""" + return {"is_initialized": os.path.exists(DB_PATH)} diff --git a/backend/app/src/schemas.py b/backend/app/src/schemas.py new file mode 100644 index 0000000..16d043a --- /dev/null +++ b/backend/app/src/schemas.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, Field + + +class InitRequest(BaseModel): + password: str = Field(..., min_length=8, max_length=128) + + +class LoginRequest(BaseModel): + password: str = Field(..., min_length=1, max_length=128) + is_recovery: bool = False diff --git a/backend/app/src/security.py b/backend/app/src/security.py new file mode 100644 index 0000000..a5d4f23 --- /dev/null +++ b/backend/app/src/security.py @@ -0,0 +1,20 @@ +import secrets +from passlib.hash import argon2 + + +def hash_password(password: str) -> str: + """Hash password using Argon2.""" + return argon2.using(type="ID").hash(password) + + +def verify_password(password: str, hash_value: str) -> bool: + """Verify password against hash.""" + try: + return argon2.using(type="ID").verify(password, hash_value) + except Exception: + return False + + +def generate_recovery_key() -> str: + """Generate random recovery key (32 hex characters).""" + return secrets.token_hex(16) diff --git a/Database/local_model_miniLM/1_Pooling/config.json b/backend/legacy/local_model_miniLM/1_Pooling/config.json similarity index 100% rename from Database/local_model_miniLM/1_Pooling/config.json rename to backend/legacy/local_model_miniLM/1_Pooling/config.json diff --git a/Database/local_model_miniLM/README.md b/backend/legacy/local_model_miniLM/README.md similarity index 100% rename from Database/local_model_miniLM/README.md rename to backend/legacy/local_model_miniLM/README.md diff --git a/Database/local_model_miniLM/config.json b/backend/legacy/local_model_miniLM/config.json similarity index 100% rename from Database/local_model_miniLM/config.json rename to backend/legacy/local_model_miniLM/config.json diff --git a/Database/local_model_miniLM/config_sentence_transformers.json b/backend/legacy/local_model_miniLM/config_sentence_transformers.json similarity index 100% rename from Database/local_model_miniLM/config_sentence_transformers.json rename to backend/legacy/local_model_miniLM/config_sentence_transformers.json diff --git a/Database/local_model_miniLM/model.safetensors b/backend/legacy/local_model_miniLM/model.safetensors similarity index 100% rename from Database/local_model_miniLM/model.safetensors rename to backend/legacy/local_model_miniLM/model.safetensors diff --git a/Database/local_model_miniLM/modules.json b/backend/legacy/local_model_miniLM/modules.json similarity index 100% rename from Database/local_model_miniLM/modules.json rename to backend/legacy/local_model_miniLM/modules.json diff --git a/Database/local_model_miniLM/sentence_bert_config.json b/backend/legacy/local_model_miniLM/sentence_bert_config.json similarity index 100% rename from Database/local_model_miniLM/sentence_bert_config.json rename to backend/legacy/local_model_miniLM/sentence_bert_config.json diff --git a/Database/local_model_miniLM/tokenizer.json b/backend/legacy/local_model_miniLM/tokenizer.json similarity index 100% rename from Database/local_model_miniLM/tokenizer.json rename to backend/legacy/local_model_miniLM/tokenizer.json diff --git a/Database/local_model_miniLM/tokenizer_config.json b/backend/legacy/local_model_miniLM/tokenizer_config.json similarity index 100% rename from Database/local_model_miniLM/tokenizer_config.json rename to backend/legacy/local_model_miniLM/tokenizer_config.json diff --git a/Database/relational_database.py b/backend/legacy/relational_database.py similarity index 100% rename from Database/relational_database.py rename to backend/legacy/relational_database.py diff --git a/Database/vector_database.py b/backend/legacy/vector_database.py similarity index 100% rename from Database/vector_database.py rename to backend/legacy/vector_database.py diff --git a/TextEditor/.gitignore b/frontend/.gitignore similarity index 100% rename from TextEditor/.gitignore rename to frontend/.gitignore diff --git a/TextEditor/README.md b/frontend/README.md similarity index 100% rename from TextEditor/README.md rename to frontend/README.md diff --git a/TextEditor/package-lock.json b/frontend/package-lock.json similarity index 100% rename from TextEditor/package-lock.json rename to frontend/package-lock.json diff --git a/TextEditor/package.json b/frontend/package.json similarity index 100% rename from TextEditor/package.json rename to frontend/package.json diff --git a/TextEditor/public/favicon.ico b/frontend/public/favicon.ico similarity index 100% rename from TextEditor/public/favicon.ico rename to frontend/public/favicon.ico diff --git a/TextEditor/public/index.html b/frontend/public/index.html similarity index 100% rename from TextEditor/public/index.html rename to frontend/public/index.html diff --git a/TextEditor/public/logo192.png b/frontend/public/logo192.png similarity index 100% rename from TextEditor/public/logo192.png rename to frontend/public/logo192.png diff --git a/TextEditor/public/logo512.png b/frontend/public/logo512.png similarity index 100% rename from TextEditor/public/logo512.png rename to frontend/public/logo512.png diff --git a/TextEditor/public/manifest.json b/frontend/public/manifest.json similarity index 100% rename from TextEditor/public/manifest.json rename to frontend/public/manifest.json diff --git a/TextEditor/public/robots.txt b/frontend/public/robots.txt similarity index 100% rename from TextEditor/public/robots.txt rename to frontend/public/robots.txt diff --git a/TextEditor/src/App.css b/frontend/src/App.css similarity index 100% rename from TextEditor/src/App.css rename to frontend/src/App.css diff --git a/TextEditor/src/App.js b/frontend/src/App.js similarity index 100% rename from TextEditor/src/App.js rename to frontend/src/App.js diff --git a/TextEditor/src/App.test.js b/frontend/src/App.test.js similarity index 100% rename from TextEditor/src/App.test.js rename to frontend/src/App.test.js diff --git a/TextEditor/src/MathField.js b/frontend/src/MathField.js similarity index 100% rename from TextEditor/src/MathField.js rename to frontend/src/MathField.js diff --git a/TextEditor/src/TextEditor.js b/frontend/src/TextEditor.js similarity index 100% rename from TextEditor/src/TextEditor.js rename to frontend/src/TextEditor.js diff --git a/TextEditor/src/index.css b/frontend/src/index.css similarity index 100% rename from TextEditor/src/index.css rename to frontend/src/index.css diff --git a/TextEditor/src/index.js b/frontend/src/index.js similarity index 100% rename from TextEditor/src/index.js rename to frontend/src/index.js diff --git a/TextEditor/src/logo.svg b/frontend/src/logo.svg similarity index 100% rename from TextEditor/src/logo.svg rename to frontend/src/logo.svg diff --git a/TextEditor/src/reportWebVitals.js b/frontend/src/reportWebVitals.js similarity index 100% rename from TextEditor/src/reportWebVitals.js rename to frontend/src/reportWebVitals.js diff --git a/TextEditor/src/setupTests.js b/frontend/src/setupTests.js similarity index 100% rename from TextEditor/src/setupTests.js rename to frontend/src/setupTests.js diff --git a/launcher.py b/launcher.py new file mode 100644 index 0000000..34dd25b --- /dev/null +++ b/launcher.py @@ -0,0 +1,83 @@ +"""Archivium Launcher - Uruchamia całą aplikację""" +import subprocess +import os +import sys +import time +import webbrowser + + +def install_missing_packages(): + """Instaluj brakujące pakiety""" + packages = ["uvicorn", "fastapi", "sqlalchemy", "passlib[argon2]"] + for package in packages: + try: + __import__(package.split("[")[0].replace("-", "_")) + except ImportError: + print(f"[*] Instalowanie: {package}...") + subprocess.check_call([sys.executable, "-m", "pip", "install", package]) + + +def run_archivium(): + """Uruchom całą aplikację Archivium""" + install_missing_packages() + + base_dir = os.path.dirname(os.path.abspath(__file__)) + backend_dir = os.path.join(base_dir, "backend", "app") + frontend_dir = os.path.join(base_dir, "frontend") + + print("\n" + "="*50) + print(" ARCHIVIUM - System Zarządzania Archiwum") + print("="*50 + "\n") + + print("[1/3] Startuje backend (Port 8000)...") + backend_process = subprocess.Popen( + [sys.executable, "main.py"], + cwd=backend_dir + ) + + print("[2/3] Startuje frontend (Port 3000)...") + try: + frontend_process = subprocess.Popen( + "npm start", + shell=True, + cwd=frontend_dir, + ) + except Exception as e: + print(f"[!] Uwaga: Nie udało się uruchomić frontendu: {e}") + print("[*] Frontend może wymagać: npm install && npm start") + frontend_process = None + + print("[3/3] Otwieranie przeglądarki...") + time.sleep(3) + + try: + webbrowser.open("http://localhost:3000") + except Exception as e: + print(f"[!] Nie udało się otworzyć przeglądarki: {e}") + print("[*] Otwórz ręcznie: http://localhost:3000") + + print("\n" + "="*50) + print("✓ Aplikacja uruchomiona!") + print(" Backend: http://localhost:8000") + print(" Frontend: http://localhost:3000") + print(" Docs: http://localhost:8000/docs") + print("="*50) + print("\nAby zatrzymać: Ctrl+C\n") + + try: + backend_process.wait() + if frontend_process: + frontend_process.wait() + except KeyboardInterrupt: + print("\n[*] Zatrzymywanie systemu...") + backend_process.terminate() + if frontend_process: + frontend_process.terminate() + backend_process.wait() + if frontend_process: + frontend_process.wait() + print("[✓] System zatrzymany") + + +if __name__ == "__main__": + run_archivium() diff --git a/main.py b/main.py deleted file mode 100644 index df4d0a9..0000000 --- a/main.py +++ /dev/null @@ -1,56 +0,0 @@ -import subprocess -import os -import sys -import time -import webbrowser - - -def install_missing_packages(): - packages = ["uvicorn", "fastapi", "sentence-transformers"] - for package in packages: - try: - __import__(package.replace("-", "_")) - except ImportError: - print(f"[*] Instalowanie brakującej biblioteki: {package}...") - subprocess.check_call([sys.executable, "-m", "pip", "install", package]) - - -def run_archivium(): - install_missing_packages() - base_dir = os.path.dirname(os.path.abspath(__file__)) - - backend_script = os.path.join(base_dir, "Database", "database.py") - frontend_dir = os.path.join(base_dir, "TextEditor") - - print("\n--- URUCHAMIANIE SYSTEMU ARCHIVIUM ---") - - print(f"[*] Startuję bazę danych...") - backend_process = subprocess.Popen( - [sys.executable, backend_script], - cwd=os.path.join(base_dir, "Database") - ) - - print(f"[*] Startuję edytor...") - frontend_process = subprocess.Popen( - "npm start", - shell=True, - cwd=frontend_dir, - creationflags=subprocess.CREATE_NEW_CONSOLE - ) - - print("[*] Oczekiwanie na gotowość...") - time.sleep(5) - - webbrowser.open("http://localhost:3000") - - try: - backend_process.wait() - frontend_process.wait() - except KeyboardInterrupt: - print("\n[*] Zamykanie systemu...") - backend_process.terminate() - frontend_process.terminate() - - -if __name__ == "__main__": - run_archivium() diff --git a/requirements.txt b/requirements.txt index 8eac4c7..ba94f40 100644 Binary files a/requirements.txt and b/requirements.txt differ