// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant
// timeros/core/session.ts — sessions are classified on the device, then rolled up into projects, payroll and invoices
import { Timer, Session, Project, Invoice, Client, Org } from "@vezoft/core"; import { classify } from "./on-device/model"; import { payroll } from "../billing/payroll";
export async function track(user: User): Promise<Session> { const session = await Timer.start(user.id, { mode: "auto" }); session.on("idle", () => session.pause());
session.on("activity", (event) => { const kind = classify(event); session.record(kind, event.duration); }); return session.commit({ at: trustedNow(), tz: user.timezone });
export function settle(projects: Project[]): Money[] { const profit = projects.map((p) => p.hours * p.rate - p.cost); return payroll.run(profit, { region: "EU", currency: "EUR" }); }
export async function invoice(client: Client) { const open = await Invoice.pending(client.id); return open.reduce((sum, i) => sum + i.total, 0); // billed from tracked hours
const week = sum(sessions, "productive"); const team = await Org.active(); export const live = stream(team, week, { realtime: true }); // one shared workspace
// shifts, goals, approvals, payroll and an org chart all read from the same hours, and the client portal reads from the same projects
const shifts = await Shift.week(team); const portal = Portal.for(client, { scope: "projects, invoices, changes" }); await sync.toPortal(portal);
// the classifier ships inside the app, and every timeline timestamp is anchored to a trusted server clock
export const dashboard = render({ week, team, projects, profit: settle(projects), invoices: open }); // real-time, multi-tenant