Javis OS
Javis OS는 기업가를 돕는 에이전시 AI로, 업무를 지원하고 함께 성장합니다
Artify HCMS 안드로이드 생산 동반 앱·기업 인력 시스템, 360° 인사 기록·다중 현장 출퇴근·휴가·프로젝트 타임시트·OMR 3자리
Production companion Android app and enterprise workforce system for Artify HCMS with Oman 360° HR records, multi-site geofenced mobile attendance, leave management, project timesheets, OMR 3-decimal
비즈니스TypeScript · PLpgSQLGitHub @usmanclaude92-creator온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Production companion Android app and enterprise workforce system for Artify HCMS with Oman 360° HR records, multi-site geofenced mobile attendance, leave management, project timesheets, OMR 3-decimal payroll, and employee ledger balances.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Employee, attendance, payroll, WPS and Oman HR compliance management. Currency is OMR at
three decimal places throughout.
• Frontend — React 19 + Vite + Tailwind, TypeScript
• Backend — Express, TypeScript, mounted both as a long-running server and as a Vercel
serverless function from the same app factory (server/app.ts)
• Store — PostgreSQL. See Data storage — the current shape is a known
constraint, not a finished design.
• Files — Supabase object storage for employee documents and payment receiptsREADME 전문 보기 ↗Employee, attendance, payroll, WPS and Oman HR compliance management. Currency is OMR at three decimal places throughout.
server/app.ts)npm install
cp .env.example .env # then fill in the values below
npm run dev # http://localhost:3000
With no DATABASE_URL set, the app runs against a local JSON file at
data/payroll_database.json and seeds a demonstration dataset (five employees, one
finalized payroll, sample loans and compliance documents) plus development sign-in
accounts. This never happens when NODE_ENV=production.
npm run lint # tsc --noEmit
npm test # payroll arithmetic, expiry rules, IBAN generation
npm run build # vite build + esbuild server bundle
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | Production | PostgreSQL connection string. Use the transaction pooler on a serverless host, not the direct connection. POSTGRES_URL and POSTGRES_URL_NON_POOLING are also accepted. |
JWT_SECRET | Always | Signing secret for session tokens. The server refuses to start without it. |
ADMIN_INITIAL_PASSWORD | First production start | Password for the first administrator. Required when the database has no user accounts and NODE_ENV=production; the server refuses to start otherwise rather than create a known default. |
ADMIN_INITIAL_USERNAME | Optional | Defaults to admin. |
ADMIN_INITIAL_EMAIL | Optional | Defaults to [email protected]. |
SUPABASE_URL | Production | Object storage endpoint. |
SUPABASE_SERVICE_ROLE_KEY | Production | Object storage credentials. |
SUPABASE_DOCUMENTS_BUCKET | Optional | Defaults to employee-documents. |
SUPABASE_RECEIPTS_BUCKET | Optional | Defaults to salary-payment-receipts. |
GEMINI_API_KEY | Optional | Enables the compliance assistant. Without it, a deterministic rule-based responder is used instead. |
WORKFORCE_FUNCTIONS_URL / WORKFORCE_INTEGRATION_SECRET / SUPABASE_ANON_KEY | Optional, but all three are required together | Links to the Artify Workforce app by Civil ID (see "Workforce app integration" below): populates "Shift Start"/"Shift End" on the Workforce Deployment dashboard, and lets Administrators sync eligible employees over so they can register there. Without all three set, cards show "Not Tracked" and the sync endpoint returns 400 -- there is no fallback URL/key/secret baked in. |
DB_CONNECT_TIMEOUT_MS | Optional | Database connect timeout, default 10000. |
ALLOW_DEMO_SEED | Optional | Set to false to suppress the demonstration dataset outside production. |
Bootstrap the first administrator, then change the password through the UI:
ADMIN_INITIAL_PASSWORD='<a strong password>' npm start
All application data currently lives in a single JSONB row (app_state), not in the
per-entity tables the schema creates. Every mutation rewrites that row under an optimistic
version check.
Consequences to be aware of before building on this:
server/app.ts refreshes it
from the durable store on every /api request — unconditionally before a mutation, and
within a 1.5s freshness window for reads — because without that, a record written through
one instance stayed invisible on every other one for the life of that instance, and two
browser refreshes could show different data.Write failures throw. A request that returns success means the data was committed. If a configured database is unreachable the server refuses to start rather than fall back to local storage, because that fallback previously caused demonstration data to be served as though it were production data.
Migrating each repository in server/db.ts onto real tables — starting with the
append-only financial records — is the highest-value structural work outstanding.
| Area | Notes |
|---|---|
| Employee Master | Core record, bank details, Excel import/export with server-side re-validation |
| HR Compliance | Civil ID, visa, driving licence and government documents with expiry tracking and renewal history |
| Document Repository | Uploads to object storage, per-employee and organisation-wide views |
| Attendance | Multi-project day/hour allocation, four-stage workflow, Excel import |
| Timesheets | Per-entry labour capture for project costing. Does not feed payroll. |
| Payroll | Monthly calculation, per-line overrides, finalisation lock, reasoned revision |
| Leave | Request/approve/reject/cancel workflow; approved paid leave feeds payable days in payroll |
| Salary Payments | Partial payments against a finalized entitlement, receipts, soft reversal |
| Payment Planning | Intended "should pay" figures. Never creates a payment. |
| WPS Recovery | Tracks recovery of the excess between declared WPS salary and net pay |
| Loans | Advances with payroll-driven and direct recovery |
| CIF | Bank file upload and reconciliation against payroll totals |
| Gratuity / End-of-Service | Oman Labour Law RD 53/2023 Art. 61 gratuity computation, non-Omani employees |
| Reports | Salary & payroll, payments, WPS, loans, project costing, employee ledger |
| Audit Trail | Action log across modules, retained to 5000 entries |
Worker Gross = hoursWorked × rate
Staff Gross = (monthlySalary ÷ 30) × min(daysWorked, 30)
Net = Gross + Additions − Deductions
Recoverable = max(wpsSalary − Net, 0)
Finalisation locks the month, posts loan recoveries and opens WPS recovery records. Correcting a finalized month requires an explicit revision, which reverses those postings and refuses outright where a WPS recovery has already received money.
Finalisation requires the month's attendance to be Approved. It can be overridden with a recorded reason, which is written to the audit trail.
These are absent by design at present and should not be assumed to work:
Leave management, overtime pay, pro-rata for mid-month joiners/leavers, and end-of-service gratuity are all implemented (see Modules above) — this list previously claimed they were missing, which was stale.
An account can be restricted to a set of companies (companyScope, managed in Users).
companyScopeOf() / canSeeCompany() (server/auth.ts) enforce this on list, single-record
and export endpoints across employees, attendance, payroll, payments, loans, WPS, leave,
gratuity, reports and document storage. This used to be a total gap ("every authenticated
user can see every company's data"); it no longer is, but treat any new endpoint that
reads employee-linked data as scoped-by-default and add the same check rather than assuming
it inherits isolation automatically.
Artify Workforce (a separate Android app + Supabase project, repo staff) tracks selfie-
verified clock-in/out. The two systems are linked by Civil ID, since that is the only
identifier that reliably exists in both -- not HCMS Employee ID, and not Workforce's own
internal UUID.
civil_id_lookup table is an eligibility whitelist: a worker can only
register in the app with a Civil ID that appears there. POST /api/workforce/sync-eligibility
(Administrator only) populates it from this app's active employees, keyed by
db.civilIds.getCurrent(employeeId). An employee with no current Civil ID on file is
skipped -- add one first.GET /api/workforce/shift-status (used by the Workforce Deployment dashboard) looks up
today's clock-in/out for those same Civil IDs and re-keys the result onto HCMS Employee ID
for the frontend.shift-status,
sync-eligibility), authenticated with a shared secret (WORKFORCE_INTEGRATION_SECRET)
that Workforce verifies against a hash in its own integration_secrets table -- the
plaintext secret is never stored there.projects table) or clock-ins there will be geofence-checked
against the wrong location.Employee.assignedProjectCode -> Project.projectCode), not free text. An employee
with nothing selected there is synced without a project (older records that only have
the legacy free-text assignedProject personal-details field are still read as a
fallback until re-saved through Employment Details).WORKER by default -- there's no HCM field for
Workforce-specific supervisor authority today, so promoting someone to SUPERVISOR is a
manual edit in Workforce's own employees table.| Role | Capability |
|---|---|
| Administrator | Everything, including user administration |
| Payroll Manager | Everything except user administration; may finalise and revise payroll |
| Payroll User | Day-to-day data entry; cannot finalise payroll or delete documents |
| Viewer | Read and export only |
Granular permissions are defined in src/permissions.ts and enforced server-side. Hiding a
control in the UI is never the access check.
Vercel, built with vite build; api/index.ts serves all /api/* routes and
vercel.json rewrites everything else to the SPA.
Before the first production deploy, confirm:
JWT_SECRET is set to a value not used anywhere elseADMIN_INITIAL_PASSWORD is set, and changed through the UI after first sign-inDATABASE_URL uses the transaction poolernpm run lint and npm test both pass