Add CHANGELOG and launch validation checklist

CHANGELOG.md follows Keep-a-Changelog. The Unreleased section
sits at the top; the v0.1.0 entry summarises every commit on
the path from the empty fork to a hosted multi-tenant build:
fork + restructure, storage/auth/tenant/httpapi packages, the
serve command, full frontend (landing, login, verify, app shell,
PWA, sync), Docker + deploy + backup tooling, docs, and the
community infrastructure. Two known-incomplete items called out
explicitly: the upstream Notesium UI is not yet wired into the
multi-tenant shell, and SMTP delivery has only been exercised
against the LogMailer.

docs/launch-checklist.md is the manual QA pass for v0.1.0:
environment prerequisites, the full sign-up to first-note flow
on Chrome / Firefox / iOS Safari / Android Chrome (with explicit
PWA-install and offline-shell verifications), documentation
accuracy spot-checks, the community-infra render checks, and a
backup-and-restore round-trip on the staging host. The QA
performer signs off at the bottom; failures are filed as
separate bugs against the milestone.

The actual v0.1.0 tag will be cut by a maintainer; tagging is
not part of this commit.

Refs #30 and #33.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 23:20:20 +02:00
co-authored by Claude Opus 4.7
parent c92d4bf953
commit d7c6dfa799
2 changed files with 174 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
# Changelog
All notable changes to librenotes are recorded here. The format
loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and the project follows [Semantic Versioning](https://semver.org/).
## [Unreleased]
## [0.1.0] — TBD
The initial public release: a fork of Notesium turned into a
multi-tenant SaaS, plus the surrounding infrastructure.
### Added
- **Fork.** Forked [alonswartz/notesium](https://github.com/alonswartz/notesium)
at `aff9f460c2d864112db7f0935b4168b107289d91`, restructured into
the standard Go layout (`cmd/`, `internal/`), renamed the
module to `git.librete.ch/public/librenotes`, preserved the MIT
license alongside librenotes copyright, documented the upstream
remote and cherry-pick workflow.
- **User model + SQLite storage** (`internal/storage`). UUIDv4
IDs, email uniqueness, WAL mode, embedded migrations.
- **Magic-link authentication** (`internal/auth`). 32-byte
cryptographically random tokens, SHA-256-hashed at rest,
single-use, 15-minute expiry. HS256 JWT sessions with 24-hour
lifetime, `jwt.WithValidMethods` to reject `alg=none`. Pluggable
`Mailer` interface with `SMTPMailer` and dev-friendly
`LogMailer`. DB-backed per-email rate limiting.
- **Per-tenant filesystem isolation** (`internal/tenant`). Each
user gets a sandboxed directory; all reads and writes go
through `os.Root` so path traversal and symlink escapes are
rejected at the syscall layer.
- **Tenant-aware HTTP API** (`internal/httpapi`). JWT middleware,
tenant context, `/api/whoami`, `/api/notes` CRUD with
optimistic-locking conflict detection (`?base=<unix>`),
`/healthz`.
- **`librenotes serve`** command wires storage, auth, tenants,
notes, and a static frontend into one binary. Configuration
via `LIBRENOTES_*` env vars or flags. Background goroutine
purges expired magic tokens.
- **Frontend** (`cmd/librenotes/web/public/`): mobile-first
landing page, login + verify pages, app shell with sync
badge and conflict dialog. Vanilla JS, no build step.
- **JWT session client** with sessionStorage + automatic
`Authorization: Bearer` injection and 401-redirects-to-login.
- **Tenant-scoped localStorage** wrapper so two users on the
same browser have isolated UI state; cleared on logout.
- **Offline cache** in IndexedDB (`notes-cache.js`) with dirty
tracking and tombstones for deletes.
- **Background sync** (`sync.js`) — pushes dirty rows on
reconnect, pulls remote changes, surfaces conflicts to the UI
via custom events.
- **PWA support**: manifest, service worker (cache-first shell,
network-first API), 192/512/maskable icons, install prompt.
- **Responsive CSS** with explicit breakpoints from 320px to
2560px, including a 3-column ultrawide layout primitive.
- **Pointer events** on the resize handle so touch and pen work
identically to mouse, including pointer capture for drag.
- **Containerised deployment**: multi-stage Dockerfile producing
a distroless `nonroot` image, dev + prod Compose stacks,
in-binary `librenotes healthcheck` for distroless HEALTHCHECK.
- **CI**: Gitea Actions workflow runs `make lint`, `make build`,
`make test` on every push and PR.
- **Deploy workflow** (gated on `DEPLOY_ENABLED=true`) builds
and pushes images, SSHes to the host, runs `compose pull && up
-d`, polls `/healthz`.
- **Backup tooling** (`scripts/`): SQLite online snapshot + tar
of notes, optional rclone off-site copy, retention pruning,
weekly automated restore-test, systemd timer units.
- **Documentation**: user guide, self-hosting, API reference,
operations, contributing.
- **Community infrastructure**: bug-report and feature-request
Gitea issue templates, PR template, Code of Conduct.
- **First-run onboarding**: welcome dialog + seeded sample note,
dismissal persisted per tenant.
### Notes
- The bundled notes engine (the original Notesium UI under
`internal/notesium/web/app/`) is not yet wired into the
multi-tenant frontend. Phase 7 will replace or wrap it.
- SMTP delivery has been exercised against the LogMailer only;
real-provider integration is part of self-hosting validation.
[0.1.0]: https://git.librete.ch/public/librenotes/releases/tag/v0.1.0