Lompat ke konten
dokumentasi.id
Commit 0da916f
v1
Star0

Ada commit baru di branch utama.

2a17915

2

Arsitektur Sistem dan Batas Modul

Termimus tersusun dari tiga lapisan yang berbeda bahasa dan tanggung jawab: frontend React 19 + TypeScript + Vite dengan Zustand dan @xterm/xterm, backend Rust di dalam proses Tauri v2, serta relay sinkronisasi Go yang berdiri sendiri di server/. AGENTS.md:9-22

Lapisan frontend mengenal satu jalur keluar saja menuju backend, yaitu modul pembungkus di src/lib/api.ts. Setiap komponen dan store berhenti di sana, sehingga tidak ada komponen yang memanggil invoke secara langsung. AGENTS.md:9-22

Sembilan modul backend Rust

Akar crate src-tauri/src/lib.rs mendeklarasikan tepat sembilan modul: biometric, commands, db, pty, sftp, ssh, sshkey, tunnel, dan vault. src-tauri/src/lib.rs:1-9

Fungsi run() membuat masing-masing manager sebagai Arc lalu merakitnya menjadi satu AppState: Database, VaultManager, SessionManager, SftpManager, TunnelManager, dan PtyManager. src-tauri/src/lib.rs:22-30 Struct AppState di commands/mod.rs memegang keenam field Arc yang sama, sehingga setiap handler #[tauri::command] menerima State<AppState> dan tidak pernah membuat koneksi sendiri. src-tauri/src/commands/mod.rs:16-23

ModulStruct utamaPeranRujukan
sshSessionManager, SshClientHandlersesi SSH, streaming PTY, verifikasi host keysrc-tauri/src/ssh/mod.rs:52-56
sftpSftpManageroperasi SFTP jarak jauh dan helper filesystem lokalsrc-tauri/src/sftp/mod.rs:35
tunnelTunnelManagerport forwarding lokalsrc-tauri/src/tunnel/mod.rs:19
vaultVaultManagerAES-256-GCM dan derivasi kunci Argon2idsrc-tauri/src/vault/mod.rs:12-14
dbDatabaseSQLite lewat rusqlite, satu Mutex<Connection>src-tauri/src/db/mod.rs:8-10
commandsAppStateseluruh handler #[tauri::command]src-tauri/src/commands/mod.rs:16-23
ptyPtyManagersesi shell lokal, terpisah dari SSHsrc-tauri/src/pty/mod.rs:22
sshkeyGeneratedKeyPairpembuatan dan derivasi pasangan kuncisrc-tauri/src/sshkey/mod.rs:30

VaultManager hanya menyimpan derived_key: RwLock<Option<[u8; 32]>> di memori; tidak ada field yang menuliskan kunci ke disk. src-tauri/src/vault/mod.rs:12-14 Database membungkus satu rusqlite::Connection di dalam Mutex dan menjalankan init_tables() saat dibuat, sehingga schema dibuat sekali di awal proses. src-tauri/src/db/mod.rs:8-10 Rincian isi tabel dan kolomnya ada di Skema Database Lokal, sedangkan siklus kunci dan verifier ada di Vault dan Model Kriptografi.

graph TD
  UI["src/components"] --> STORE["src/stores Zustand"]
  STORE --> API["src/lib/api.ts"]
  API -->|"invoke"| CMD["commands/mod.rs"]
  CMD --> STATE["AppState"]
  STATE --> DB["db::Database"]
  STATE --> VAULT["vault::VaultManager"]
  STATE --> SSH["ssh::SessionManager"]
  STATE --> SFTP["sftp::SftpManager"]
  STATE --> TUN["tunnel::TunnelManager"]
  STATE --> PTY["pty::PtyManager"]
  SSH --> HOSTKEY["SshClientHandler"]
  HOSTKEY --> DB
  CMD -->|"sync_push / sync_pull"| RELAY["server handlers"]
  RELAY --> HUB["hub"]
  RELAY --> SDB["server db"]
  style DB fill:#336791,color:#fff
  style SDB fill:#336791,color:#fff
  style API fill:#8b5cf6,color:#fff
  style STATE fill:#8b5cf6,color:#fff
  style VAULT fill:#f59e0b,color:#000
  style HOSTKEY fill:#2d7d46,color:#fff
%% fig: Arah dependensi dari komponen sampai storage
%% desc: Komponen React memakai store Zustand, store memanggil api.ts, dan api.ts mengirim invoke ke handler yang berbagi satu AppState berisi enam manager.
Fig. 1: Arah dependensi dari komponen sampai storageKomponen React memakai store Zustand, store memanggil api.ts, dan api.ts mengirim invoke ke handler yang berbagi satu AppState berisi enam manager.

Satu pintu di frontend

src/lib/api.ts dimulai dari satu impor invoke dan mengekspor satu objek api yang memetakan setiap command Tauri ke fungsi TypeScript bertipe. src/lib/api.ts:1 src/lib/api.ts:202-204 Objek itu dikelompokkan per domain lewat komentar: Vault, Hosts, Folders, SSH Sessions, Local PTY Sessions, SSH Key Utilities, Keychain, SFTP Remote, Local Filesystem, Port Forwarding / Tunnels, Snippets, Workspaces & Layout Presets, Ping / Latency, Known Hosts / MITM Verification, Backup & Restore, dan Sync Relay. src/lib/api.ts:202-396

Panggilan relay sinkronisasi juga melewati jalur ini: sync_test_connection, sync_push, sync_pull, dan sync_get_devices diimplementasikan di sisi Rust, bukan fetch di browser, untuk menghindari blokir mixed-content dan CORS WebKitGTK. src/lib/api.ts:365-396 Perilaku sinkronisasinya dijelaskan di Backup, Sync Relay, dan API Server.

Setiap command wajib terdaftar di makro generate_handler![...] pada run(); daftar itu dibuka oleh commands::vault_status dan ditutup oleh commands::sync_get_devices. src-tauri/src/lib.rs:37-115 Karena registrasi terpusat di satu tempat, command yang lupa didaftarkan tetap dapat dikompilasi tetapi tidak bisa dipanggil dari frontend. Pendaftaran tiga langkah ini adalah konvensi yang mengikat seluruh modul. AGENTS.md:24-34

⚠️ Command baru memerlukan tiga perubahan sekaligus: fungsi #[tauri::command] di commands/mod.rs, entri di generate_handler![...] pada lib.rs, dan wrapper bertipe di src/lib/api.ts. Melewatkan salah satunya membuat command diam-diam tidak dapat dipanggil. AGENTS.md:24-34

Saat proses diminta keluar, run() mengirim pemutusan SSH untuk setiap sesi hidup lewat ssh.disconnect_all() di dalam tokio::time::timeout berdurasi 2 detik, sehingga keluar aplikasi tidak menggantung pada socket mati. src-tauri/src/lib.rs:118-132 Urutan handshake dan pemutusan satu sesi dibahas di Siklus Hidup Koneksi SSH.

Relay Go di server/internal/

Relay sinkronisasi adalah program Go terpisah dengan lima paket internal: config, db, hub, handlers, dan middleware. main() memuat config.Load(), membuka SQLite lewat db.Open(cfg.DBPath), membuat hub.New(), lalu menyerahkan keduanya ke handlers.New dan middleware.NewAuth. server/cmd/server/main.go:25-40

Routing memakai http.ServeMux biasa. Hanya /health yang publik; empat endpoint sync dibungkus auth.Wrap, dan seluruh mux akhirnya dibungkus middleware.CORS. server/cmd/server/main.go:48-70

EndpointMethodMiddlewareRujukan
/healthGETtanpa authserver/cmd/server/main.go:52
/api/v1/sync/statusGETauth.Wrapserver/cmd/server/main.go:55
/api/v1/sync/bundleGET, POSTauth.Wrapserver/cmd/server/main.go:56-65
/api/v1/sync/devicesGETauth.Wrapserver/cmd/server/main.go:66
/api/v1/sync/wsGETauth.Wrapserver/cmd/server/main.go:67

/api/v1/sync/bundle menangani dua method di satu handler: http.MethodGet memanggil h.GetBundle dan http.MethodPost memanggil h.PostBundle, selain itu dijawab 405 Method not allowed. server/cmd/server/main.go:56-65

Bila TERMIMUS_AUTH_TOKEN kosong, server mencatat peringatan [Security Warning] TERMIMUS_AUTH_TOKEN is not set! Running in OPEN mode. dan berjalan tanpa autentikasi. server/cmd/server/main.go:42-46

graph LR
  CFG["config.Load"] --> MAIN["cmd/server/main.go"]
  MAIN --> DBI["db.Open"]
  MAIN --> HUBI["hub.New"]
  MAIN --> HANDLERS["handlers.New"]
  MAIN --> AUTH["middleware.NewAuth"]
  AUTH -->|"auth.Wrap"| ROUTES["http.ServeMux"]
  ROUTES --> CORS["middleware.CORS"]
  DBI --> SQLITE["SQLite"]
  style DBI fill:#336791,color:#fff
  style SQLITE fill:#336791,color:#fff
  style CFG fill:#f59e0b,color:#000
  style AUTH fill:#f59e0b,color:#000
  style HUBI fill:#8b5cf6,color:#fff
%% fig: Perakitan relay Go
%% desc: main.go memuat config, membuka database, membuat hub, lalu membungkus setiap endpoint sync dengan auth.Wrap sebelum CORS.
Fig. 2: Perakitan relay Gomain.go memuat config, membuka database, membuat hub, lalu membungkus setiap endpoint sync dengan auth.Wrap sebelum CORS.

Batas yang menjaga dependensi satu arah

Dependensi selalu menuju satu arah: komponen → store → src/lib/api.ts → commands → manager di AppState → db. Tidak ada manager yang memanggil commands, dan tidak ada store yang menyentuh rusqlite atau russh. Satu-satunya jalur balik adalah event Tauri seperti ssh-data-${sessionId} yang dipancarkan backend ke frontend. AGENTS.md:24-34

Batas antar bahasa juga tegas: relay Go hanya berbicara lewat HTTP dan WebSocket ke sync_* di sisi Rust, bukan ke api.ts langsung. server/cmd/server/main.go:48-70 src/lib/api.ts:365-396

Verifikasi batas ini dilakukan dengan dua perintah: bun run build untuk tsc + vite build di frontend, dan cargo check di dalam src-tauri untuk backend. Belum ada test suite, sehingga verifikasi manual lewat bun run tauri dev masih menjadi norma. AGENTS.md:48-53