
# curl https://accfam-work.ner-dev.com
Accfam Work
$ attendance --rosters --tasks --chat --calls --assistant --native-apps --atomic-permissions
- web
- android
- ios
- windows
- macos
A workforce platform for companies whose people work at client sites — GPS-verified punches, roster-aware lateness rules, tasks and projects, team chat and calls, and an assistant that answers from the company's own documents — on the web and in native apps for Android, iPhone, Windows and Mac built from one Kotlin Multiplatform codebase, with a permission matrix where every action is granted one at a time.
FLAGS
- --gps-verified
- Every punch carries one GPS fix measured against the site's geofence; an outside-radius punch is flagged for review or refused, per the company's chosen mode. Nothing is recorded between punches.
- --offline-first
- Punches and messages made without signal are held on the device by the apps and sent when the connection returns; the web stays an installable PWA with a service worker and the same durable submit queue.
- --native-apps
- One Kotlin Multiplatform codebase with a shared Compose Multiplatform UI ships the Android, iOS, Windows and macOS apps. They call the same API as the web, so permissions and every rule stay on the server, and a parity check keeps web and apps from drifting apart.
- --attested-punches
- Every app punch proves where it came from — Google Play Integrity on Android, Apple App Attest on iPhone, and on a computer an Ed25519 key registered on first run that signs each punch over its body, the time and a one-time nonce.
- --device-bound
- Each employee is bound to one phone; a punch from any other device is refused until an admin approves the change, which is what stops one person punching for another.
- --spoof-aware
- Heuristics catch faked locations — a too-perfect accuracy figure, coordinates identical to the last punch, a device clock far from real time, travel faster than is physically possible, or GPS that disagrees with the network's own position.
- --roster-aware
- Lateness, early-leave, half-day and absence are judged against each team-or-site's own schedule and time zone — its custom hours when set, the company default otherwise.
- --site-clocks
- A site keeps its own time zone, so a team in Karachi working a New York client's day is judged in New York time, and hours like 18:00 to 03:00 are a night shift into the next morning.
- --atomic-permissions
- Every feature splits into single actions, and each action about somebody's records exists four times over — own, juniors', peers', seniors' — crossed with reach across one's teams or the whole company. Nothing is visible until it is granted, and only the platform owner can hand out the permission that edits permissions.
- --client-policy
- A company decides, per person, where they may sign in — web, Windows, Mac, Android or iPhone — checked by the server on every request.
- --team-chat
- Direct messages, groups, channels scoped to a team or site, moderator-only announcement rooms, files and voice notes with waveforms, mentions, read receipts, an edit window, moderation that cannot read rooms it is not in, and exports written to the audit log.
- --calls
- WebRTC voice calls and screen sharing — browser-to-browser mesh up to four, bigger rooms on the company's own Cloudflare SFU/TURN or LiveKit keys. Calls ring a locked phone and survive app switches.
- --ai-assistant
- An assistant that answers from the company's own handbooks and policies, held to the subjects it was given, with its own name, face and tone — OpenAI, Anthropic or Gemini behind one provider interface, every request logged.
- --tasks-projects
- Tasks with comments, a submit-then-review step, recurring series and a chat thread of their own; projects that group them and archive when finished; assignment bounded by rank; a self-raised task can be made private to its owner.
- --report-exports
- Eight report types render to XLSX, PDF and CSV from a single table builder, so the on-screen preview and the downloaded file can never disagree — and no report shows more than the reader's permissions allow.
- --multi-tenant
- Each company's data is walled off by server-side scoping; a super-admin creates companies, switches add-ons on, sets caps and retention, and enters a scoped support view without mixing one client's records with another's.
- --self-updating-desktop
- The Windows (MSI) and Mac (DMG) apps find a new release, download it with resume, verify its size and SHA-256, and swap themselves in place. A minimum version per app turns older builds away with HTTP 426 until they update.
- --one-retention-dial
- One retention period per company: attendance, shifts, messages, media, notifications and assistant logs older than it are purged nightly, while deleting a person anonymises their work history instead of shredding the record.
SCREENSHOTS
browsers tested: chromium 120+ • firefox 119+ • safari 17+ • edge 120+ • mobile safari 16+
MODULES
CHECK-IN / CHECK-OUT
GPS punch against the site geofence, offline queue with replay, one-device binding, spoof heuristics, compulsory check-out notes, automatic half-day detection.
ROSTER & SHIFTS
Range-based generation from team → site, assign a whole team (or a chosen subset) to a site, copy last week, clear a client-closed day, draft then publish, reminders before a shift starts.
ATTENDANCE REVIEW
Approve, reject, correct or reject-as-absence; half-day and lateness overrides; admin check-out of a forgotten punch; both GPS pins on a map with the full timeline.
REQUESTS
Leave, half days, late arrivals and early finishes; balances shown before and after; approved days suppress the nightly absence and block a same-day punch.
TASKS & PROJECTS
Tasks with assignees, comments, history and a submit-then-review step; recurring series; projects that group related work and archive when finished; ranked assignment; private self-raised tasks; a chat thread per task.
TEAM CHAT
DMs, group chats, team- and site-scoped channels that enrol everyone assigned, moderator-only announcement rooms, up to ten attachments a message, voice notes with waveform and range-streamed playback, mentions, pins, read receipts, an edit window and audited exports.
AI ASSISTANT
Company documents ingested from PDF and DOCX and retrieved per question; answers confined to the subjects it was given; identity, greeting and tone per company; voice and image input; per-request activity log and monthly usage; provider and key held by the platform owner.
PERMISSIONS & ROLES
A matrix of feature.action permissions with four rank columns, custom roles built from admin / manager / employee templates, reach across one's own teams or the whole company, deny-by-default visibility, and a role-manager permission only the platform owner can grant.
REPORTS & EXPORTS
Timesheet, location log, attendance summary, site-visit log, billable hours, exception report, task log and task summary — one builder, rendered to XLSX, PDF or CSV.
SITES & GEOFENCES
Client sites with lat/lng and a radius drawn on a map, per-site custom hours, working days and time zone, address geocoding, allowed-team assignment.
TEAMS & EMPLOYEES
Teams with multi-site assignment and their own overrides of the company's rules, employees who can sit on several teams, bulk import, per-employee device binding and unbind.
DASHBOARD & AUDIT
Live on-site board, present / late / absent / flagged tiles with day-over-day deltas, a seven-day chart, and an append-only audit log with detail views.
SETTINGS & RULES
Geofence mode, grace period, absent cut-off, half-day and full-day thresholds, overtime, auto-close, working days, holidays, chat and assistant switches, shift reminders, quiet hours, and one retention period.
COMPANY DRIVE
Every file the company holds — chat attachments, voice notes, avatars — with storage totals, separate read and delete permissions, and audited access to files from conversations an admin is not part of.
PLATFORM / MULTI-TENANT
Super-admin company estate — create companies, switch add-ons on, set per-company caps and retention, configure each assistant, review its usage, and enter a scoped support view.
CALLS & SCREEN SHARING
Voice calls and screen sharing from any chat; browser-to-browser mesh up to four, bigger rooms on the company's own Cloudflare SFU/TURN or LiveKit keys; ringing on a locked phone; calls that survive switching apps.
NATIVE APPS
Android, iPhone, Windows and Mac from one Kotlin Multiplatform codebase on the web API; attested punches, offline queue for punches and messages, push, in-app updates on Android, self-updating MSI and DMG, and a per-person rule for where each employee may sign in.
Also: device-change approvals, push and email notifications with quiet hours, eighteen light and dark palettes a company picks its look from, and one nightly job that auto-closes, marks absent, purges past retention and sends the digest.
STACK
- frontend
- Vite 7 • React 19 • TypeScript 5.8 • Tailwind v4 • Radix UI • react-router 6 • lucide • zod • installable PWA with a service worker and an offline punch queue
- backend
- Express 4 on Node 20 • pure-domain core in its own workspace • Kysely • zod • ExcelJS + @react-pdf/renderer for report rendering • node-cron for the nightly job • server-sent events for live updates
- database
- PostgreSQL • SQL migrations applied at container start • generated types • PGlite for the database test suite
- auth
- Firebase Auth (email/password) • httpOnly session cookie • App Check + reCAPTCHA Enterprise • atomic permissions and ranked visibility held in Postgres, not in claims
- ai
- OpenAI / Anthropic / Google Gemini behind one provider interface • company documents ingested with pdf.js and mammoth • retrieval confined to configured subjects • every request logged
- maps
- Google Maps JavaScript API (geofence draw + pins) • Leaflet for the lighter map views • OpenStreetMap Nominatim for address geocoding
- media
- Chat files, voice notes and avatars on a server volume • sharp for image processing • HTTP range requests, so a voice note starts playing before it has finished downloading
- infra
- One Docker image running as either half — Express API or nginx serving the SPA • Contabo VPS in Germany • Cloudflare tunnel • Redis for rate limits and presence • Resend for transactional email • Firebase Cloud Messaging for push
- apps
- Kotlin 2.4 • Compose Multiplatform 1.12 • Ktor 3.6 client • webrtc-kmp on mobile, webrtc-java on desktop • Firebase Messaging, Crashlytics and App Check (Play Integrity, App Attest) • Google Play in-app updates • jpackage MSI and DMG
- calls
- WebRTC mesh • Cloudflare Calls (SFU + TURN) • LiveKit
- ci
- GitHub Actions — one Installers workflow builds the MSI, the DMG, the signed Play bundle and the iOS archive at one version
FAQ
- q: how does it stop one worker punching in for another?
- a: three layers — each employee is bound to one phone (a new device needs admin approval), every punch is geofenced to the site, and spoof heuristics flag faked GPS, a wrong device clock or travel too fast to be real.
- q: what happens when a field worker has no signal?
- a: the apps keep punches and messages on the device and send them when the connection returns. on the web it's a PWA: the punch is queued by a service worker and replayed, so the queue survives a closed tab or a dead network.
- q: which devices?
- a: the web, plus native apps for android, iphone, windows and mac — one kotlin multiplatform codebase for all four apps, on the same api as the web. android is on google play, windows on the microsoft store.
- q: can a manager read a private conversation?
- a: no. a room is readable by its members and nobody else, whatever rank somebody holds. moderators can delete a message they can already see, and every conversation export is written to the audit log.
- q: does the assistant train on our documents?
- a: no. a question retrieves passages from the company's own documents and sends them to the model provider for that one answer. it stays inside the subjects it was given, declines the rest, and every request is logged.
- q: how fine-grained are permissions, really?
- a: every feature is split into single actions, and each action about somebody's records exists four times — own, juniors', peers', seniors' — narrowed again to one's own teams or the whole company. nothing shows until it is granted, and only the platform owner can grant the permission that edits permissions.
- q: is it multi-company?
- a: yes — fully multi-tenant. one company can never see another's data; a super-admin creates companies, switches add-ons like chat and the assistant on, and sets per-company caps and retention.
- q: where does it run?
- a: one docker image on a contabo vps in germany behind a cloudflare tunnel — nginx serves the spa, express serves the api, postgres holds the data, files sit on a server volume and redis covers rate limits and presence.
- q: how are the numbers kept honest for payroll?
- a: a day is counted once regardless of how many site visits it holds, hours sum across visits, half/full is threshold-driven, and every admin override is written to an append-only audit log.





