First working prototype

This commit is contained in:
2026-09-06 13:50:58 +02:00
parent ecf08f8307
commit f61b9025eb
44 changed files with 5118 additions and 905 deletions

129
README.md
View File

@@ -1,43 +1,96 @@
# Svelte + Vite
# TimeLog
This template should help get you started developing with Svelte in Vite.
Offline-first PWA for tracking hours on site. The day starts and ends on its own, each
task begins where the previous one ended, and the app's main output is a concise
summary of the last working day, ready to copy into a paper logbook.
## Recommended IDE Setup
Built for use outdoors: high contrast, large targets, usable with gloves on. All data
stays on the device (IndexedDB); there is no backend and nothing is uploaded.
[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
## Development
## Need an official Svelte framework?
Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
## Technical considerations
**Why use this over SvelteKit?**
- It brings its own routing solution which might not be preferable for some users.
- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
**Why include `.vscode/extensions.json`?**
Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
**Why enable `checkJs` in the JS template?**
It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate. This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of JavaScript, it is trivial to change the configuration.
**Why is HMR not preserving my local component state?**
HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/sveltejs/svelte-hmr/tree/master/packages/svelte-hmr#preservation-of-local-state).
If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
```js
// store.js
// An extremely simple external store
import { writable } from 'svelte/store'
export default writable(0)
```sh
npm install
npm run dev # http://localhost:5173
npm test # unit tests for the time, prediction, resume and boundary logic
npm run check # svelte-check
npm run build # production build into dist/
```
In dev the console exposes `timelog.seed()` to generate 20 days of realistic history
(useful for exercising the suggestion engine) and `timelog.wipe()` to clear it.
## Deployment
The stack is a single container: a multi-stage build compiles the app and Caddy serves
the static output, obtaining and renewing a Let's Encrypt certificate on its own.
```sh
cp .env.example .env
$EDITOR .env # set SITE_ADDRESS and ACME_EMAIL
docker compose up -d --build
```
Requirements:
- `SITE_ADDRESS` must already resolve to the server.
- Ports **80 and 443** must be reachable from the internet. Port 80 is not optional —
it is what the ACME challenge uses to prove domain ownership.
Certificates are stored in the `caddy_data` volume. Keep it: without it Caddy re-issues
on every recreate and will hit the Let's Encrypt rate limit after a handful of restarts.
To update, pull and rebuild:
```sh
git pull && docker compose up -d --build
```
Running clients do not reload on their own. Each app checks hourly for a new build and
offers an **"Installer"** banner — but only while no working day is in progress, so an
update can never interrupt someone mid-day.
### HTTPS is not optional
Browsers only register a service worker in a secure context. Served over plain `http://`
to an IP or hostname, the app still loads but has **no offline support, cannot be
installed, and never updates** — which removes the point of the design. `localhost` is
the only exception, which is why `npm run dev` works without certificates.
### Behind an existing reverse proxy
If something upstream already terminates TLS, set `SITE_ADDRESS=:80`, drop the `443`
port mappings, and let the proxy forward to port 80. `ACME_EMAIL` is then unused but
must still be non-empty — Caddy will not parse a blank value.
The app must be served from the root of its domain. `start_url` and the service worker
scope are both `/`, so hosting it under a subpath will not work without changing the
manifest and Vite's `base`.
## Architecture
Two decisions shape everything else.
**Raw timestamps are stored; rounding is applied only at render.** Changing the rounding
setting therefore corrects past days too. Adjacent entries share one stored instant —
entry *N*'s end *is* entry *N+1*'s start — so rounding can never open a gap between
them. Times a worker sets by hand are snapped to the grid on write, so a chosen value
reads back exactly as chosen.
**Suggestions are derived from history, not from counter tables.** There is nothing to
keep in sync; the model is rebuilt in memory from the entries. The tradeoff is that a
short retention window degrades predictions, which is why retention defaults to two
years.
```
src/lib/
time.js local dates, rounding, formatting (pure)
predict.js the suggestion engine (pure)
resume.js logbook text builder (pure)
db.js Dexie schema and the chain invariant
day.svelte.js day lifecycle state machine
```
The four pure modules hold the logic worth testing and carry the unit tests. `db.js`
concentrates every write that touches a boundary into `closeAndStart` and
`setEntryStart`, so the timeline cannot drift out of order from anywhere else.