Synaplan
开源 AI 软件平台,面向企业:自托管 AI 代理,符合 GDPR 的聊天机器人小部件,RAG 知识库,WhatsApp 与 Outlook AI,MCP,多模型路由。支持 Docker、Kubernetes 或在 Germ 托管。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Absensi selfie, data karyawan (SDM), dan payroll — produk SaaS berdiri sendiri. Next.js (App Router, TypeScript, Tailwind) + Supabase (Postgres, Auth, Storage), dengan database & backend independen (bukan berbagi database dengan produk lain) supaya bisa dijual ke bisnis mana pun.
src/
app/
login/, signup/, forgot-password/, reset-password/, auth/callback/ auth pemilik/admin bisnis
onboarding/ buat business pertama kali
dashboard/ halaman transit, redirect ke /business/[businessId]
business/[businessId]/(dashboard)/
employees/ CRUD karyawan, tunjangan-tetap/ (tunjangan berulang per karyawan)
attendance/ grid absensi manual harian
shifts/ shift template + jadwal per karyawan per hari
leave-types/, leave-requests/ jenis cuti, pengajuan + approval, sisa kuota
payroll/ daftar slip, rekap pra-slip, detail slip, kasbon/, pinjaman/
settings/ info bisnis, jam kerja, aturan payroll, link absen selfie & link cuti,
late-tiers/ (potongan telat bertingkat), holidays/ (tanggal merah tambahan)
activity-log/ riwayat aksi sensitif (hapus karyawan, slip lunas, cuti disetujui/ditolak, dst.)
absen/[slug]/ halaman publik absen selfie (tanpa login)
cuti/[slug]/ halaman publik pengajuan cuti (tanpa login)
api/attendance-checkin/ API route (service-role) untuk proses selfie check-in
components/
ledger-manager.tsx komponen generik ledger karyawan (dipakai kasbon & pinjaman pribadi)
lib/
supabase/ client.ts (browser), server.ts (RSC/actions), service.ts (service-role), middleware.ts
payroll/ calc.ts (rumus slip), aggregate.ts (rekap absensi), kasbon.ts, personal-loan.ts, payslip-total.ts
email/ resend.ts (client Resend), leave-notifications.ts (email approve/reject cuti, best-effort)
activity-log.ts helper logActivity() — best-effort, dipanggil setelah aksi utama berhasil
types/database.ts tipe hasil `supabase gen types typescript` (ditulis manual, ganti setelah project di-link)
supabase/
migrations/ schema database, urut sesuai modul
npm install
.env.example ke .env.local dan isi NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY dari Project Settings → API.npx supabase login
npx supabase link --project-ref <project-ref>
npx supabase db push
src/lib/types/database.ts):
npx supabase gen types typescript --project-id <project-ref> > src/lib/types/database.ts
npm run dev
20260909100000_extensions_and_helpers.sql — extension pgcrypto, skema private20260909100100_businesses.sql — businesses, business_staff, helper RLS private.owns_business()20260909100200_employees.sql — data karyawan20260909100300_attendance.sql — absensi (manual + selfie), storage bucket attendance-selfies, RPC publik get_attendance_checkin_info20260909100400_payslips.sql — slip gaji + adjustment (tunjangan/potongan bebas)20260909100500_employee_advances.sql — kasbon (ledger sederhana)20260909100600_payroll_rules.sql — tanggal merah tambahan, skema potongan telat bertingkat20260910100000_leave.sql — modul cuti: leave_types, leave_requests, RPC publik get_leave_request_info/submit_leave_request_public20260910100100_shifts.sql — shift_templates, employee_shift_assignments, kolom attendance.shift_template_id20260910100200_personal_loans.sql — employee_personal_loans, kolom payslips.personal_loan_deduction20260910100300_recurring_allowances.sql — employee_recurring_allowances20260911100000_employee_email.sql — kolom employees.email (opsional, dipakai notifikasi)20260912100000_spam_protection.sql — public_submission_log + cooldown 60 detik di RPC submit_leave_request_public20260912100100_activity_log.sql — activity_log20260920100000_pph21.sql — businesses.pph21_enabled, employees.ptkp_status, kolom payslips.pph21_amount/ptkp_status/ter_category20261008100000_attendance_security.sql — geofence (businesses.office_lat/office_lng/attendance_radius_m), PIN absen (employees.attendance_pin_hash, businesses.attendance_pin_required), bucket attendance-selfies jadi privat20261009100000_bpjs_portal_overtime.sql — BPJS (businesses.bpjs_*, , ), , tabel Setiap tabel dengan business_id diamankan RLS lewat private.owns_business(business_id) — akses hanya untuk businesses milik auth.uid() yang sedang login (owner atau staff aktif). Halaman /absen/[slug], /cuti/[slug], dan API /api/attendance-checkin sengaja tanpa login (karyawan tidak punya akun) — divalidasi manual di server lewat slug + employee id, lewat RPC security definer atau service-role client.
Approval cuti tidak menambah logic payroll baru: saat pengajuan disetujui, server action meng-upsert baris attendance untuk tiap tanggal dalam rentang jadi status='izin' — note diisi nama jenis cuti kalau jenis itu berbayar (masuk jalur "izin berketerangan" = dibayar penuh, logic yang sudah ada), atau dibiarkan kosong kalau tidak berbayar (masuk jalur "izin tanpa keterangan" = dipotong sesuai aturan izin bisnis). attendance.leave_request_id cuma jejak asal-usul, tidak dipakai kalkulasi.
Opsional (butuh setup terpisah) — saat cuti disetujui/ditolak (baik lewat approval maupun input manual admin), ABSENKU mencoba kirim email ke karyawan lewat Resend:
RESEND_API_KEY di .env.local.RESEND_FROM_EMAIL (mis. ABSENKU <[email protected]>). Kalau dikosongkan, dipakai alamat testing bawaan Resend ([email protected]) — cukup untuk uji coba, tapi terbatas untuk pemakaian nyata.RESEND_API_KEY kosong, atau karyawan tidak punya email (kolom opsional di form Karyawan), email cukup dilewati — tidak pernah menggagalkan approve/reject.Diatur di Pengaturan → "Keamanan Absen Selfie" dan di form Karyawan:
src/lib/attendance/pin.ts), tidak pernah dikirim ke browser. Karyawan yang punya PIN wajib mengisinya saat absen; kalau "Wajibkan PIN" dicentang, karyawan tanpa PIN tidak bisa absen selfie sama sekali. Setelah 5 kali salah PIN dalam 15 menit, absen karyawan itu dikunci sementara (dicatat di public_submission_log dengan kind absen_pin_gagal).attendance-selfies tidak lagi publik. Kolom attendance.check_in_photo_url/check_out_photo_url menyimpan path objek, dan dashboard membuat signed URL berumur 1 jam saat halaman dibuka (src/lib/attendance/selfie.ts).Foto selfie absen dihapus permanen (file di bucket + kolom check_in_photo_url/check_out_photo_url) dengan dua aturan:
purgeSelfies di src/lib/attendance/selfie.ts). Jam, lokasi GPS, dan status tetap tersimpan./api/cron/cleanup-selfies (harian, 02.00 WIB). Presensi yang ditolak juga mengikuti batas 30 hari ini supaya fotonya tersedia kalau ada sengketa.Foto lama sebelum fitur ini aktif dibersihkan sekali jalan dengan scripts/purge-old-selfies.mjs (default dry-run, tambahkan --apply untuk menghapus): node --env-file=.env.local scripts/purge-old-selfies.mjs.
Butuh env CRON_SECRET di Vercel (string acak panjang); tanpa itu endpoint cron menolak semua request. Ubah masa simpan lewat SELFIE_RETENTION_DAYS.
Mati secara default per bisnis (Pengaturan → BPJS). Kalau dinyalakan, setiap slip baru menghitung iuran (src/lib/payroll/bpjs.ts):
| Program | Perusahaan | Karyawan (memotong gaji) | Batas upah |
|---|---|---|---|
| BPJS Kesehatan | 4% | 1% | default Rp12 jt (bisa diubah) |
| JHT | 3,7% | 2% | — |
| JP | 2% | 1% | default Rp10.547.400 — perbarui tiap Maret sesuai pengumuman BPJS |
| JKK | 0,24–1,74% (pilih sesuai risiko) | — | — |
| JKM | 0,3% | — | — |
/karyawan/[slug] (slug sama dengan link absen, linknya ada di Pengaturan). Karyawan masuk dengan nama + PIN absen (karyawan tanpa PIN tidak bisa masuk), lalu bisa melihat rekap absensi bulan ini, sisa cuti, slip gaji (12 terakhir, termasuk rincian dan iuran BPJS perusahaan), kasbon & pinjaman pribadi (sisa, potongan yang akan datang, riwayat), dan mengajukan lembur.
src/lib/portal/session.ts). Kunci tanda tangan diturunkan dari SUPABASE_SERVICE_ROLE_KEY, atau dari PORTAL_SESSION_SECRET kalau diisi. Mengganti/menghapus PIN karyawan otomatis membatalkan sesinya.Diatur di Pengaturan → Lembur (src/lib/payroll/overtime.ts):
Kalau Pengaturan → Lembur → "harus diajukan & disetujui" dicentang, absen pulang selfie tidak lagi mengisi jam lembur otomatis. Karyawan mengajukan lembur lewat Portal Karyawan (maks. 31 hari ke belakang, 0,5–12 jam), admin menyetujui/menolak di menu Lembur (jam bisa dikoreksi saat menyetujui). Saat disetujui, jam ditulis ke attendance.overtime_hours tanggal itu dan ikut ke rekap payroll lewat jalur yang sudah ada. Butuh absensi berstatus "hadir" di tanggal tersebut.
/absen/[slug] (API /api/attendance-checkin) dan /cuti/[slug] (RPC submit_leave_request_public) sama-sama dilindungi cooldown sederhana berbasis tabel public_submission_log (bukan infra rate-limit eksternal): absen 5 detik per karyawan, pengajuan cuti 60 detik per karyawan. Cukup untuk mencegah spam-klik/bot dasar — bukan pengganti rate-limiting di level CDN/edge kalau butuh proteksi terhadap volumetric flood sungguhan.
Halaman detail slip punya tombol "Cetak Slip" yang memicu window.print() browser — tidak ada library PDF baru. Layout cetak (payslip-print-view.tsx) disembunyikan di layar dan cuma muncul saat print (Tailwind print: variant), sementara sidebar/nav dashboard disembunyikan sebaliknya lewat print:hidden di dashboard-shell.tsx.
Tombol "Import CSV" di halaman Karyawan menerima file dengan header nama (wajib), tipe_gaji, gaji_harian, gaji_bulanan, divisi, email (semua opsional kecuali nama) — urutan kolom bebas, dicocokkan lewat nama header. Parsing & validasi terjadi di server (import-actions.ts), baris yang gagal validasi dilaporkan per baris tanpa menggagalkan baris lain yang valid.
Mati secara default per bisnis (businesses.pph21_enabled, toggle di Pengaturan). Kalau dinyalakan:
src/lib/payroll/pph21.ts.⚠️ Batasan yang disengaja (baca sebelum dipakai untuk pelaporan pajak sungguhan):
Integrasi akuntansi/jurnal (sengaja tidak dibangun — di luar scope ABSENKU, lihat komentar di supabase/migrations/20260910100200_personal_loans.sql), notifikasi WhatsApp sebagai alternatif email, billing/subscription, undang admin/staff lewat UI (tabel business_staff sudah ada sejak v1, belum ada halamannya), landing page marketing, halaman legal (Syarat & Ketentuan/Privasi).
employees.bpjs_*payslips.bpjs_*businesses.overtime_approval_requiredovertime_requests20261010100000_overtime_rules.sql — aturan lembur per bisnis: minimum, pembulatan, maks. per hari, mode tarif flat/PP 35, hari kerja per minggu