time-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 4857f8a940b5
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 703ed60f2cc5ad3d98a5bf4a
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
AGENTS.md
# Time

Time is a free time tracker with timesheets and reports, and a free alternative to Toggl Track and Harvest. It is an OpenApp in the OpenApps free apps store (https://openapps.free/), owned by the OpenApps team. It lives at https://time-free.openapps.xyz/.

## What it promises

- Free, with no limit on projects, clients, entries or teammates, no ads, no third-party trackers, nothing sold and no paid tier. The hosting counts visits (page views, speed and errors); say so whenever the app talks about tracking. Never add a cap, an upsell, ads or a third-party tracker.
- No sign-up. Every visitor starts as a guest workspace in the browser; email sign-in only keeps time on every device.
- People own their time: CSV export of any range, and of everything, is always free.
- A shared project shows its owner the name and time teammates log to that project, and nothing else of theirs. Teammates never see the owner's rates, other projects or other time.
- "Create an invoice" sends only the invoice lines, the person's name and the client's name to Invoice (https://invoice-free.openapps.xyz/), and says so before sending.
- AI assistants can do the main job through the public API (`functions/api.ts`) with a workspace key, documented in `public/llms.txt` and `public/openapi.json`. Keep both true whenever the API changes.

## How it is built

- `index.html` is the static landing page that search engines and AI crawlers read. `public/index.md` is the same page in markdown. Keep their copy, comparison (dated, "as reported"), FAQ and JSON-LD in step with each other and with what the app does. Competitor facts come from `docs/research/wave4-pricing.md` in the store repo.
- `src/` is the React app. `/` mounts the start box (`Start.tsx`) into the landing hero; `/timer`, `/timesheet`, `/reports`, `/projects`, `/settings` and `/join/<id>` hide the landing (`Shell.tsx`).
- `functions/lib/time.ts` is shared by the app and the API: durations, days in a time zone, money in minor units, report totals, CSV and invoice lines. A billable entry earns seconds x hourly rate / 3600, rounded half up once per entry; every total is a sum of entries, so groupings always add up.
- `src/lib/session.ts`: the guest session, the workspace (`users/<user>` points at it), and the sign-in hand-off. Before the hosted email sign-in the guest writes a one-time code to `ws/<id>/handoffs/<code>`; after it, the account claims the code and becomes an owner. A new account adopts the workspace; an account that already has one gets this browser's projects, clients, tags, time and running timer copied in (same ids).
- `src/lib/data.ts`: live queries for the workspace, the running timer and entries in a range, a short local overlay so writes show at once, and every write (timer, entries, projects, sharing, keys).
- `policy.json` (all reads need membership; ids are random):
  - `ws/<w>` settings (name, currency, default rate in minor units, week start, time zone); `members/<user>` with role owner or api; `handoffs/<code>`; `apikeys/<sha256 of key>`; `clients`, `projects`, `tags`, `entries` (start/end unix seconds, at most 1,000 hours), `timer/now`.
  - `shared/<s>` a project shared by link (name, color, client name, billable default, owner name, closed): `owners/<user>` (members of the owning workspace), `joins/<user>` (anyone who knows the id, unless their workspace is in `removed/<workspace>`), `entries/<id>` (a teammate's copy of an entry in their own workspace, written in the same batch; only owners read them). Removing a teammate deletes their joins and marks their workspace removed, so that workspace and its assistant cannot rejoin, add time, or change or delete what it logged until the owner lets them back in. Stopping sharing freezes teammates' logged time the same way. The link itself still works for anyone else who has it, including the same person in a new browser.
  - Workspace keys look like `tk_<workspace>_<secret>`. Only the hash is stored. The API function checks the hash before it reads or writes anything, then joins the workspace as role api. Every API caller shares one identity, so never act on a workspace without checking its key first.
  - Rules mention `@const.BOUNDED_PUBLIC_PRINCIPAL_API`, which exists only once the app exists: a brand new app first deploys with those clauses removed.
- `policy-tests/` covers every rule that guards access. Run `bounded tests run --app-id <id>` after changing the policy.
- `public/sw.js` is built from `src/sw.js` (vite.config.ts) and caches the app's files; data always comes live.

## Working on it

```bash
npm install
npm run build     # typecheck + build to dist/
npm run dev       # http://localhost:4349
```

The app is an OpenApp, so nobody deploys it directly: changes ship through previews and releases as your runtime instructions describe. Check a change by tracking time on a phone-sized and a desktop browser, reloading with a timer running, typing totals into the timesheet, reading a report and its CSV, creating an invoice, sharing a project into a second browser and logging time there, and calling the API with curl (including a wrong key).

## Voice

Plain words, short sentences, no jargon, no em dashes. Say what happens and be honest about limits.

Change history

Point OpenApps links to openapps.free
4857f8a940 · 19 hours ago
Bind agent address constants in policy
62b1e6acb2 · 20 hours ago
Use functions.openapps.xyz alias and add OpenApp contribution strip
61d972193a · 20 hours ago
Bounded source sync
fc644b4327 · 1 day ago
Bounded source sync
22f511f3db · 1 day ago
Bounded source sync
351a8d754c · 1 day ago
Bounded source sync
0da238a77e · 1 day ago