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:
86
CHANGELOG.md
Normal file
86
CHANGELOG.md
Normal 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
|
||||
88
docs/launch-checklist.md
Normal file
88
docs/launch-checklist.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Launch validation checklist
|
||||
|
||||
Manual QA pass for v0.1.0. Performed on a staging environment
|
||||
that mirrors production (Docker Compose with the prod overrides,
|
||||
real SMTP, public DNS + TLS termination).
|
||||
|
||||
The goal is to convince yourself a brand-new user can go from
|
||||
landing page to first note without confusion, and that a
|
||||
contributor can file an issue or open a PR through the templates.
|
||||
|
||||
## Environment
|
||||
|
||||
- [ ] Staging URL reachable over HTTPS.
|
||||
- [ ] `LIBRENOTES_BASE_URL` matches the staging URL exactly.
|
||||
- [ ] SMTP credentials valid; test send to a real inbox succeeds.
|
||||
- [ ] `/healthz` returns 200 from outside the Docker network.
|
||||
|
||||
## End-user flow
|
||||
|
||||
### Desktop — Chrome
|
||||
|
||||
- [ ] Landing page (`/`) loads and renders correctly.
|
||||
- [ ] All links in the header and footer work.
|
||||
- [ ] "Sign in with email" → `/login.html`.
|
||||
- [ ] Submit a never-before-seen address → success state shows.
|
||||
- [ ] Magic-link email arrives within 30s.
|
||||
- [ ] Click link → `/verify.html` → "Go to your notes".
|
||||
- [ ] Token is stripped from the address bar after verification.
|
||||
- [ ] App shell shows email + sync badge transitions to
|
||||
"synced" within a few seconds.
|
||||
- [ ] Onboarding dialog appears.
|
||||
- [ ] Welcome note exists in the notebook.
|
||||
- [ ] Dismissing the dialog does not reopen on reload.
|
||||
- [ ] Theme toggle persists across reload.
|
||||
- [ ] Sign out clears session and tenant store; signing back
|
||||
in does NOT show onboarding again (same device, same
|
||||
tenant).
|
||||
|
||||
### Desktop — Firefox
|
||||
|
||||
- [ ] Repeat the same flow with no console errors specific to
|
||||
Firefox.
|
||||
|
||||
### Mobile — iOS Safari
|
||||
|
||||
- [ ] Layout has no horizontal scroll on iPhone SE (320px).
|
||||
- [ ] Touch handles for any interactive controls respond
|
||||
without ghost clicks.
|
||||
- [ ] PWA installable via "Add to Home Screen".
|
||||
|
||||
### Mobile — Android Chrome
|
||||
|
||||
- [ ] beforeinstallprompt surfaces the install button.
|
||||
- [ ] Installed PWA opens in standalone mode.
|
||||
- [ ] Offline: open the app with airplane mode on; the shell
|
||||
renders and the welcome note loads from IndexedDB.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [ ] User guide accurate (reflects current behaviour).
|
||||
- [ ] Self-hosting guide produces a working stack on a fresh
|
||||
Debian box (re-run quick-start).
|
||||
- [ ] API reference matches actual responses for /auth and
|
||||
/api/notes.
|
||||
- [ ] CONTRIBUTING dev-setup section runs to a green
|
||||
`make test` from a fresh clone.
|
||||
|
||||
## Community infrastructure
|
||||
|
||||
- [ ] "New issue" page shows two templates (bug, feature).
|
||||
- [ ] Bug template's required fields actually require input.
|
||||
- [ ] PR template renders on the new-PR form.
|
||||
- [ ] CoC reachable from the README.
|
||||
|
||||
## Backup & restore
|
||||
|
||||
- [ ] `scripts/backup.sh` produces an archive on the staging
|
||||
host.
|
||||
- [ ] `scripts/backup-restore-test.sh` passes against that
|
||||
archive.
|
||||
- [ ] Retention prune leaves the right number of files.
|
||||
|
||||
## Sign-off
|
||||
|
||||
- [ ] All checked. Any failures filed as separate bug reports
|
||||
against the v0.1.0 milestone.
|
||||
- [ ] QA performer: ____________________
|
||||
- [ ] Date (UTC): ____________________
|
||||
Reference in New Issue
Block a user