sistem-absensi1: The Attendance App That Tries to Understand Any Fingerprint Export
A Laravel 11 and React system built for messy biometric data, local shift rules, and the real-world chaos of small-business payroll.
- sistem-absensi1 treats attendance imports as a recognition problem, not a file-format problem.
- The import service scans messy Excel exports for layout clues, then routes them into parser paths it trusts enough to write transactionally.
- The data model separates live employee state from durable attendance history, which keeps current views fast without losing auditability.
- The React frontend is not just a viewer, because it validates dates, shifts, and local conventions before the backend ever sees the file.
The app does not trust your spreadsheet
Most attendance tools assume the export is polite. This one assumes the opposite. It looks at the first rows of a workbook, searches for layout markers, and decides what kind of file it is before it commits anything to the database.
That choice changes the whole system. Instead of forcing every fingerprint machine into one template, sistem-absensi1 tries to recognize whatever the hardware produced and then normalize it into payroll-friendly records.
Why attendance data is harder than it looks
Attendance is rarely just check in and check out. It is a mix of hardware exports, inconsistent vendor formats, shift rules that cross midnight, and local business habits that do not fit neat SaaS assumptions.
| Approach | Assumption | Failure mode | What sistem-absensi1 does instead |
|---|---|---|---|
| Strict template import | Every export looks the same | One altered column breaks the whole flow | Scans the file for clues before choosing a parser |
| Vendor-specific importer | Each machine deserves its own code path | Maintenance grows with every new model | Uses heuristics to classify export shape first |
| Manual cleanup in Excel | Humans can normalize everything | Errors slip in and auditability gets worse | Converts messy input into structured records automatically |
| Heuristic detection and normalization | The file is hostile until proven otherwise | Requires a smarter import layer | Inspects early rows, routes by pattern, and writes transactionally |
That is why this repository is interesting. It does not just store attendance. It absorbs dirty operational data from the edges of a small business and tries to make it reliable enough for reporting.
The import engine is the real product
The core service is AttendanceExcelImportService.php. It inspects the first 20 rows of a workbook, looks for markers such as machine headers and attendance record patterns, and decides whether it is dealing with a fingerprint log, a horizontal attendance sheet, or a vendor-specific export.
// Simplified shape of the import flow
$workbook = $reader->load($filePath);
foreach ($workbook->getAllSheets() as $sheet) {
$sampleRows = $sheet->rangeToArray('A1:Z20');
if ($this->looksLikeFingerprintRecord($sampleRows)) {
$records = $this->parseFingerprintRecord($sheet);
} elseif ($this->looksLikeHorizontalAttendance($sampleRows)) {
$records = $this->parseHorizontalAttendance($sheet);
} else {
$records = $this->parseVendorSpecificExport($sheet);
}
DB::transaction(function () use ($records) {
$this->writeEmployees($records);
$this->writeAttendanceHistory($records);
});
}
The important detail is not just parsing. It is the write path. The service updates employees and attendance history inside a single transaction, so a half-imported workbook does not leave the database in a broken state.
That is defensive software in the best sense. It assumes the input is inconsistent and protects the system from becoming inconsistent too.
Current state on one side, history on the other
The model splits the problem into two layers. Employee holds the live state, such as current status and today’s snapshot. EmployeeAttendance holds durable history, with a unique constraint on employee_id and date.
| Layer | Job | Why it matters |
|---|---|---|
| Employee | Current state and today’s snapshot | Keeps the active view fast and simple |
| EmployeeAttendance | Historical attendance log | Preserves auditability and avoids overwriting past records |
| Unique constraint | One record per employee per date | Prevents duplicate history during repeated imports |
That split is clean because it matches how people actually use the system. Managers want the current picture, but payroll and audits need a stable record of what happened.
The frontend is not just a viewer
The React and TypeScript UI is doing real work. It parses dates in multiple formats, including Indonesian month names, and it understands shift windows that are not neatly nine to five.
type ParsedDate = {
year: number;
month: number;
day: number;
};
function parseDateParts(input: string): ParsedDate | null {
// Handles ISO, slash-separated, and localized month names.
// The goal is to accept messy operational data without making the user clean it first.
return null;
}
const workShifts = [
'10:00 - 22:00',
'22:00 - 10:00',
'08:00 - 17:00'
];
That makes the frontend a validation layer, not a decorative shell. It helps users catch problems before they turn into database writes, which is exactly what a file import screen should do.
The result is a product that reflects its market. Local date formats, practical shift patterns, and simple operational workflows matter more here than abstract elegance.
The repo looks AI-assisted on purpose
The .agents and .claude directories are not cosmetic. They suggest a codebase shaped for machine-readable rules, maintenance prompts, and assistant-friendly workflows.
That is a meaningful signal. Even in an early-stage repository, the developer is trying to encode conventions so both humans and coding assistants can stay aligned.
Why this stack fits its market
Laravel 11, React, Vite, TypeScript, SQLite or MySQL, Docker, and Render are all sensible choices for a compact operational app. The stack is modern, but not overbuilt.
| Choice | Why it fits |
|---|---|
| Laravel 11 | Fast to build, easy to structure services and transactions |
| React + TypeScript | Good fit for a data-heavy import and review UI |
| PhpSpreadsheet and XLSX | Useful on both server and client for Excel handling |
| Docker and Render | Keeps deployment straightforward for a small team |
This is the kind of stack you choose when the product’s value is in the workflow, not in platform novelty. It needs to be understandable, maintainable, and easy to deploy for a narrow but real market.