Light of day
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# puppy-tracker
|
||||
|
||||
A tiny offline-first PWA for tracking your puppy's sleep, meals, pees, and poos.
|
||||
The browser is the primary client; a small Go server provides a shared
|
||||
source-of-truth and sync between devices.
|
||||
|
||||
## How sync works
|
||||
|
||||
- Each event has a UUID and an `updatedAt` timestamp.
|
||||
- Mutations (add / edit / delete) happen against `localStorage` first, so the
|
||||
app keeps working when offline. Deletes are recorded as tombstones so they
|
||||
can propagate.
|
||||
- On app load, on `online`, on every mutation (debounced), and every 60 s, the
|
||||
client POSTs its full event list to `/api/events/sync`. The server merges
|
||||
it with its own copy using last-write-wins on `updatedAt` and returns the
|
||||
merged set.
|
||||
- Service worker bypasses cache for `/api/*` so writes always hit the server
|
||||
when online; static assets are still cached for offline use.
|
||||
|
||||
A status pill in the header shows `syncing…` / `synced 2m ago` / `pending` /
|
||||
`sync error` / `offline`. Tap it to force-sync.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
puppy-tracker/
|
||||
├── flake.nix # packages (server, static, default), devShell, nixosModule
|
||||
├── module.nix # systemd unit, StateDirectory, hardening
|
||||
├── server/
|
||||
│ ├── go.mod
|
||||
│ └── main.go # JSON-file store, LWW sync, static file serving
|
||||
└── src/ # the web app
|
||||
├── index.html
|
||||
├── app.js
|
||||
├── style.css
|
||||
├── sw.js
|
||||
├── manifest.json
|
||||
└── icon.svg
|
||||
```
|
||||
|
||||
## Run locally
|
||||
|
||||
```sh
|
||||
nix run # http://localhost:8080, data in $XDG_DATA_HOME/puppy-tracker
|
||||
PUPPY_ADDR=:9000 nix run # custom port
|
||||
|
||||
# Hot-iterate (data in /tmp):
|
||||
nix develop -c sh -c 'cd server && go run . -static ../src -data /tmp/puppy-events.json'
|
||||
```
|
||||
|
||||
## Use it on NixOS
|
||||
|
||||
In your system flake:
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs.puppy-tracker.url = "path:/path/to/puppy-tracker";
|
||||
|
||||
outputs = { self, nixpkgs, puppy-tracker, ... }: {
|
||||
nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
puppy-tracker.nixosModules.default
|
||||
{
|
||||
services.puppy-tracker = {
|
||||
enable = true;
|
||||
port = 8080;
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The server runs as a `DynamicUser` systemd unit. Data is stored at
|
||||
`/var/lib/puppy-tracker/events.json` via `StateDirectory`.
|
||||
|
||||
## Notes
|
||||
|
||||
- No auth. Intended for a home LAN. If exposing publicly, terminate TLS and
|
||||
authenticate with a reverse proxy in front (Caddy / nginx / Tailscale Funnel).
|
||||
Reference in New Issue
Block a user