Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
1f19281
docs: complete platform design documentation
claude Jul 17, 2026
ef85531
build: Gradle 8.9 build system with convention plugins
claude Jul 17, 2026
8083efe
feat(core): domain, data, sync, and design system modules
claude Jul 17, 2026
64ff4fd
feat(app): feature modules and application shell
claude Jul 17, 2026
954d759
feat(backend): REST API v1 on Cloud Functions with Firestore rules
claude Jul 17, 2026
3e030a4
feat(l10n): Afghanistan-first localization — Dari default, Pashto, So…
claude Jul 17, 2026
56ec50f
fix(build): resolve Gradle toolchain sync failure (no JDK 17 installed)
claude Jul 18, 2026
ad1a8b2
fix(database): widen Int to Long for LocalTime.ofSecondOfDay converter
claude Jul 18, 2026
69b1777
fix(data): encapsulate RoomDatabase.clearAllTables behind core:database
claude Jul 18, 2026
ca1019b
fix(data): inject DatabaseCleaner so core:data needs no Room on class…
claude Jul 18, 2026
68a1f84
fix(auth): lazy FirebaseAuth so app launches without google-services.…
claude Jul 18, 2026
fced409
feat(web): manager portal (React) + backend endpoints it needs
claude Jul 18, 2026
2aa8453
fix(web): show setup screen instead of white-screening when Firebase …
claude Jul 18, 2026
d401e8d
feat(demo): local emulator seed + one-command demo setup
claude Jul 18, 2026
d60f49b
fix(demo): build functions before starting emulator in setup
claude Jul 18, 2026
5da26bf
feat(demo): one-command run-demo.sh (build + emulator + seed + portal)
claude Jul 18, 2026
fd36693
fix(web): Solar Hijri conversion used Math.floor instead of trunc-to-…
claude Jul 18, 2026
bc97184
feat(android): connect debug build to the local Firebase emulator
claude Jul 18, 2026
2d26fa7
feat(payroll): calculation engine, portal page, and seeded run
claude Jul 18, 2026
ce8f797
feat(signup): company self-registration + production deployment guide
claude Jul 18, 2026
24e12d8
feat(invite): adding an employee creates their mobile-app login
claude Jul 18, 2026
9288da4
feat(attendance): end-to-end attendance regularization (request + app…
claude Jul 18, 2026
73af180
feat(ui): professional UI/UX pass on both the web portal and Android …
claude Jul 18, 2026
6e52185
feat(web): dark-mode toggle + further UI/UX polish
claude Jul 18, 2026
1f6a3f9
feat: shift scheduling + roster, editable company settings, dedicated…
claude Jul 18, 2026
a8bdd02
feat(web): smooth area/line trend chart on the dashboard
claude Jul 18, 2026
2dafd0e
feat(web): add orange as a secondary accent color
claude Jul 18, 2026
6493edb
feat(android): feature-flag gating end-to-end + orange secondary accent
claude Jul 18, 2026
ac49913
feat: kiosk check-in mode — rotating QR display closes the loop
claude Jul 18, 2026
3cf5cb1
feat: dedicated kiosk device accounts
claude Jul 18, 2026
a7a9365
feat: photo-verified check-in — manager review backbone (option 1)
claude Jul 18, 2026
10efe7f
feat(android): on-device selfie capture for photo-verified check-in
claude Jul 18, 2026
a914e23
fix(web): toggle switches were unclickable — track ate the click
claude Jul 18, 2026
08b89e5
fix: resolve all compiler and lint warnings
aminullah-dev Jul 23, 2026
afd28a4
feat(desktop): Windows installer for the company portal
aminullah-dev Jul 23, 2026
a952c61
feat(attendance): face-verified check-in, with server-proven verifica…
aminullah-dev Jul 25, 2026
6e70fee
fix(attendance): make a check-in that did not count visible to managers
aminullah-dev Jul 25, 2026
62d0fde
test(web): vitest + testing-library setup for the manager portal
aminullah-dev Jul 25, 2026
8ca56fd
fix(attendance): face check-in never reached the punch it verified
aminullah-dev Jul 27, 2026
fccdff9
fix(attendance): add the index the day projection needs
aminullah-dev Jul 27, 2026
3105598
fix: resolve "today" in the company's timezone everywhere
aminullah-dev Jul 27, 2026
51946a7
chore: ignore locally installed Claude skills
aminullah-dev Jul 27, 2026
f269b1d
chore: ignore Firebase emulator logs and the hosting cache
aminullah-dev Jul 27, 2026
7262f53
fix(attendance): compute the day from local midnight, not UTC
aminullah-dev Jul 27, 2026
a3764c9
feat(attendance): script to rebuild missing day projections
aminullah-dev Jul 27, 2026
f6e559a
test(attendance): pin the company-calendar date maths
aminullah-dev Jul 28, 2026
717a0bb
test(attendance): prove the day projection against a real Firestore
aminullah-dev Jul 28, 2026
fdb460d
ci: run the tests on every push, and fix what that surfaced
aminullah-dev Jul 28, 2026
9bed754
ci: give the emulator job JDK 21
aminullah-dev Jul 28, 2026
c8208a2
perf: halve the app download and stop re-shipping vendor code
aminullah-dev Jul 28, 2026
0912f58
chore: move the API off the Node 20 runtime before it is decommissioned
aminullah-dev Jul 28, 2026
ea9ca87
feat: nightly audit so lost attendance cannot stay invisible
aminullah-dev Jul 28, 2026
50c4cd0
feat(monitoring): define the integrity alert as code, not console steps
aminullah-dev Jul 28, 2026
9d22c67
docs: operations runbook for a live system
aminullah-dev Jul 28, 2026
ccecd77
feat(payslips): browse payslips by month, not just by year
aminullah-dev Jul 28, 2026
dd9e8a6
fix(payslips): hide the month row when the year has no payslips
aminullah-dev Jul 28, 2026
ea173d6
feat(attendance): weekly report for managers
aminullah-dev Jul 28, 2026
3d90849
fix: twelve defects found reviewing the branch
aminullah-dev Aug 25, 2026
e17bb3b
fix(web): update the test row for the renamed selfie field
aminullah-dev Aug 25, 2026
da2398e
feat(payroll): configure employee salaries so payroll can produce pay…
aminullah-dev Aug 25, 2026
4f28b78
feat: a working calendar, account closure, and an honest login failure
aminullah-dev Sep 7, 2026
3691b59
feat: production hardening, licensing, finance and the hosted demo
aminullah-dev Sep 7, 2026
42c2d8d
fix(payroll): stop docking days that have not happened yet
aminullah-dev Sep 7, 2026
accd305
feat(licensing): make the licence something the vendor sells, not a s…
aminullah-dev Sep 7, 2026
b0aacfe
feat: make the product answer three questions a buyer will ask
aminullah-dev Sep 7, 2026
a658a33
fix: three bugs that writing the customer manual uncovered
aminullah-dev Sep 7, 2026
d4ddc87
feat: the handover pack, a download page, and app 1.0.1
aminullah-dev Sep 8, 2026
9573c98
feat(payroll): a screen for allowances and deductions
aminullah-dev Sep 8, 2026
90460c4
feat(payroll): give an allowance to one employee, or a different amount
aminullah-dev Sep 8, 2026
e0d5754
chore(site): brochure updater, ready to run once wp-admin is signed in
aminullah-dev Sep 8, 2026
d490918
chore(site): record the brochure wording that actually shipped
aminullah-dev Sep 8, 2026
f21012f
fix(demo): restore the APK downloads I broke, and show the new feature
aminullah-dev Sep 8, 2026
fa4f059
fix(demo): an individual deduction, and stop the demo breaking when used
aminullah-dev Sep 8, 2026
e5aee12
refactor(demo): seed the payroll run with the real engine
aminullah-dev Sep 8, 2026
9fc72ed
fix(portal): make the per-employee amount reachable, and stop serving…
aminullah-dev Sep 8, 2026
1a1360a
feat(vendor): a console for Linumic, with a boundary that has to hold
aminullah-dev Sep 8, 2026
0962768
fix(vendor): the setup step I wrote could not actually be carried out
aminullah-dev Sep 8, 2026
31200db
feat(vendor): a CRM, on top of the data the console already had
aminullah-dev Sep 8, 2026
67a6b37
feat(support): let a customer raise an issue from inside the product
aminullah-dev Sep 8, 2026
824d68e
feat(work): tell every employee which part of the job they are on
aminullah-dev Sep 8, 2026
57ca8ca
fix(work): two things the emulator could not have told me
aminullah-dev Sep 8, 2026
8e0546e
docs: iOS feasibility, and the distribution fact that shapes it
aminullah-dev Sep 8, 2026
bebbe76
docs(site): brochure copy for work assignment, portal claims only
aminullah-dev Sep 8, 2026
b23b794
build(app): 1.1.0 for the work-assignment release
aminullah-dev Sep 8, 2026
193b8c2
docs(site): record that the app half of the brochure is now live
aminullah-dev Sep 8, 2026
c04d21b
feat(portal): let an employee sign in and see their own work
aminullah-dev Sep 8, 2026
0a75a54
feat(ios): the employee app, first screen working end to end
aminullah-dev Sep 8, 2026
64df4f2
feat(ios): GPS check-in and check-out
aminullah-dev Sep 8, 2026
31f7f26
feat(ios): work offline — queued punches and a cached day
aminullah-dev Sep 8, 2026
80a99aa
feat(ios): face embedding on the same model as Android
aminullah-dev Sep 8, 2026
1536b23
feat(ios): the face check-in screen
aminullah-dev Sep 8, 2026
4711112
feat(ios): leave and payslip screens
aminullah-dev Sep 8, 2026
b43b78a
feat(ios): attendance history and correction requests
aminullah-dev Sep 8, 2026
4c3e080
feat(ios): company notices
aminullah-dev Sep 8, 2026
97c2824
feat(ios): profile screen and an app lock
aminullah-dev Sep 8, 2026
45844eb
feat(ios): an office icon set, and an app icon at all
aminullah-dev Sep 8, 2026
b67ab05
ios: prepare device signing, and correct the distribution doc
aminullah-dev Sep 8, 2026
14b2adc
ios: set the Apple Developer Team ID
aminullah-dev Sep 8, 2026
6507c4a
ios: a punch that did not count must not say "recorded"
aminullah-dev Sep 9, 2026
19e6d84
ios: declare the encryption exemption in the spec
aminullah-dev Sep 9, 2026
f4ec76c
ios: declare the app iPhone-only, because it is
aminullah-dev Sep 9, 2026
74c48f7
docs: the iOS distribution recipe that actually worked
aminullah-dev Sep 9, 2026
1d39f57
ios: Release builds now talk to production, and versions come from on…
aminullah-dev Sep 9, 2026
ffd31f1
employees: the system numbers people, not the person filling the form
aminullah-dev Sep 9, 2026
e211c9d
web: EmployeeWrite.employeeCode is optional, like the form now sends
aminullah-dev Sep 9, 2026
942e753
web: a privacy notice that matches what the code actually does
aminullah-dev Sep 9, 2026
f1bf5f5
web: privacy contact is contact@linumic.com
aminullah-dev Sep 9, 2026
5922619
docs: business categories, and what the product is still missing
aminullah-dev Sep 9, 2026
fcf3732
employees: an edit now reaches the account it belongs to
aminullah-dev Sep 9, 2026
8fc7ab5
signup: ask what the business does, and set it up accordingly
aminullah-dev Sep 9, 2026
bfb4c7a
payroll: salary advances, and taking them back without taking them twice
aminullah-dev Sep 9, 2026
0144d80
docs: record what of the plan was built overnight, and what was delib…
aminullah-dev Sep 9, 2026
07b7ca5
firestore: the composite index the advances list needs
aminullah-dev Sep 9, 2026
aded358
portal: the advances card
aminullah-dev Sep 9, 2026
4bd1393
payroll: a sheet the workers can sign, and a file the accountant can …
aminullah-dev Sep 9, 2026
e6125f0
payroll: daily wages and piece work
aminullah-dev Sep 9, 2026
6e36f97
notifications: telling people things happened
aminullah-dev Sep 9, 2026
812afad
employees: a register of papers, and something that watches them
aminullah-dev Sep 9, 2026
35244c4
Add a support page, because linumic.com is not one
aminullah-dev Sep 16, 2026
d7cf417
Answer the Afghanistan territory question, and record what we told Apple
aminullah-dev Sep 16, 2026
346a2a1
Build the pods against iOS 16, like the app
aminullah-dev Sep 16, 2026
0f50382
Re-read `me` when the app comes forward
aminullah-dev Sep 16, 2026
0f7dd13
Target Android 16, and move the toolchain far enough to compile it
aminullah-dev Sep 16, 2026
0b8e5df
Write down what a Play listing needs, before we need it
aminullah-dev Sep 16, 2026
e999989
Call the Play build 1.2.0, not 1.1.0 again
aminullah-dev Sep 16, 2026
4699f68
Stop the ABI splits from blocking the App Bundle
aminullah-dev Sep 16, 2026
8fd35ec
Add the Play store assets we did not have
aminullah-dev Sep 16, 2026
23e5475
Housekeeping: update README, fix duplicate doc number
aminullah-dev Sep 16, 2026
417d112
Housekeeping: update README, fix duplicate doc number
aminullah-dev Sep 16, 2026
925a879
Add trilingual landing page for marketing
aminullah-dev Sep 16, 2026
eea6d05
Add trilingual landing page for marketing
aminullah-dev Sep 16, 2026
b42bb87
Rewrite landing page: conversational tone, story flow
aminullah-dev Sep 16, 2026
6919f47
Rewrite landing page: conversational tone, story flow
aminullah-dev Sep 16, 2026
4a99022
Fix login button visibility across language switch
aminullah-dev Sep 16, 2026
e698c12
Fix login button visibility across language switch
aminullah-dev Sep 16, 2026
c5d2f1f
Add real store links to landing page badges
aminullah-dev Sep 16, 2026
6777c89
Merge origin/claude/worktrack-hrms-platform-tlar35: keep real store l…
aminullah-dev Sep 16, 2026
78b25ec
Merge pull request #2 from aminullah-dev/claude/go-fix-3f657b
aminullah-dev Sep 16, 2026
ff086c2
ios: stay signed in and in English when the language changes
aminullah-dev Sep 16, 2026
5ec09c8
Merge pull request #3 from aminullah-dev/claude/go-fix-3f657b
aminullah-dev Sep 17, 2026
8b12a4b
android: show built-in leave and pay names in the chosen language
aminullah-dev Sep 17, 2026
6fd3fb8
Merge pull request #4 from aminullah-dev/claude/android-builtin-names
aminullah-dev Sep 17, 2026
752fb93
Correct the Pashto copy on the landing page
aminullah-dev Sep 17, 2026
56f7e0f
Merge pull request #5 from aminullah-dev/claude/pashto-site-copy
aminullah-dev Sep 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"projects": {
"default": "worktrack-prod",
"prod": "worktrack-prod",
"demo": "worktrack-demo-af"
}
}
94 changes: 94 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: CI

# Every bug that reached production this month was catchable by a test that
# already existed but that nothing ran automatically. This runs them.
on:
push:
pull_request:

# A new push to the same branch makes the previous run irrelevant.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
backend:
name: Backend (functions)
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend/functions
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22" # matches the Cloud Functions runtime
cache: npm
cache-dependency-path: backend/functions/package-lock.json

# The Firestore emulator is a Java process, and current firebase-tools
# refuses to start on anything below JDK 21. This is unrelated to the
# Android toolchain below, which is pinned to 17 by the Gradle config.
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"

- run: npm ci
- run: npm run typecheck
- run: npm test

# Integration tests skip themselves without an emulator, so they need one
# started explicitly or they would silently pass by doing nothing.
- name: Integration tests (Firestore emulator)
run: |
npm install --global firebase-tools
npm run test:integration

web:
name: Web (manager portal)
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: web/package-lock.json

- run: npm ci
- run: npm run typecheck
- run: npm test
# Catches what typecheck cannot: a broken import or a template that only
# fails when Vite actually bundles it.
- run: npm run build

android:
name: Android
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"

- uses: gradle/actions/setup-gradle@v4

# google-services.json is never committed; the app module applies the
# plugin only when it is present, so the build works without it.
- run: ./gradlew compileDebugKotlin testDebugUnitTest lintDebug --no-daemon

- name: Upload lint report
if: failure()
uses: actions/upload-artifact@v4
with:
name: lint-report
path: app/build/reports/lint-results-debug.html
if-no-files-found: ignore
47 changes: 47 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Gradle
.gradle/
build/
!gradle/wrapper/gradle-wrapper.jar

# IDE
.idea/
*.iml
.DS_Store
local.properties
captures/
.externalNativeBuild/
.cxx/

# Secrets / environment-specific configuration (never commit)
app/google-services.json
app/src/demo/google-services.json
backend/.firebaserc
backend/functions/.env*
backend/functions/.secret.local
web/.env.local
*.keystore
*.jks
# Holds the release signing password.
keystore.properties

# Node
node_modules/
backend/functions/lib/
npm-debug.log*

# Third-party Claude skills (installed locally, not vendored)
.claude/skills/

# Firebase local artifacts: emulator logs and the hosting upload cache.
# Regenerated on every run/deploy, and machine-specific.
.firebase/
firestore-debug.log
firebase-debug.log
ui-debug.log

# Release build output — APKs and baseline profiles. Large, regenerated
# by every build, and never worth keeping in history.
app/release/

# Kotlin compiler scratch and error logs.
.kotlin/
152 changes: 150 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,150 @@
# WorkTrack
Smart Workforce & Attendance Management
# WorkTrack — Smart Workforce & Attendance Management

**ورک‌ترک — مدیریت هوشمند نیروی کار برای افغانستان.** پلتفرم به زبان‌های **دری**
(پیش‌فرض) و **پښتو** و انگلیسی است؛ تاریخ‌ها و دوره‌های معاش بر اساس تقویم
**هجری شمسی** با نام ماه‌های افغانستان (حمل، ثور، جوزا…) نمایش داده می‌شود و رخصتی
هفته‌وار روز جمعه است.

WorkTrack is a multi-tenant Workforce Management Platform (HRMS) **built for
Afghanistan**: attendance with GPS geofencing and kiosk QR check-in, shift
scheduling, leave management with approval chains, payroll, announcements,
analytics, and enterprise-grade security — designed for organizations from small
teams to 100,000+ employees. Dari is the default language (full Pashto and English
translations, RTL-first UI), and all dates/payroll periods use the Solar Hijri
calendar — see `docs/10-localization-afghanistan.md`.

**Two products, one backend.** Each company self-registers and gets its own
isolated workspace (multi-tenant):

| Product | Audience | Where |
|---|---|---|
| **Company Console** | managers, HR, payroll | web portal (`web/`) — dashboard, employees, attendance, leave, payroll |
| **Employee App** | employees | Android (`app/`) + iOS (`ios/`) — attendance, leave, payslips |

To take it live, see **[docs/12-production-deployment.md](docs/12-production-deployment.md)**.
To try it locally with sample data, see **[docs/11-local-demo-setup.md](docs/11-local-demo-setup.md)**.

## Repository layout

| Path | Contents |
|---|---|
| `docs/` | Complete design documentation (start at `docs/00-master-spec.md`) |
| `app/`, `core/`, `feature/` | Android app — Kotlin, Jetpack Compose (M3), MVVM + Clean Architecture, Hilt, Room, WorkManager, offline-first sync |
| `build-logic/` | Gradle convention plugins shared by all modules |
| `backend/` | Firebase backend — REST API v1 on Cloud Functions (TypeScript/Express), Firestore rules and indexes |
| `web/` | Manager portal (web admin) — React + TypeScript + Vite, Dari/Pashto/English, Solar Hijri |
| `ios/` | iOS app — SwiftUI, XcodeGen + CocoaPods, TensorFlowLite face recognition |
| `desktop/` | Desktop shell — Electron wrapper around the web portal (Windows) |
| `delivery/` | Store assets — Play Store icon, feature graphic, screenshots |
| `scripts/` | One-off admin scripts (licence provisioning, etc.) |

## Design documentation

1. [Master specification (source of truth)](docs/00-master-spec.md)
2. [Product requirements](docs/01-product-requirements.md)
3. [System architecture](docs/02-system-architecture.md)
4. [Database design & ER diagrams](docs/03-database-design.md)
5. [REST API design](docs/04-api-design.md)
6. [Android architecture & navigation](docs/05-android-architecture.md)
7. [Web admin console design](docs/06-web-admin-design.md)
8. [Security architecture](docs/07-security-architecture.md)
9. [Offline-first sync strategy](docs/08-sync-strategy.md)
10. [Development roadmap](docs/09-roadmap.md)
11. [Afghanistan localization (دری/پښتو, Solar Hijri)](docs/10-localization-afghanistan.md)
12. [Local demo setup — run everything with sample data](docs/11-local-demo-setup.md)
13. [Production deployment — take it live](docs/12-production-deployment.md)
14. [Operations runbook — diagnosing and repairing a live system](docs/13-operations-runbook.md)
15. [The hosted demo](docs/14-hosted-demo.md)
16. [اپلیکیشن iOS — امکان‌سنجی و برنامه](docs/15-ios-app.md)
17. [Business types and feature gaps](docs/16-business-types-and-gaps.md)
18. [Google Play submission](docs/17-google-play.md)

## Android app

Module graph (details in `docs/05-android-architecture.md`):

```
app → feature:{auth,dashboard,attendance,leave,payslips,profile}
→ core:{data,sync} → core:{database,network,datastore} → core:{domain,model,common}
→ core:designsystem
```

Key properties:

- **Offline-first**: Room is the local source of truth; mutations queue in an outbox
with ULID idempotency keys and sync via WorkManager (`core/sync`). Punches are
append-only; the server is authoritative for balances, attendance days, payroll.
- **Attendance**: GPS punch with client+server geofence validation, mock-location
rejection, kiosk TOTP QR scanning (CameraX + ML Kit), monthly history.
- **Leave**: balances, apply flow with half-days, approver inbox with approve/reject.
- **Security**: Firebase Auth ID tokens, tenant/RBAC custom claims, no tokens stored
outside the Firebase SDK, cloud backup disabled for tenant data.

### Building

Prerequisites: JDK 17+, Android SDK 36. The Gradle wrapper is pinned (8.13).

```bash
./gradlew :app:assembleDebug
./gradlew test # JVM unit tests (domain/common)
```

### Firebase setup (required to run the app)

The app authenticates with Firebase, so it needs a `google-services.json`. Without
it the app still launches to the login screen, but sign-in fails. To wire it up:

1. Create a Firebase project at <https://console.firebase.google.com>.
2. Add Android app(s) to it. **The debug build's application id is
`app.worktrack.debug`** (the `.debug` suffix is added by the debug build type),
so register that package name to run debug builds. Add `app.worktrack` too for
release builds — both clients end up in the same `google-services.json`.
3. Download `google-services.json` and put it in the **`app/`** directory
(`WorkTrack/app/google-services.json`). The Google Services Gradle plugin is
applied automatically when the file is present (see the bottom of
`app/build.gradle.kts`), which generates the default `FirebaseOptions` that
`FirebaseApp` initializes from at startup.
4. In the Firebase console, enable **Authentication → Sign-in method →
Email/Password**.
5. Rebuild and run.

The file is git-ignored (it's per-environment config). Debug builds point the API
at the local Functions emulator (`app/build.gradle.kts` → `API_BASE_URL`); run the
backend emulator (see below) and provision a tenant to sign in end-to-end.

## Backend

```bash
cd backend/functions
npm install
npm run typecheck # strict TypeScript
npm run serve # Firebase emulators: functions + firestore + auth
```

- REST API v1 (Express on Cloud Functions v2): `me`, `attendance` (punch validation:
geofence, kiosk HMAC token, speed-of-travel plausibility), `leave` (transactional
balance reservation + approval chain), `payslips`, `announcements`, and the
sync protocol (`POST /sync/push`, `GET /sync/pull` with per-type delta cursors).
- Firestore rules deny all direct client access — every read/write goes through the
API (deny-by-default RBAC middleware, RFC 7807 errors, audit log on privileged ops).
- Kiosk QR secret: `firebase functions:secrets:set KIOSK_HMAC_SECRET`.

## Provisioning a tenant (P0)

1. Create `companies/{cid}` with `name`, `timezone`, `currency`.
2. Create `companies/{cid}/employees/{eid}` documents and geofences/shifts/leaveTypes.
3. Create the Firebase Auth user and set custom claims
`{ cid, eid, r: ["EMPLOYEE"], b: [branchIds] }` (Admin SDK).
4. Sign in from the app — session bootstraps via `GET /v1/me`, then full sync runs.

## Distribution

| Platform | Status | Link |
|---|---|---|
| **Google Play** | Closed testing | — |
| **App Store** | In review | — |
| **Web portal** | Live | `worktrack-prod.web.app` |

## Roadmap

See `docs/09-roadmap.md` for the full plan.
Loading
Loading