Backend Overview
Na tej stronie
Tech Stack
Dział zatytułowany „Tech Stack”graph TB subgraph "Backend Stack" TAURI["Tauri 2.5<br/>Desktop Framework"] RUST["Rust 1.75+<br/>Core Language"] SQLX["SQLx<br/>Type-safe SQL"] TOKIO["Tokio<br/>Async Runtime"] end
subgraph "External Services" LIB["LibraxisAI Cloud<br/>AI Services"] MLX["Local MLX<br/>Apple Silicon AI"] OAI["OpenAI API<br/>Fallback"] end
TAURI --> RUST RUST --> SQLX RUST --> TOKIO TAURI --> LIB TAURI --> MLX TAURI --> OAIKluczowe liczby
Dział zatytułowany „Kluczowe liczby”| Kategoria | Liczba | Lokalizacja |
|---|---|---|
| Tauri Commands | 250 | src-tauri/src/commands/ |
| Database Tables | 33 | src-tauri/src/database/schema.rs |
| Rust Modules | 25 | src-tauri/src/ |
| Lines of Rust | ~15,000 | src-tauri/src/**/*.rs |
Architektura Tauri
Dział zatytułowany „Architektura Tauri”src-tauri/├── Cargo.toml # Rust dependencies├── tauri.conf.json # Tauri configuration├── capabilities/ # Permissions│ └── default.json # Allowed APIs│├── src/│ ├── main.rs # Entry point│ ├── lib.rs # Library root│ ││ ├── commands/ # Tauri commands (60)│ │ ├── mod.rs│ │ ├── auth.rs # Authentication│ │ ├── patients.rs # Patient CRUD│ │ ├── visits.rs # Visit management│ │ ├── audio/ # Audio processing│ │ ├── ai/ # AI integration│ │ └── ...│ ││ ├── database/ # Database layer│ │ ├── mod.rs # Pool & connection│ │ ├── models.rs # Rust structs│ │ ├── schema.rs # CREATE statements│ │ └── migrations.rs│ ││ ├── services/ # Business logic│ │ ├── ai_service.rs│ │ ├── audio_service.rs│ │ └── ...│ ││ └── utils/ # Helpers│ ├── error.rs│ ├── crypto.rs│ └── ...│└── migrations/ # SQL migrationsTauri IPC Communication
Dział zatytułowany „Tauri IPC Communication”Frontend → Backend
Dział zatytułowany „Frontend → Backend”// Frontend (TypeScript)import { invoke } from '@tauri-apps/api/core';
const patient = await invoke<Patient>('get_patient', { patientId: '123'});// Backend (Rust)#[tauri::command]pub async fn get_patient( db: State<'_, Database>, patient_id: String,) -> Result<Patient, String> { let patient = sqlx::query_as!(Patient, "SELECT * FROM patients WHERE patient_id = ?", patient_id ).fetch_one(&db.pool).await .map_err(|e| e.to_string())?;
Ok(patient)}Command Registration
Dział zatytułowany „Command Registration”#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .manage(Database::new().await.unwrap()) .invoke_handler(tauri::generate_handler![ // Auth commands::auth::login, commands::auth::logout, commands::auth::login_biometric,
// Patients commands::patients::get_patient, commands::patients::list_patients, commands::patients::create_patient, commands::patients::update_patient,
// Visits commands::visits::get_visit, commands::visits::create_visit, commands::visits::update_visit_soap, commands::visits::finalize_visit,
// Audio commands::audio::save_audio_file, commands::audio::start_transcription, commands::audio::get_transcription_status,
// AI commands::ai::chat_completion, commands::ai::generate_soap, commands::ai::get_ai_suggestions,
// ... 60 total commands ]) .run(tauri::generate_context!()) .expect("error while running tauri application");}State Management
Dział zatytułowany „State Management”Database State
Dział zatytułowany „Database State”pub struct Database { pub pool: SqlitePool,}
impl Database { pub async fn new() -> Result<Self, sqlx::Error> { let database_url = get_database_path();
let pool = SqlitePoolOptions::new() .max_connections(10) .acquire_timeout(Duration::from_secs(30)) .connect(&database_url) .await?;
// Run migrations run_migrations(&pool).await?;
Ok(Database { pool }) }}
// Access in commands via State#[tauri::command]pub async fn some_command(db: State<'_, Database>) -> Result<(), String> { let pool = &db.pool; // ... use pool}App State
Dział zatytułowany „App State”// Global app statepub struct AppState { pub current_user: RwLock<Option<User>>, pub ai_config: RwLock<AIConfig>, pub session_manager: SessionManager,}Error Handling
Dział zatytułowany „Error Handling”Result Pattern
Dział zatytułowany „Result Pattern”// All commands return Result<T, String>#[tauri::command]pub async fn create_visit( db: State<'_, Database>, data: CreateVisitRequest,) -> Result<Visit, String> { // Validation if data.patient_id.is_empty() { return Err("Patient ID is required".to_string()); }
// Database operation let visit = sqlx::query_as!(Visit, /* ... */) .fetch_one(&db.pool) .await .map_err(|e| format!("Database error: {}", e))?;
Ok(visit)}Custom Error Types
Dział zatytułowany „Custom Error Types”#[derive(Debug, thiserror::Error)]pub enum VistaError { #[error("Database error: {0}")] Database(#[from] sqlx::Error),
#[error("Authentication failed: {0}")] Auth(String),
#[error("AI service unavailable: {0}")] AIService(String),
#[error("File not found: {0}")] FileNotFound(String),}
impl From<VistaError> for String { fn from(err: VistaError) -> String { err.to_string() }}Async Runtime
Dział zatytułowany „Async Runtime”Vista używa Tokio jako async runtime:
// Async command#[tauri::command]pub async fn long_running_task( db: State<'_, Database>,) -> Result<String, String> { // Spawn background task tokio::spawn(async move { // Long-running work process_audio_files().await; });
// Return immediately Ok("Task started".to_string())}
// Parallel operations#[tauri::command]pub async fn fetch_dashboard_data( db: State<'_, Database>, user_id: String,) -> Result<DashboardData, String> { // Run queries in parallel let (visits, appointments, tasks) = tokio::join!( get_recent_visits(&db, &user_id), get_upcoming_appointments(&db, &user_id), get_pending_tasks(&db, &user_id), );
Ok(DashboardData { visits: visits?, appointments: appointments?, tasks: tasks?, })}Security
Dział zatytułowany „Security”Capability-based Permissions
Dział zatytułowany „Capability-based Permissions”{ "identifier": "default", "description": "Default capabilities for Vista", "windows": ["main"], "permissions": [ "core:default", "shell:allow-open", "dialog:allow-open", "dialog:allow-save", "fs:allow-read", "fs:allow-write", "http:default" ]}Keychain Integration
Dział zatytułowany „Keychain Integration”// Secure storage for API keysuse security_framework::os::macos::keychain::SecKeychain;
pub fn store_api_key(service: &str, key: &str) -> Result<(), Error> { let keychain = SecKeychain::default()?; keychain.set_generic_password(service, "api_key", key.as_bytes())?; Ok(())}
pub fn get_api_key(service: &str) -> Result<String, Error> { let keychain = SecKeychain::default()?; let (password, _) = keychain.find_generic_password(service, "api_key")?; Ok(String::from_utf8(password.to_vec())?)}Build & Development
Dział zatytułowany „Build & Development”Development
Dział zatytułowany „Development”# Start development serverpnpm tauri:dev
# Run Rust testscd src-tauri && cargo test
# Check compilationcargo check --all-features
# Format codecargo fmtProduction Build
Dział zatytułowany „Production Build”# Build for all platformspnpm tauri:build
# macOS specificpnpm tauri:build --target universal-apple-darwin
# With debug symbolspnpm tauri:build --debugBuild Targets
Dział zatytułowany „Build Targets”| Platform | Output | Notes |
|---|---|---|
| macOS | .dmg, .app | Universal binary (Intel + ARM) |
| Windows | .msi, .exe | NSIS installer |
| Linux | .deb, .rpm, .AppImage | Multiple formats |
Performance Characteristics
Dział zatytułowany „Performance Characteristics”| Metric | Value |
|---|---|
| Cold start | ~2-3 seconds |
| Warm start | ~800ms |
| Database init | ~200ms |
| AI connection | ~500ms |
| Base RAM | ~150MB |
| With AI loaded | ~400MB |
Backend 2.0 - Docelowa Struktura
Dział zatytułowany „Backend 2.0 - Docelowa Struktura”Metryki migracji
Dział zatytułowany „Metryki migracji”| Metryka | Obecny stan | Cel |
|---|---|---|
| LOC backend | ~43,000 | ~35,000 (po cleanup) |
| Moduły commands/ | 45 (płaskie) | ~25 (per-domain) |
| Zarejestrowane komendy | 248 | ~200 (używane) |
| Test coverage | 9.22% | 30%+ |
Nowa struktura katalogów
Dział zatytułowany „Nowa struktura katalogów”src-tauri/src/├── main.rs # Entry point (minimal)├── lib.rs # Tauri setup + generate_handler![]├── session.rs # Session management│├── api/ # [API] Tauri Commands (per domain)│ ├── mod.rs # Re-exports wszystkich komend│ ├── auth/ # Autentykacja & autoryzacja│ │ ├── login.rs # login, logout, verify_session│ │ ├── password.rs # change_password, reset flow│ │ ├── biometric.rs # biometric_*, enable/disable│ │ └── pin.rs # PIN authentication│ ├── users/ # Zarządzanie użytkownikami│ │ ├── crud.rs # create, get, update, delete│ │ ├── invitations.rs # invite flow│ │ └── preferences.rs # user preferences│ ├── patients/ # Pacjenci│ │ ├── crud.rs # CRUD operations│ │ └── search.rs # search, filter, pagination│ ├── visits/ # Wizyty│ │ ├── crud.rs # create, update, delete│ │ ├── queries.rs # get, search, pagination│ │ └── soap.rs # SOAP notes, retention│ ├── ai/ # AI & ML│ │ ├── chat.rs # unified_ai_chat_*│ │ ├── transcription.rs # transcribe_*, STT│ │ ├── soap.rs # SOAP generation│ │ └── suggestions.rs # AI suggestions, tasks│ ├── audio/ # Audio & recordings│ │ ├── recordings.rs # save, serve, cleanup│ │ └── transcription.rs # queue jobs, status│ └── analytics/ # Analytics & raporty│ ├── dashboard.rs # dashboard stats│ └── trends.rs # visit trends│├── domain/ # [DOMAIN] Business Logic (pure Rust)│ ├── auth/ # Auth domain logic│ │ ├── session.rs # Session validation│ │ └── permissions.rs # Permission checks│ ├── ai/ # AI domain│ │ ├── prompts.rs # Prompt construction│ │ └── streaming.rs # Stream management│ └── medical/ # Medical validation│ └── validation.rs # Drug interactions, dosage│├── infra/ # [INFRA] Infrastructure│ ├── database/ # Persistence│ │ ├── schema.rs # SQLite schema│ │ ├── models.rs # ORM models│ │ └── queries/ # Reusable queries│ ├── ai_providers/ # AI provider integrations│ │ ├── resolver.rs # Provider selection│ │ ├── openai.rs # OpenAI integration│ │ └── libraxis.rs # Libraxis integration│ ├── engines/ # External engines│ │ ├── stt/ # Speech-to-text│ │ ├── tts/ # Text-to-speech│ │ └── recordings/ # Audio recordings│ └── platform/ # Platform-specific│ ├── macos/ # TouchID, window effects│ └── windows/ # Windows specifics│├── shared/ # [SHARED] Shared utilities│ ├── types/ # SessionId, UserId, errors│ ├── utils/ # cipher, secure_logger│ └── middleware/ # Auth middleware│└── bootstrap/ # [BOOTSTRAP] App Startup ├── runtime.rs # Tauri runtime setup ├── env.rs # Environment loading └── health.rs # Health checksMapowanie: Obecne → Docelowe
Dział zatytułowany „Mapowanie: Obecne → Docelowe”| Obecna lokalizacja | Docelowa lokalizacja |
|---|---|
commands/auth/*.rs | api/auth/*.rs |
commands/patients.rs | api/patients/crud.rs + search.rs |
commands/visits/*.rs | api/visits/*.rs |
unified_ai/chat/*.rs | api/ai/chat.rs + domain/ai/ |
unified_ai/service_resolver/ | infra/ai_providers/ |
engines/stt/ | infra/engines/stt/ |
database/ | infra/database/ |
utils/ | shared/utils/ |
Checklist przy dodawaniu nowych funkcji
Dział zatytułowany „Checklist przy dodawaniu nowych funkcji”- Nowa komenda Tauri →
api/<domain>/<module>.rs - Business logic →
domain/<domain>/<module>.rs - External integration →
infra/<service>/ - Shared utility →
shared/utils/ - Plik < 500 LOC
- Test dla domain logic
Anty-wzorce (czego unikać)
Dział zatytułowany „Anty-wzorce (czego unikać)”- Nie dodawaj nowych plików do root
commands/- używajapi/<domain>/ - Nie mieszaj Tauri command logic z business logic - wydziel do
domain/ - Nie duplikuj queries - używaj
infra/database/queries/ - Nie hardkoduj providerów AI - używaj
infra/ai_providers/resolver.rs - Nie twórz plików > 500 LOC - podziel na mniejsze moduły
Related
Dział zatytułowany „Related”- Command Handlers - Szczegóły komend
- Unified AI - System AI
- Data Flow - Przepływ danych