Skip to content

Releases: 0xzerolight/watchpost

v1.3.0

Choose a tag to compare

@0xzerolight 0xzerolight released this 08 Sep 18:14

Added

  • Start page (Settings -> Start page). Which of the three nav pages watchpost opens on.

Changed

  • The repositories dashboard has its own path, /repos.

  • No movement badge on the "All" period (repo page KPI tiles, Analytics totals).

v1.2.0

Choose a tag to compare

@0xzerolight 0xzerolight released this 29 Aug 16:38

Added

  • An Analytics page (third nav entry). Portfolio totals over a combined star curve, a ranked
    repo table and a recent-changes feed.

  • A sync interval (Settings -> Sync every). Set 10m, 6h or 1h 30m instead of a cron
    expression, applied without a restart.

  • CSV and JSON export per repo (repo page header).

Changed

  • The repo page leads with KPI tiles over one hero chart. Clicking a tile switches the metric
    the chart plots.

  • Views and clones plot as bars.

  • Recessive chart gridlines, an HTML tooltip and event markers that rest as dots.

  • The recent-changes feed moves from the dashboard to the Analytics page.

v1.1.0

Choose a tag to compare

@0xzerolight 0xzerolight released this 20 Aug 07:57

Added

  • GHCR container pull counts, auto-detected. Every sync also fetches each tracked repo's
    public package page (github.com/{owner}/{repo}/pkgs/container/{name}) and charts the
    cumulative pull count as a "Container pulls" card on the repo page. Scraped, because no GitHub
    API exposes the number; unauthenticated, so it costs no token scope and no rate budget. A repo
    without a package named after it 404s and is skipped — zero configuration. A failed scrape is a
    partial sync like any failing endpoint, and deliberately does not count toward the total-failure
    verdict that backs a repo off. Schema migration v4 adds the container_pulls table (day-keyed,
    monotonic MAX, same rules as release assets).

Changed

  • The repo charts are redrawn on a validated palette. Each series is a gradient-filled line on
    a palette checked for colourblind separation and 3:1 contrast against the card surface. The axis
    borders and vertical gridlines are gone, dates read Aug 19 rather than 2026-08-19, counts past
    five digits read 12.3K, and the tooltip takes the card's own surface and ink instead of the
    library default. Event markers drop to a half-strength dashed line under a ringed dot, so a
    marker sits behind the data it annotates rather than across it.

  • Event-kind chips carry their colour on a dot, not in the text. The label is body ink at every
    size, which frees the palette from having to be readable as small text and lets its two lightest
    slots be used as marks.

  • Chart cards with no observed data are hidden. A repo that ships only docker images no longer
    shows a blank Downloads pane, and repos without container packages don't get a blank pulls pane;
    the same rule covers views/clones cards where the token lacks traffic permissions. A repo with
    nothing observed at all keeps its existing empty state.

v1.0.0

Choose a tag to compare

@0xzerolight 0xzerolight released this 18 Aug 20:15

Added

  • One-line install. curl … | bash on Linux and macOS, irm … | iex on Windows. Pulls the published image, writes PUID/PGID so the bind-mounted data/ is writable whatever the host uid is, waits for /health, and opens the setup page. scripts/update.sh updates in place.
  • First-run setup page. An install with no WATCHPOST_GITHUB_TOKEN boots and redirects every page to /setup, where a pasted token is checked against GitHub before it is saved and collection starts immediately. Replaceable from settings afterwards; only the last four characters are ever rendered.
  • Multi-arch images at ghcr.io/0xzerolight/watchpost, linux/amd64 and linux/arm64, built on a tag push.
  • PUID/PGID support. The container entrypoint aligns the data directory with the host user and drops privileges, replacing the manual chown -R <uid> data.
  • WATCHPOST_TZ. Displayed times - last synced, the --doctor rate-limit reset, the day a new event defaults to - render in the configured IANA zone instead of always UTC. Stored dates, chart day buckets and WATCHPOST_CRON stay UTC.
  • Real error and loading states. A failed request says so instead of failing silently, and every request that can be waited on has a loading indicator and a disabled state.
  • Accessible navigation. Skip link, current-page state in the nav, focus that survives a fragment swap, visible sort-direction indicators, and delete confirmation in a real dialog.
  • Faster page loads. gzip compression, plus content-hashed asset URLs served immutable for a year and revalidated with a 304.
  • Safe migrations. The database is copied to data/watchpost.v{schema}.{timestamp}.bak before a schema upgrade and the newest three are kept. Schema v2 adds the indexes the page queries actually use.
  • AGPL-3.0-or-later license.

Changed

  • WATCHPOST_GITHUB_TOKEN is optional. Missing is no longer a startup error; it is the state the setup page exists to resolve. Schema v3 adds a settings table to hold a token saved there.
  • --doctor reports token provenance. Which token is in use and where it came from, and an install with none fails with a pointer to the setup page rather than a request that was never made.
  • Rebuilt pages. One shared component set - real labels on every form field, consistent headings, empty states, and a restructured repo, settings and index page. Spacing, type and colour are design tokens from a single source, and the event-kind chips meet WCAG AA contrast.
  • Cheaper charts and queries. A period change re-scales the existing charts instead of rebuilding them; the repo overview is one query rather than one per repo, with the delta recompute bounded to the window that can have changed.
  • Inline event handlers are gone, replaced by delegated listeners.
  • Minimum supported Rust version is 1.88. Docker base images are pinned to explicit versions and the build caches its dependency layer; CI runs a locked build, an MSRV check, a Docker build and an advisory audit.

Fixed

  • The Add event form pre-filled the UTC day, so between local midnight and the UTC rollover it defaulted to the wrong date.
  • A line chart with only one or two observed days drew nothing at all - the Downloads card on a repo whose releases were first read this week was an empty plot area. Such points now get a marker.
  • Rate-limit classification is limited to 403 and 429; a transient 5xx is retried instead of being counted as a rate limit.
  • Daily stats record the last observation of the day rather than the intraday maximum.
  • Repo writes are transactional, and a partial sync no longer inflates the error streak or the backoff behind it.
  • A database written by a newer build is refused at open with the version pair and the fix, instead of being served against a schema the binary does not know.
  • Backup pruning keys off the embedded timestamp, so a v10 database no longer discards its newest backups first.
  • The health endpoint verifies the database and queries the live schema.
  • Background polls no longer clear the error toast or clobber a pending focus target.
  • Enter submits the picker and edit-row forms, and sort links carry the client-side zoom instead of resetting it.
  • Chart tooltips are clamped to the canvas, reduced-motion preferences are honoured, and the axis labels are readable.
  • A poisoned mutex is recovered and a panicking handler is caught, rather than taking down the worker behind it.
  • Configuration is validated at startup: the token, the API base URL and the log filter.

Security

  • Security headers on every response. Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Cross-Origin-Opener-Policy. The policy allows no inline script or style at all (script-src 'self', style-src 'self'), so an injected <script> or onerror= does not execute even if it survives the escaping.
  • CSRF hardening. The cookie is checked for the shape this server mints, and carries Secure when the request arrived over HTTPS plus a 30-day Max-Age. Repo discovery is a CSRF-gated POST; it used to be a GET that spent API calls as a side effect.
  • Error responses carry no internal detail - no paths, no SQL, no upstream error strings.
  • There is no authentication. Anyone who can reach the port has full read and write. compose.yml publishes to 127.0.0.1:8080 rather than every interface, so the default deployment is not reachable from the network - bind it to the loopback or put it behind a proxy that authenticates.