Przejdź do głównej zawartości

Backend Overview

Na tej stronie
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 --> OAI
KategoriaLiczbaLokalizacja
Tauri Commands250src-tauri/src/commands/
Database Tables33src-tauri/src/database/schema.rs
Rust Modules25src-tauri/src/
Lines of Rust~15,000src-tauri/src/**/*.rs

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 migrations

// 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)
}
src-tauri/src/lib.rs
#[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");
}

src-tauri/src/database/mod.rs
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
}
// Global app state
pub struct AppState {
pub current_user: RwLock<Option<User>>,
pub ai_config: RwLock<AIConfig>,
pub session_manager: SessionManager,
}

// 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)
}
src-tauri/src/utils/error.rs
#[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()
}
}

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?,
})
}

src-tauri/capabilities/default.json
{
"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"
]
}
// Secure storage for API keys
use 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())?)
}

Okno terminala
# Start development server
pnpm tauri:dev
# Run Rust tests
cd src-tauri && cargo test
# Check compilation
cargo check --all-features
# Format code
cargo fmt
Okno terminala
# Build for all platforms
pnpm tauri:build
# macOS specific
pnpm tauri:build --target universal-apple-darwin
# With debug symbols
pnpm tauri:build --debug
PlatformOutputNotes
macOS.dmg, .appUniversal binary (Intel + ARM)
Windows.msi, .exeNSIS installer
Linux.deb, .rpm, .AppImageMultiple formats

MetricValue
Cold start~2-3 seconds
Warm start~800ms
Database init~200ms
AI connection~500ms
Base RAM~150MB
With AI loaded~400MB

MetrykaObecny stanCel
LOC backend~43,000~35,000 (po cleanup)
Moduły commands/45 (płaskie)~25 (per-domain)
Zarejestrowane komendy248~200 (używane)
Test coverage9.22%30%+
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 checks
Obecna lokalizacjaDocelowa lokalizacja
commands/auth/*.rsapi/auth/*.rs
commands/patients.rsapi/patients/crud.rs + search.rs
commands/visits/*.rsapi/visits/*.rs
unified_ai/chat/*.rsapi/ai/chat.rs + domain/ai/
unified_ai/service_resolver/infra/ai_providers/
engines/stt/infra/engines/stt/
database/infra/database/
utils/shared/utils/
  • 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
  1. Nie dodawaj nowych plików do root commands/ - używaj api/<domain>/
  2. Nie mieszaj Tauri command logic z business logic - wydziel do domain/
  3. Nie duplikuj queries - używaj infra/database/queries/
  4. Nie hardkoduj providerów AI - używaj infra/ai_providers/resolver.rs
  5. Nie twórz plików > 500 LOC - podziel na mniejsze moduły