Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Zkteco Adms Laravel Package

syofyanzuhad/filament-zkteco-adms

Filament plugin for ZKTeco ADMS biometric attendance devices. Receive pushed attendance and user data from fingerprint and facial recognition terminals, sync logs, and manage devices directly from your Filament admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package and run migrations:

    composer require syofyanzuhad/filament-zkteco-adms
    php artisan vendor:publish --tag="filament-zkteco-adms-config"
    php artisan vendor:publish --tag="filament-zkteco-adms-migrations"
    php artisan migrate
    
  2. Register the plugin in your panel provider:

    public function panel(Panel $panel): Panel
    {
        return $panel
            ->plugin(ZktecoAdmsPlugin::make());
    }
    
  3. Point the device at your app. On the ZKTeco terminal go to Comm → ADMS / Cloud Server and set the server address to your host (your-app.test, path typically /iclock, port 80/443). The device immediately performs a handshake against the package's /iclock/* routes.

  4. Look here first: the Devices and Attendance Filament resources. The Devices resource is your health dashboard — a device that has completed its handshake shows up there with a serial number and last-activity timestamp. If nothing appears after ~60 seconds, the problem is network/middleware, not the package (see Gotchas).

  5. First useful case: let one device sync, confirm punches land as attendance records, then attach them to your own domain — e.g. a relation from Attendance to your Employee model keyed on the device user/employee ID. That's the first 30 minutes of real value; everything else (leave calculations, payroll export) builds on it.

Implementation Patterns

Exclude /iclock/* from CSRF and auth. Devices POST form-encoded data with no session and no token. The package ships routes, but the middleware stack is yours:

// bootstrap/app.php (Laravel 11+)
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: ['iclock/*']);
})

Also ensure the panel's auth middleware doesn't apply to those routes, and that any 2FA / IP allowlist middleware is bypassed for device traffic.

React to punches via events rather than polling the table. Subscribe to the package's attendance/device events and queue listeners so the device's HTTP response is never blocked by your business logic:

Event::listen(AttendanceRecorded::class, fn ($event) => ProcessPunch::dispatch($event->attendance));

Keep listeners ShouldQueue — devices have short timeouts and will retry, and a slow listener looks exactly like an outage to the terminal.

Simulate device traffic in tests. The ADMS protocol is plain HTTP, so you can drive the full path in a feature test without hardware:

$this->post('/iclock/cdata?SN=ABC123456', ['SN' => 'ABC123456'])
     ->assertOk();

Use the recorded payload format (operator=...&SN=...&options=all) to build fixtures for handshake, heartbeat, and attendance-push requests. This is the single highest-leverage thing to do early — it makes upgrades like v1.2.9 verifiable.

Treat attendance ingestion as idempotent at your layer. Devices resend on flaky networks. Upsert your derived records on (device_sn, employee_id, punched_at) rather than blindly inserting, so retries don't double-count hours.

Multi-device / multi-site. Devices are keyed by serial number, which is the natural tenant key. If devices serve different branches, resolve the branch from the serial number inside your listener/observer rather than adding schema to the package tables.

Command dispatch. The ADMS protocol is bidirectional — the device polls for pending commands. Use this for time sync, reboot, and user push instead of walking to the terminal. Note that command execution is eventually-consistent: queue it, then verify on the next poll window rather than expecting a synchronous result.

Reporting. For anything beyond the panel's default listing (monthly hours, lateness, missing punches), build a query layer over the attendance table and export to CSV/Excel. Don't try to bend the resource's table filters into payroll logic.

Gotchas and Tips

  • v1.2.9 specifically: config calls now carry default fallbacks for response, device, and events settings, so the package no longer explodes when the config file isn't published. This is a real fix for slim deployments and CI. It is not a reason to skip publishing — you still want the file in version control so response strings and event toggles are explicit and reviewable in diffs.
  • Config cache is the classic post-upgrade trap. After changing config or upgrading, run php artisan config:cache (and config:clear when debugging). Stale cached config is the most common reason a "fixed" setting appears not to work.
  • Device shows offline; no rows anywhere. Work outward: (1) does curl -X POST https://your-app/iclock/cdata?SN=TEST return 200? (2) check the web server access log for /iclock hits at all; (3) check WAF/CDN — Cloudflare bot rules and ModSecurity rule sets routinely block these unattended POSTs; (4) verify the device's server address has no trailing path or scheme mistake. Absence of log entries means the device never reached you.
  • HTTPS with self-signed certs will silently fail on most terminals. Use a valid certificate or plain HTTP on a trusted LAN.
  • Clock drift, not bugs. Devices drift and some report local time with no offset. Decide once whether you store raw device time or normalized UTC (config('app.timezone')), document it, and never mix.
  • Duplicate punches are a device behaviour, not a package bug. Short-interval re-punches happen on retries and on finger re-scans. De-duplicate in your domain layer.
  • Upgrades are low-risk here — this was a patch with no breaking changes, no schema changes, no config key renames. Pin the version in composer.json but don't hesitate to bump.
  • Extension points to reach for first: events (business logic), published config (response strings, toggles), and your own Eloquent relations on top of the package tables. Before overriding package classes, check whether a listener gets you there — it usually does, and it survives upgrades better.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource