Saatyar is an open-source, Persian-first, right-to-left, local-first web application for personal work-time management. Employees, freelancers, and hybrid workers can record attendance, lunch, breaks, leave, projects, expenses, invoices, and reports without creating an account or depending on a remote backend.
Core product data is stored in the user's browser through IndexedDB. Normal daily use does not require a backend, cloud account, or .env file.
The public deployment is available at:
For real long-term data, create regular JSON backups from the data and backup section. Browser storage is not a substitute for an external backup.
The screenshots below come from a real production build using isolated demo fixtures. The capture workflow does not read real user data.
Regenerate every screenshot from the real production build with npm run media:capture (or npm run media:capture:built after a fresh build). See docs/assets/README.md for the privacy-safe capture contract.
- Start and finish a workday
- Record paid or unpaid lunch
- Record multiple independent breaks
- Edit start, end, lunch, and break times precisely
- Handle shifts that cross midnight
- Suggest an exit time from the selected day's schedule
- Recover stale open sessions, resume an auto-closed current-day session safely, and keep the recovery gap out of worked time
- Optional break reminders and open-timer notifications
- Employee: attendance, targets, overtime, deficit, leave, and estimated payroll
- Freelancer: clients, projects, hourly rates, budgets, expenses, and invoices
- Hybrid: employee and freelancer workflows in the same local workspace
- Independent schedule for each weekday
- Configurable net-work weekly target distributed over enabled days
- Bulk lunch defaults for duration and paid/unpaid accounting, with per-day overrides
- Selectable payroll basis: prorated monthly, fixed monthly, hourly, or daily
- Independent overtime, holiday-work, deficit, and rounding policies
- Official holidays and manual date overrides
- Live payroll preview and explainable breakdown of earnings, benefits, deductions, and net pay
- Monthly attendance, target, overtime, and deficit reports
- GitHub-style monthly work-activity heatmap with keyboard navigation, streaks, and overtime/deficit intelligence
- Daily details and record filters
- CSV and Excel export
- A4-aware print and PDF output
- Versioned backup and restore
- Automatic migration of older local data
- Local recovery snapshots and a 30-day recycle bin
- Direct encrypted mobile/desktop transfer over WebRTC with locally generated pairing QR codes
- Bilingual Persian/RTL and English/LTR interface with a quick flag language switcher
- Language-aware calendar: Auto follows the interface language, with explicit Persian/Jalali or Gregorian override
- Light, dark, and system themes
- Violet is the default brand preset; configurable accent, surface, and radius options remain available
- Locally bundled Vazirmatn font
- Responsive desktop and mobile layouts
- Keyboard access, focus management, and reduced-motion support
- PWA install UX, offline shell, and user-approved update prompts where the browser supports them
Saatyar does not send core work records to a project server by default. Data belongs to the browser profile and origin where the application is used.
This has useful properties:
- No account is required
- The user keeps direct control of their data
- Core workflows are not tied to a continuously available backend
- There is no central Saatyar database containing users' private work records
It also creates a responsibility: clearing site data, changing browsers or devices, using private browsing, or moving to a different origin can make local records unavailable. Regular exported backups are essential for serious use.
- Node.js
22.x - npm bundled with Node.js
- Git
git clone https://github.com/hamedtkd/saat-yar.git
cd saat-yar
npm ci
npm run devThe default local development server uses Next.js and normally starts at:
http://localhost:3000
If you specifically need the optional Vite/Vinext environment, run:
npm run dev:vinextVite/Vinext normally uses http://localhost:5173. npm run dev:next remains an explicit alias for the default Next.js server.
Installation problems are documented in:
| Command | Purpose |
|---|---|
npm ci |
Install the exact dependency tree from the lockfile |
npm run dev |
Start the stable local Next.js development server |
npm run dev:next |
Explicit alias for the default Next.js development server |
npm run dev:vinext |
Start the optional Vite/Vinext development server |
npm run check:dependencies |
Verify direct dependencies after replacing a phase package |
npm run typecheck |
Run TypeScript validation without emitting files |
npm run lint |
Run ESLint with zero warnings allowed |
npm test |
Run domain, regression, and architecture tests |
npm run check |
Run cleanup, import checks, schema audit, typecheck, lint, and tests |
npm run check:quality |
Run the complete quality pipeline and production Next.js build |
npm run test:browser:production |
Build the static export and run the Chromium production smoke test |
npm run check:release |
Run quality checks and the production browser smoke test on the same build |
npm run test:browser:pairing |
Run the real WebRTC encrypted multi-chunk transfer/ACK smoke |
npm run audit:vercel |
Verify the local static-export → out/ Vercel deployment contract |
npm run audit:production |
Read-only audit of deployed routes, PWA, service worker, robots, and sitemap |
npm run media:capture |
Regenerate product screenshots/GIF from isolated demo data |
npm run build:pages |
Produce the static application build |
npm run build:vercel |
Produce the Vercel-compatible build |
npm start |
Start the Vinext production output |
Before pushing a change:
npm run check:quality
npm run check:releaseattendance = exit - entry
net work = attendance - unpaid lunch - unpaid breaks
credited time = net work + credited leave
daily balance = credited time - selected-day target
Paid lunch and paid breaks are not subtracted from net work. Manually edited records use the selected day's clock values so stale timestamps cannot create multi-day overtime.
daily base salary = monthly salary / 30
Partial days are prorated from credited time. Time above the daily target can use the configured overtime multiplier, and holiday work can use the configured holiday multiplier.
Saatyar provides personal estimates. It does not replace an employment contract, official payslip, accountant, or applicable labor and tax rules.
app/ Routes and application layout
components/
common/ Shared product components
layout/ Shell, header, navigation, and onboarding
pages/ Today, month, reports, settings, and business views
pickers/ Jalali date and time pickers
ui/ Shared UI primitives
hooks/
controller/ Application workflows and mutations
settings/ Draft-based settings editing
use-saatyar-controller.ts Main product state facade
use-persisted-app-data.ts Local-first loading and persistence
lib/
data/ Schema, migrations, normalization, and audit
time-engine.ts Time calculation engine
payroll.ts Payroll calculations
work-schedule.ts Weekly schedule and targets
backup-schema.ts Backup validation
storage.ts IndexedDB storage adapter
types.ts Domain contracts
scripts/ Build, quality, and browser smoke utilities
tests/ Domain, regression, architecture, and repository tests
The current application schema version is defined in lib/data/version.ts. Any incompatible data change must include:
- A schema version increment
- A deterministic migration step
- Normalization for incomplete legacy data
- Backup validation and round-trip coverage
- Regression tests and a passing schema audit
The repository protects the product through several layers:
- Local import resolution checks
- Direct dependency preflight
- Runtime
AppDataschema audit across factory, migration, backup, recovery, snapshot, and merge paths - TypeScript validation
- ESLint with
--max-warnings=0 - Domain tests for time, payroll, backup, recovery, and migration
- Architecture and source-boundary tests
- Theme and semantic-token tests
- Next.js production build and static prerendering
- A real Chromium smoke test covering initial load, onboarding, the Today route, and calendar navigation
The current suite contains more than 600 tests. The exact release evidence should always come from the current npm run check:release output rather than a hard-coded badge alone.
The automated release browser gate currently runs in Chrome, Edge, or Chromium. Firefox and Safari require manual verification for release-critical UI changes. IndexedDB, multi-tab coordination, service-worker behavior, PWA installation, notifications, and private-mode limitations are documented in the browser compatibility matrix.
- Tailwind classes stay next to the JSX that owns them.
- Product surfaces use semantic theme tokens instead of fixed color literals.
- There is no central Tailwind class registry such as
lib/tw.ts. app/globals.csscontains only global styles, tokens, print rules, and browser-level behavior.- Production UI and hook modules should remain focused and generally below 250 lines.
- Destructive actions use the shared official Radix/shadcn Alert Dialog wrapper.
The Persian deployment guide covers Windows, macOS, Linux, Docker, GitHub Pages, and Vercel:
- Latest stable Saatyar 2.6.0 release notes
- Historical Saatyar 2.5.0 release notes
- Historical Saatyar 2.4.0 release notes
- Historical Saatyar 2.3.2 release notes
- Historical Saatyar 2.3.1 release notes
- Historical Saatyar 2.3.0 release notes
- Historical Saatyar 2.2.0 release notes
- Historical Saatyar 2.1.0 release notes
Bug reports, UX suggestions, documentation fixes, and pull requests are welcome.
Before opening a pull request, read CONTRIBUTING.md and the English agent guide. Security vulnerabilities must not be reported in a public issue; use the responsible disclosure path in SECURITY.md.
Track post-release work in the development backlog.
Version 2.6.0 is the latest stable Saatyar release. It packages the post-2.5.0 product cycle (Phases 195–200) on AppData v21, including the workspace-specific Today experience, Freelancer Work Session, Employee Activity Context, bilingual PWA identity, corrected locale-aware dates, Work Calendar naming, and final release hardening.
The Phase 201 candidate commit is 3e5bcbf, verified with 964/964 tests plus Production/Freelancer/Employee/Pairing browser gates, PWA/offline coverage, hardening audit, and the Vercel static-export audit. Phase 202 adds release-contract coverage for a 970/970 final Node-test target without adding product scope.
The release uses AppData schema v21 with a formal migration boundary from released 2.5.0 schema v20. Final rollout is controlled: merge the verified finalization commit to main, wait for the production deployment, run npm run audit:production, and create annotated tag v2.6.0 only on that exact production-audited commit.
Saatyar remains free and open source. Optional support is available at:
Support does not unlock product features and is not required to use the application.
Saatyar is released under the MIT License.
Maintained by Hamed Ahmadi — hamedtkd
- GitHub: hamedtkd
- Support: daramet.com/hamedtkd