TIME is CyberOS's time-entry, leave-management, and expense-capture spine. The basic primitives are simple: a TimeEntry records minutes worked against an Engagement / Project / Issue with a billable flag; an Expense records VND or USD spent with vendor, VAT, and receipt image; a LeaveRequest records absence with a kind and approver flow. What is hard is the integrity model: entries are append-only at the audit layer, every mutation writes a fresh row with a correction_to link, the weekly approval flow goes Member → Account Manager → CFO/CEO visibility, and Vietnamese labour-law caps (40 h regular / week, 300 h overtime / year) are enforced as hard rules. Expense receipts run through a Vietnamese-hóa-đơn-aware OCR pipeline (MST extraction, line-item parsing, VAT split). Multi-currency at every layer. Feeds INV (weekly billable summary), feeds REW (members' total hours fold into compensation context), feeds OBS (audit replay).
correction_to for mutationWhy TIME exists
Three reasons TIME is its own module rather than a feature in PROJ: (1) audit integrity — time entries drive Client invoices and Member compensation, so the storage model has to be append-only with chained audit rows, not the optimistic-mutation pattern PROJ uses for issues; (2) regulator obligations — Vietnamese Labour Code Art. 105 caps weekly hours and overtime, requires written approval flows, and demands a per-Member time record auditable on inspection; (3) expense capture is a different UX (camera + OCR) than time entry (timer + form) and warrants a separate workflow. Folding all of this into PROJ would corrupt PROJ's data model and bury the regulator-visible flows.
Every entry write produces a chained BRAIN row. Corrections write a new row with correction_to; the original is never edited. Invoice-grade integrity.
Snap a hóa đơn; the OCR pipeline pulls MST, line items, VAT split, and queues for Member confirm. No form-filling for the 80% case.
Hard rules enforce 40 h regular / week and 300 h overtime / year (Labour Code 2019 Art. 107). Violations block save and page CHRO.
The bet is that the integrity properties travel best when they live next to the timer; the labour-law caps travel best when they sit between the timer and the database; and the expense flow travels best when it shares the integrity model. Putting all three in one module keeps the audit chain coherent and lets INV pull from a single source of truth.
What it does — 5W1H2C5M
A structured decomposition of TIME's scope. Every cell traces back to PRD §9.10 and §19.5.
| Axis | Question | Answer |
|---|---|---|
| 5W · What | What is TIME? | Three sub-modules: time tracking (start/stop, retroactive, billable flag), leave management (annual, sick, sabbatical, unpaid, other), and expense capture (camera + OCR + categorise). All three share a Postgres canonical store, an append-only audit chain into BRAIN, and a weekly approval workflow. |
| 5W · Who | Who uses it? | Members: log time + expense + leave daily; submit weekly. Account Managers: approve weekly per Engagement. CFO: view consolidated dashboards, approve overtime exceptions, sign off on reimbursement batches. CHRO: own leave policy + labour-law cap enforcement. Agents: CUO/COO-skill nudges Members who haven't logged time in 2 days ((FR pending)). |
| 5W · When | When does it run? | Continuous: SPA timer, mobile capture. Weekly: batch approval cycle (Sunday 23:59 → Monday 09:00 AM review). Nightly: leave accrual recompute, overtime cap check, expense reimbursement batch. Monthly: hours summary to REW. |
| 5W · Where | Where does it run? | P1: single region (SG-1) with VN-residency S3 for receipt images. P3+: multi-region. The OCR pipeline runs as a Fargate task per OCR job; bursty workloads scale to 50 parallel tasks via SQS. |
| 5W · Why | Why a separate module? | Audit integrity, labour-law caps, and receipt OCR are three concerns that do not belong in PROJ. Splitting them out keeps PROJ's sync-engine simple and gives the regulator a single place to look. |
| 1H · How | How does it work? | Timer: SPA writes start_time; on stop, end_time + duration computed server-side as a generated column. Retroactive: Member enters duration + date; same path. Expense: camera capture → S3 → OCR Lambda → categoriser → Member confirm → entry. Leave: form submit → approver Notify → decision → calendar sync. |
| 2C · Cost | Cost budget? | P1: ~$70 / month for SG-1 single-tenant pilot. OCR cost averages $0.002 per receipt (AWS Textract); ~$50 / month for 25k receipts at 50 Members. 50-tenant: ~$280 / month. |
| 2C · Constraints | Constraints? | (a) Audit append-only — non-negotiable. (b) Labour-law caps enforced as hard rules. (c) Multi-currency at every layer. (d) Member time-log annotations are private namespace ((FR pending)) — not visible to AM. (e) Receipt OCR must handle hóa đơn (Vietnamese VAT invoice) format. |
| 5M · Materials | Stack? | Rust 1.81 · axum 0.7 · sqlx · PostgreSQL 16 · Redis 7 · S3 + KMS · AWS Textract (or PaddleOCR self-hosted at P2+) · vn-mst-validate skill · OpenTelemetry SDK · React + Zustand SPA · React Native (P3+). |
| 5M · Methods | Method choices? | Append-only with correction_to (not in-place edit). Generated column for duration_minutes. Per-Engagement billable_default + per-entry override. Weekly batch approval (not per-entry). Camera-first expense capture. Multi-currency stored as canonical-VND + spot-FX-rate snapshot. |
| 5M · Machines | Deployment? | Fargate axum service. RDS Postgres Multi-AZ. Redis hot cache. S3 + KMS for receipt images. SQS-driven OCR pool. Calendar sync via OAuth (Google / Outlook). |
| 5M · Manpower | Who maintains? | 0.5 FTE (CFO seat) at P1 launch + 0.25 FTE (CHRO for leave policy). CTO owns the engine. |
| 5M · Measurement | How measured? | Mobile capture p95 ≤ 250 ms (start/stop button). OCR turn-around p95 ≤ 8 s. Weekly approval completion ≥ 95% by Friday EOB. Labour-law cap violations = 0. INV billable-hours feed durability = 100%. |
Architecture
TIME is a single axum service exposing four surfaces (GraphQL subgraph, REST admin, mobile-friendly REST, MCP). It writes to PostgreSQL canonical, drives an OCR pipeline via SQS + Fargate workers, and writes chained audit rows to BRAIN. Outputs flow downstream to INV (billable summary), REW (hours context), and Calendar (leave events).
timer + form"] MOB["Mobile capture (P3)"] AGENT["🎯 CUO
via MCP"] end subgraph EDGE ["Edge"] GQL["GraphQL subgraph"] REST["REST admin"] MCP["MCP tools"] end subgraph CORE ["TIME service (Rust)"] TE["TimeEntry handler"] EX["Expense handler"] LR["Leave handler"] LAW["VN labour-law
cap enforcer"] APPR["Approval workflow"] FX["FX rate snapshotter"] CAL_SYNC["Calendar sync
(Google / Outlook)"] AUDIT["BRAIN audit bridge"] end subgraph OCR ["OCR pipeline"] SQS["SQS queue"] OW["Fargate OCR worker"] TX["AWS Textract
(or PaddleOCR)"] VN["vn-mst-validate
skill"] CAT["Categoriser"] end subgraph STORES ["Stores"] PG[("PostgreSQL
time_entry · expense
leave_request
append-only audit-side")] RED[("Redis 7
active timers · FX cache")] S3[("S3 + KMS
receipt images")] end subgraph SINKS ["Sinks"] BRAIN["🧠 BRAIN
audit + summary"] INV["🧾 INV
billable summary"] REW["💎 REW
hours context"] OBS["👁 OBS"] end SPA --> GQL MOB --> REST AGENT --> MCP GQL --> TE GQL --> EX GQL --> LR REST --> TE REST --> EX REST --> LR MCP --> TE TE --> LAW EX --> SQS SQS --> OW OW --> TX TX --> VN VN --> CAT CAT --> EX TE --> FX EX --> FX LR --> APPR LR --> CAL_SYNC TE --> APPR EX --> APPR APPR --> AUDIT TE --> PG EX --> PG LR --> PG TE --> RED EX --> S3 AUDIT --> BRAIN TE --> INV TE --> REW TE --> OBS classDef planned fill:#ccfbf1,stroke:#115e59 classDef store fill:#f5f3ff,stroke:#7c3aed classDef sink fill:#f5ede6,stroke:#45210e class SPA,MOB,AGENT,GQL,REST,MCP,TE,EX,LR,LAW,APPR,FX,CAL_SYNC,AUDIT,SQS,OW,TX,VN,CAT planned class PG,RED,S3 store class BRAIN,INV,REW,OBS sink
Internal components
| Component | Path (planned) | Responsibility |
|---|---|---|
time_entry.rs | services/time/src/time_entry.rs | TimeEntry CRUD. Generated column for duration_minutes. Per-entry billable override defaults from Engagement. |
expense.rs | services/time/src/expense.rs | Expense CRUD. Camera-capture → S3 → OCR queue. Categorisation via per-tenant chart of accounts. |
leave_request.rs | services/time/src/leave_request.rs | LeaveRequest CRUD. Kinds: annual · sick · sabbatical · unpaid · other. Approver flow via Notify. |
law_caps.rs | services/time/src/law_caps.rs | Vietnamese Labour Code Art. 105 / 107 enforcement. 40 h regular / week, 300 h overtime / year. Hard-blocks save on violation; pages CHRO. |
approval.rs | services/time/src/approval.rs | Weekly approval workflow. Member submit → AM approve → CFO visibility. Self-approval rejected ((FR pending)). |
fx.rs | services/time/src/fx.rs | FX rate snapshotter. Pulls Vietcombank rate daily; stores snapshot per entry for invoice-time fidelity. |
ocr_pipeline.rs | services/time/src/ocr_pipeline.rs | SQS-driven OCR worker. Calls AWS Textract (P1) or PaddleOCR self-hosted (P2+). Parses Vietnamese hóa đơn format. |
categoriser.rs | services/time/src/categoriser.rs | Expense categoriser via AI Gateway. Picks from per-tenant chart of accounts; confidence threshold for auto-apply. |
calendar_sync.rs | services/time/src/calendar_sync.rs | Two-way Google / Outlook sync for leave events ((FR pending)). |
nudge.rs | services/time/src/nudge.rs | CUO/COO-skill nudge for Members who haven't logged time in 2 days ((FR pending)). |
inconsistency.rs | services/time/src/inconsistency.rs | Detect overlapping entries, > 12 h continuous, and other anomalies ((FR pending) SRS). |
inv_export.rs | services/time/src/inv_export.rs | Weekly batched billable summary export to INV. |
dsar_export.rs | services/time/src/dsar_export.rs | DSAR bundle for a Member. |
migrations/ | services/time/migrations/ | sqlx migrations. All tables RLS by tenant_id; time_entry.member_id additionally enforced. |
Data model
Three primitives (TimeEntry, Expense, LeaveRequest) plus supporting tables for approvals, FX snapshots, and OCR results. Mutations are encoded as a fresh row with correction_to pointing at the superseded row.
Append-only audit pattern
A mutation never edits an existing row. The mutator inserts a new row with the new values and sets correction_to to the prior row's id. The prior row's status transitions to corrected. INV and downstream consumers read the latest row in a correction chain via WHERE correction_to IS NULL or by walking the chain forward from the original.
| Step | Action | DB effect | BRAIN row |
|---|---|---|---|
| 1 | Original entry | INSERT row A (status=submitted) | time.entry_create |
| 2 | Member discovers error, corrects duration | INSERT row B (correction_to=A); UPDATE A status=corrected | time.entry_correct |
| 3 | AM approves | UPDATE B status=approved + APPROVAL row | time.entry_approved |
| 4 | INV reads | SELECT * FROM time_entry WHERE correction_to IS NULL AND status='approved' | — |
API surface
Four surfaces: a federated GraphQL subgraph, a mobile-friendly REST surface for the timer / receipt-capture, an admin REST for OCR pipeline introspection, and an MCP tool catalogue for CUO.
GraphQL subgraph (federated)
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key", "@requiresScopes"])
type TimeEntry @key(fields: "id") {
id: ID!
member: Subject!
engagement: Engagement!
project: Project
issue: Issue
entryDate: Date!
durationMinutes: Int!
billable: Boolean!
description: String!
status: TimeEntryStatus!
correctionTo: ID
approvals: [Approval!]!
}
type Expense @key(fields: "id") {
id: ID!
member: Subject!
engagement: Engagement
expenseDate: Date!
vendor: String!
vnMst: String
amountMinor: Int!
currency: String!
vatAmountMinor: Int
categoryCode: String!
receiptUrl: String! # presigned 5-min
status: ExpenseStatus!
ocr: OcrResult
}
type LeaveRequest @key(fields: "id") {
id: ID!
member: Subject!
kind: LeaveKind!
startDate: Date!
endDate: Date!
durationDays: Int!
status: LeaveStatus!
approver: Subject
}
enum TimeEntryStatus { DRAFT SUBMITTED APPROVED REJECTED CORRECTED }
enum ExpenseStatus { DRAFT SUBMITTED APPROVED REIMBURSED REJECTED CORRECTED }
enum LeaveStatus { SUBMITTED APPROVED REJECTED CANCELLED }
enum LeaveKind { ANNUAL SICK SABBATICAL UNPAID OTHER }
type Mutation {
startTimer(engagementId: ID!, projectId: ID, issueId: ID, billable: Boolean): TimeEntry!
stopTimer(entryId: ID!, description: String!): TimeEntry!
logRetroactive(input: LogRetroactiveInput!): TimeEntry!
correctTimeEntry(id: ID!, patch: TimeEntryPatch!): TimeEntry!
submitWeek(weekOf: Date!): SubmitWeekResult!
@requiresScopes(scopes: [["time.submit"]])
approveTimeEntry(id: ID!): TimeEntry!
@requiresScopes(scopes: [["time.approve"]])
captureExpense(receiptBase64: String!, hint: ExpenseHint): Expense!
fileLeave(input: LeaveInput!): LeaveRequest!
approveLeave(id: ID!): LeaveRequest!
@requiresScopes(scopes: [["time.leave.approve"]])
}
Mobile-friendly REST
| Method | Path | Purpose |
|---|---|---|
| POST | /time/timer/start | Start timer with engagement / project / issue context. |
| POST | /time/timer/stop | Stop active timer. |
| GET | /time/timer/active | Return active timer for the caller, if any. |
| POST | /time/expense/capture | Multipart upload of receipt; returns expense id + OCR job handle. |
| GET | /time/expense/{id}/ocr | Poll OCR result. |
| POST | /time/leave | File leave request. |
| GET | /time/week/{week_of} | Get weekly summary for caller. |
| POST | /time/week/submit | Submit week. |
| GET | /admin/approvals/pending | List pending approvals for AM / CFO. |
| POST | /admin/approvals/{id}/decide | Approve or reject. |
| GET | /admin/inv/billable-summary?week_of=… | Billable summary export for INV. |
MCP tool catalogue
| Tool name | Inputs | Outputs | Annotations |
|---|---|---|---|
cyberos.time.start_timer | engagement_id, project_id?, issue_id? | TimeEntry | scope=time.write |
cyberos.time.stop_timer | description | TimeEntry | scope=time.write |
cyberos.time.log_retroactive | date, minutes, description | TimeEntry | scope=time.write |
cyberos.time.weekly_summary | member_id?, week_of | WeeklySummary | readonly · scope=time.read |
cyberos.time.capture_expense | receipt_image_url | Expense + OcrResult | scope=time.write |
cyberos.time.file_leave | kind, start, end, reason | LeaveRequest | scope=time.leave.file |
cyberos.time.approve | target_id, tier | Approval | destructive · human-confirm · scope=time.approve |
cyberos.time.nudge_member | member_id | {ok} | scope=time.nudge |
Key flows
Flow 1 — Log a time entry (timer)
Flow 2 — Weekly approval workflow
overtime exceptions require explicit CFO sign-off
(FR pending) — a Member MUST NOT be able to approve their own entries; self-approval attempts rejected at the API.
Flow 3 — Expense capture with OCR
or receives push via WebSocket U->>API: confirm / correct + submit API->>PG: status=submitted API->>B: time.expense_submit
Flow 4 — Sync to INV (weekly billable summary)
Flow 5 — Leave request with calendar sync
Entry lifecycle
A time entry traverses six states. Correction is encoded as a new row with correction_to pointing at the superseded row; the original is never edited in place.
Expense lifecycle (variant)
| Status | Trigger | BRAIN row |
|---|---|---|
draft | capture (image uploaded) | time.expense_capture |
ocr_pending | queued to OCR worker | — |
ocr_complete | OCR done; Member to confirm | time.expense_ocr_complete |
submitted | Member confirms + submits | time.expense_submit |
approved | AM approves | time.expense_approved |
reimbursed | CFO marks batch paid | time.expense_reimbursed |
rejected | AM rejects | time.expense_rejected |
corrected | superseded by correction row | time.expense_correct |
Functional Requirements
The CyberOS FR catalogue is being rebuilt one feature at a time via the open fr-author Agent Skill.
Previous FR enumerations were archived 2026-05-14 and are no longer reflected on this page. PRD/SRS narrative remains authoritative for the spec; specific FRs land here as they are re-authored.
Non-Functional Requirements
NFRs from PRD §11.2 that TIME must satisfy.
| NFR ID | Concern | Target | Measurement |
|---|---|---|---|
N(FR pending) | Timer start / stop API | p95 ≤ 250 ms | k6 + RUM |
N(FR pending) | Weekly summary view (5 weeks) | p95 ≤ 400 ms | SPA RUM |
N(FR pending) | OCR turn-around (receipt → result) | p95 ≤ 8 s | SQS + worker histogram |
N(FR pending) | Mobile capture viable on 3G | ≤ 3 s upload at 150 KB receipt | simulated network test |
N(FR pending) | OCR accuracy on hóa đơn corpus | ≥ 90% field-level | quarterly eval on 200-receipt corpus |
N(FR pending) | Append-only audit integrity | 0 in-place edits | schema constraint + CI gate |
N(FR pending) | Receipt image at rest | KMS-encrypted, RLS by tenant | policy audit |
N(FR pending) | Service availability | ≥ 99.9% (28-day) | OBS SLO |
N(FR pending) | VN Labour Code cap violations | = 0 (hard rule) | law_caps.rs runtime + CI test |
N(FR pending) | INV billable summary durability | 100% delivered | retry + dead-letter monitor |
N(FR pending) | Approval decisions persisted | 0 lost under crash | chaos test |
N(FR pending) | Correction-chain integrity | cycles forbidden; max depth 50 | migration constraint + CI |
Dependencies
TIME depends on AUTH, BRAIN, PROJ (for Engagement / Project / Issue references), AI (categoriser + OCR pipeline), MCP (CUO tools), and OBS. It is depended on by INV (billable summary), REW (hours context), HR (leave accruals), and PORTAL (Client-visible billable view at P2+).
(or PaddleOCR)"] MCP["🔌 MCP"] OBS["👁 OBS"] VN["vn-mst-validate skill"] end TIME["⏱ TIME"] subgraph downstream ["TIME is depended on by"] INV["🧾 INV"] REW["💎 REW"] HR["👥 HR"] PORTAL["Portal · P2"] end AUTH --> TIME BRAIN --> TIME PROJ --> TIME AI --> TIME OCR --> TIME MCP --> TIME OBS --> TIME VN --> TIME TIME --> INV TIME --> REW TIME --> HR TIME --> PORTAL classDef shipped fill:#f5ede6,stroke:#45210e classDef planned fill:#fef6e0,stroke:#9c750a class BRAIN,VN shipped class TIME,AUTH,PROJ,AI,OCR,MCP,OBS,INV,REW,HR,PORTAL planned
Compliance scope
Time records drive payroll and tax exposures; TIME must satisfy Vietnamese labour law, tax obligations, and the standard PDPL / GDPR set.
| Regulation / standard | Article / clause | TIME feature that satisfies it |
|---|---|---|
| Vietnam Labour Code 2019 (Law 45/2019) | Art. 105 — Normal working hours (≤ 48 h/week, ≤ 10 h/day) | law_caps.rs enforces 40 h regular / 48 h with OT cap. |
| Vietnam Labour Code 2019 | Art. 107 — Overtime caps (≤ 200 h / 300 h annually with consent) | Hard-block at 300 h annual; CHRO override required. |
| Vietnam Labour Code 2019 | Art. 113 — Annual leave entitlement | LEAVE_REQUEST + quota tracking + auto-accrual. |
| Vietnam Decree 13/2023 | Art. 17 — Personal data processing log | Every time entry → audit row. |
| Vietnam Decree 53/2022 | Art. 26 — Data residency | VN-tenant receipt images on hanoi-1 S3. |
| Vietnam Circular 88/2020 (Ministry of Finance) | Hóa đơn electronic invoice format | OCR pipeline parses canonical hóa đơn fields (MST, line items, VAT). |
| Vietnam PDPL (Law 91/2025) | Art. 14 — DSAR | DSAR export includes time entries, expenses, leave. |
| GDPR (EU 2016/679) | Art. 32 — Security of processing | KMS-encrypted receipt images, RLS, audit chain. |
| ISO/IEC 27001:2022 | A.5.36 — Compliance with policies | Approval workflow enforces policy on every entry. |
| SOC 2 Type II | CC6.1 — Logical access | RBAC + per-Member private namespace ((FR pending)). |
| SOC 2 Type II | CC7.1 — Detection / monitoring | Inconsistency detection (overlap / > 12 h). |
Risk entries
TIME-specific risks tracked in the risk register.
| ID | Risk | Likelihood | Impact | Owner | Mitigation |
|---|---|---|---|---|---|
R-TIME-001 | Audit chain breakage via direct DB edit | Low | Catastrophic | CSO | schema constraint forbids UPDATE on canonical columns; in-place change rejected at trigger. |
R-TIME-002 | Overtime cap bypass via timer-then-retroactive trick | Medium | High | CHRO | Cap enforcer evaluates total per ISO-week regardless of entry mode. |
R-TIME-003 | OCR mis-parse of MST → wrong vendor on invoice | Medium | Medium | CFO | vn-mst-validate skill checks; Member confirm step required before submit. |
R-TIME-004 | Self-approval via direct API call | Low | High | CFO | API rejects approver_id == member_id; CI test on every PR. |
R-TIME-005 | INV pulls double after correction | Low | High | CFO | INV reads WHERE correction_to IS NULL; chain walk asserted in test. |
R-TIME-006 | Receipt image leaks via presigned URL replay | Low | Medium | CSO | 5-min presign TTL; one-time use; audit row on every presign. |
R-TIME-007 | FX rate snapshot stale → wrong invoice value | Medium | Medium | CFO | Snapshot per entry; weekly Vietcombank fetch; INV uses entry-time snapshot. |
R-TIME-008 | Calendar sync clobbers user-created events | Low | Medium | CTO | Sync only events created by TIME; mark with X-CYBEROS-SOURCE property. |
R-TIME-009 | OCR cost spike from receipt spam | Low | Low | CTO | Per-Member rate limit (50 captures / day); CFO dashboard alert at 80%. |
R-TIME-010 | Member time-log private annotations leaked in DSAR | Low | Medium | DPO | DSAR for the Member themselves includes private namespace; cross-Member DSAR excludes. |
KPIs
TIME health rolls up into 9 KPIs covering usage, integrity, and OCR quality.
| KPI | Formula | Source | Target |
|---|---|---|---|
| Weekly submission rate | submitted / expected | BRAIN | ≥ 95% by Friday EOB |
| Days-since-last-entry distribution | histogram | BRAIN | median ≤ 1 day |
| OCR field-level accuracy | fields_correct / fields_total | quarterly eval | ≥ 90% |
| OCR turn-around p95 | histogram | SQS + worker | ≤ 8 s |
| Approval cycle time p50 | submit → approve, business hours | BRAIN | ≤ 24 h |
| Self-approval attempts blocked | count / month | BRAIN | tracked; expect 0 |
| Overtime cap violations | count / month | law_caps | = 0 |
| INV summary delivery | delivered / weeks | BRAIN | 100% |
| Correction-rate per Member | corrections / entries | BRAIN | tracked; alert > 10% |
RACI matrix
TIME is owned by CFO seat with CHRO co-ownership on the leave / labour-law facets.
| Activity | CEO | CFO | CHRO | CTO | CSO | AM |
|---|---|---|---|---|---|---|
| Service design + spec | A | R | C | C | C | I |
| Implementation | I | C | I | A/R | C | I |
| Approval-flow policy | C | A/R | C | I | I | R |
| VN labour-law cap policy | I | C | A/R | R | I | I |
| OCR engine procurement | I | C | I | A/R | C | I |
| INV billable summary review | I | A/R | I | C | I | C |
| Audit-chain integrity review | C | C | I | R | A | I |
| DSAR fulfilment | I | C | C | C | I | I |
| Incident response | A | R | C | R | R | I |
R Responsible · A Accountable · C Consulted · I Informed.
Planned CLI surface
A single admin CLI cyberos-time. Member-facing actions live in the SPA and mobile clients; the CLI is for tenant operators and CFO reporting.
1. Bulk-import historical entries (CSV)
$ cyberos-time import --csv historical-2026-q1.csv --tenant cyberskill
[import] parsed 4,217 rows · 6 errors
[import] creating entries (status=approved, source=migration)
[import] ✓ 4,211 created · ✗ 6 in errors.csv
[audit] brain seq=15203 chain=…
2. Weekly billable summary preview
$ cyberos-time billable-summary --week-of 2026-08-04 --tenant cyberskill
week of 2026-08-04 (5 working days)
engagement hours billable_vnd rate_card
ACME Q3 platform 142.5 285,000,000 senior-mix
BetaCo retainer 40.0 72,000,000 retainer-flat
GamaCorp T&M 12.0 24,000,000 senior
─────────────────────────────────────────────────────────────
total 194.5 381,000,000
→ push to INV? [y/N]
3. Push to INV
$ cyberos-time inv push --week-of 2026-08-04
[push] 194.5 hours · 381 mil VND · 3 engagements
[inv] batch_id: 01HZK5… created (status=draft on INV)
[audit] brain seq=15211 chain=…
4. Overtime cap report
$ cyberos-time overtime-report --year 2026
member ot_hours cap pct_used risk
linh@cyberskill.world 142 300 47.3% ▬ ok
tu@cyberskill.world 203 300 67.7% ▲ approaching
hai@cyberskill.world 287 300 95.7% ▼ critical → CHRO sign-off required
5. Replay OCR for a receipt
$ cyberos-time ocr replay --expense 01HZK6…
[replay] re-running OCR pipeline (engine=textract)
[replay] parsed: vendor=Highlands Coffee, MST=0304556677, amount=178,000 VND, VAT=16,182 VND
[replay] vn-mst-validate: ✓ matches GDT registry
[replay] categoriser: T&E.meals (confidence=0.93)
[audit] brain seq=15218 chain=…
6. DSAR export for a Member
$ cyberos-time dsar-export --subject linh@cyberskill.world --output linh-time.zip
[dsar] subject: linh@cyberskill.world
[dsar] time_entries: 1,247 (including 18 corrected chains)
[dsar] expenses: 287 (with receipts)
[dsar] leave_requests: 12
[dsar] approvals: 842
[dsar] written: linh-time.zip (62 MB)
[audit] brain seq=15221 chain=…
7. Calendar reconcile (re-sync drift)
$ cyberos-time calendar reconcile --provider google --member linh@cyberskill.world
[reconcile] fetching Google calendar events created by CyberOS …
[reconcile] 3 leave requests · 3 calendar events found · 0 drift
[reconcile] done
Phase status & estimates
cyberos-time| Capability | Status |
|---|---|
| Timer start/stop + retroactive entry | planned · P1 |
| Per-Engagement billable rules | planned · P1 |
Append-only audit + correction_to | planned · P1 |
| Weekly approval workflow | planned · P1 |
| VN Labour Code cap enforcement | planned · P1 |
| Multi-currency + FX snapshot | planned · P1 |
| Camera receipt capture | planned · P1 |
| Vietnamese hóa đơn OCR + MST validate | planned · P1 |
| Expense categoriser (chart of accounts) | planned · P1 |
| Leave request + approver flow | planned · P1 |
| Calendar two-way sync | planned · P1 |
| INV weekly billable summary push | planned · P1 |
| CUO nudge for missing entries | planned · P1 |
| Inconsistency detection | planned · P1 |
| Self-hosted PaddleOCR (cost optimisation) | planned · P2+ |
| Native mobile (offline-first capture) | planned · P3+ |
References
- PRD §9.10 — TIME product FRs.
- PRD §19.5 — Schedule, Leave, Attendance SRS-tier FRs.
- PRD §11.2 — NFRs that TIME must satisfy.
- SRS §4.10 — Formal (FR pending) through (FR pending) with verification methods.
- Vietnam Labour Code (Law 45/2019/QH14) — Art. 105 (working hours), Art. 107 (overtime), Art. 113 (annual leave).
- Vietnam Decree 13/2023/NĐ-CP — Personal data processing.
- Vietnam Decree 53/2022/NĐ-CP — Data residency.
- Vietnam Law 91/2025/QH15 (PDPL) — Personal Data Protection Law.
- Circular 88/2020/TT-BTC — Hóa đơn (Vietnamese VAT e-invoice) format.
- AWS Textract — OCR engine (P1).
- PaddleOCR — open-source alternative for P2+ self-hosting.
- vn-mst-validate — CyberOS skill for MST validation against GDT.
- Architecture context: infrastructure.html#time.