Tempo
Pencatatan waktu, persetujuan, dan invoice untuk studio kecil, dalam satu ruang kerja.
- Tahun
- 2026
- Peran
- Desain dan pembangunan
- Jenis
- Produk · API dan aplikasi web
- Stack
- .NET 10 · PostgreSQL · Next.js 15 · React 19 · Tailwind v4 · Kubernetes

Masalah
Freelancer dan agensi mencatat jam di satu alat, menyetujuinya di alat lain, dan membuat invoice dari alat ketiga. Tempo menyambung lingkaran itu: proyek, tugas, timesheet, persetujuan, invoice, dan portal klien dalam satu tempat.
Batasan
- Pemisahan arsitektur harus mempertahankan setiap route, status code, dan bentuk JSON.
- Riwayat migrasi tetap linear; tidak ada penulisan ulang migrasi yang sudah rilis.
- Izin multi-workspace dengan pemeriksaan server-side di setiap endpoint.
- Satu target deploy: klaster k3s homelab, disajikan melalui satu ingress.
Sistem
- API
- .NET 10 minimal API yang dibagi menjadi Domain, Shared, Application, Infrastructure, dan Api. Aturan bisnis berupa static class dengan unit test; handler memakai EF Core langsung, tanpa lapisan repository.
- Data dan job
- PostgreSQL dengan migrasi EF Core yang dijalankan saat startup di balik advisory lock. Outbox dispatcher menangani email; overdue sweep menandai invoice. Persetujuan timesheet adalah state machine, bukan sekadar kolom status.
- Klien
- Next.js 15 App Router dengan React 19, Tailwind v4, dan primitif Radix. Portal klien dan ruang kerja internal berbagi komponen, tetapi tidak berbagi izin.
Keputusan
1.
Aturan di static class, bukan service
Total invoice, pembulatan waktu, dan state machine tugas adalah fungsi murni. Integration test mencakup kontrak HTTP; unit test mencakup aritmetika dan transisi.
Tradeoff Lebih sedikit indirection, tetapi handler harus tetap tipis atau aturan bocor ke dalamnya.
2.
Outbox, bukan email langsung
Penulisan menyimpan pesan dalam transaksi yang sama dengan perubahan bisnis. Dispatcher mencoba ulang di luar request.
Tradeoff Satu tabel dan background worker tambahan untuk dioperasikan.
3.
Satu workspace per request
CurrentWorkspace diselesaikan sekali dan diwajibkan di setiap endpoint. Tidak ada tenant ambien di koneksi database.
Tradeoff Setiap query harus membawa predikat workspace; test menegakkannya.
4.
Migrasi saat startup
Advisory lock PostgreSQL menyerialkan migrasi di antara replika. Deploy tetap satu langkah.
Tradeoff Migrasi yang buruk menjatuhkan API; lock hanya mencegah balapan.
Layar


Status
Berjalan di deployment dev dari klaster k3s homelab. Screenshot memakai workspace demo. Repositori privat.
Bukti
- Deployment dev: dev-tempo.byros.dev (perlu masuk)
- Repositori privat
- Profil GitHub