Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ All notable changes to Sheaf are documented here. The format is based on [Keep a

`v1.0.0` is the first stable release. The `v0.x.y` releases were betas; from 1.0 on, the v1 API and database schema carry semver compatibility guarantees.

## [Unreleased]
## [1.0.1] - 2026-06-12

### Added

- **Support page.** A new Support entry in the sidebar with two sections. The top is an operator contact card populated from optional env vars (`SUPPORT_EMAIL`, `SUPPORT_URL`, `SUPPORT_NOTE`, `STATUS_URL`), surfaced read-only via `GET /v1/auth/config` the same way the legal-footer links are; it hides entirely when none are set, so a bare self-host shows nothing there. The bottom is static and identical on every instance: links to the project's GitHub issue tracker for bug reports and to the security policy + `security@sheaf.sh` for private vulnerability disclosure. The status-page link is operator-set rather than static, since a self-hosted instance's status page is the operator's own.
- **SMTP2GO delivery webhook.** A new `POST /v1/webhooks/smtp2go/events` endpoint feeds SMTP2GO's delivery/bounce/spam events into the same deliverability lifecycle as the SES and SendGrid handlers, so bounce suppression and soft-bounce self-healing work when sending via SMTP2GO (over the `smtp` backend). `delivered` clears transient soft-bounce state, `bounce` maps hard/soft from SMTP2GO's classification (an unclassified bounce defaults to soft, the conservative choice), and `spam` is treated as a complaint. SMTP2GO does not sign payloads, so the endpoint is guarded by a shared secret in the URL (`SMTP2GO_WEBHOOK_SECRET`; returns 404 when unset) - point the SMTP2GO webhook at `/v1/webhooks/smtp2go/events?token=<secret>` (JSON or form-encoded output both accepted) and enable at least the Delivered, Bounce, and Spam events. See SELFHOSTING for setup.

### Fixed

- **Email deliverability no longer permanently locks an account out.** Bounce/complaint handling was a write-once-to-bad flag: a single transient soft bounce (e.g. a greylisting MX deferring the first delivery attempt) flagged the address undeliverable, the matching `delivered` event was ignored, and nothing - not re-verifying, not even changing email - ever cleared it, so all further mail to the account was silently dropped with admin-only recovery. Deliverability is now a recoverable lifecycle: a soft bounce only blocks after `EMAIL_SOFT_BOUNCE_THRESHOLD` (default 5) accumulate without an intervening delivery; a successful-delivery event clears soft state automatically (the SendGrid webhook now consumes `delivered` events - enable Delivered in your event selection); and a flagged user gets a sign-in banner prompting them to re-verify or change their address. Verification emails are now sent even to a blocked address (the recovery channel must reach the user), and completing verification - or changing to a new address - clears the deliverability flags. New `POST /v1/auth/revalidate-email` drives the re-verify recovery. Hard bounces and spam complaints still block immediately and are cleared only by re-verification, never silently undone by a later delivery.

## [1.0.0] - 2026-06-12

### Added
Expand All @@ -23,7 +27,6 @@ All notable changes to Sheaf are documented here. The format is based on [Keep a

### Fixed

- **Email deliverability no longer permanently locks an account out.** Bounce/complaint handling was a write-once-to-bad flag: a single transient soft bounce (e.g. a greylisting MX deferring the first delivery attempt) flagged the address undeliverable, the matching `delivered` event was ignored, and nothing - not re-verifying, not even changing email - ever cleared it, so all further mail to the account was silently dropped with admin-only recovery. Deliverability is now a recoverable lifecycle: a soft bounce only blocks after `EMAIL_SOFT_BOUNCE_THRESHOLD` (default 5) accumulate without an intervening delivery; a successful-delivery event clears soft state automatically (the SendGrid webhook now consumes `delivered` events - enable Delivered in your event selection); and a flagged user gets a sign-in banner prompting them to re-verify or change their address. Verification emails are now sent even to a blocked address (the recovery channel must reach the user), and completing verification - or changing to a new address - clears the deliverability flags. New `POST /v1/auth/revalidate-email` drives the re-verify recovery. Hard bounces and spam complaints still block immediately and are cleared only by re-verification, never silently undone by a later delivery.
- **Build provenance for local compose builds.** `GET /v1/version` reports the commit/tag/build-time the backend was built from; CI-built ghcr images already set these, but a local `docker compose build` left them null because the compose `args` didn't forward them. The app service now accepts `GIT_COMMIT` / `GIT_TAG` / `BUILD_TIME` from the host environment (documented in SELFHOSTING.md), so a compose build can identify itself too. Unset values stay null, same as before.
- **SimplyPlural importer survives real-world export variants.** SP exports are a decade of MongoDB-into-Firebase sediment, and the shapes tidy test fixtures never produce were failing or silently dropping data on live imports. The importer now handles: collections exported as either an array or a map keyed by id (a map previously crashed the whole job); timestamps as integer/float millis, numeric strings, zone-less ISO strings, or Firebase `{_seconds, _nanoseconds}` objects (the old int-only parser silently skipped or crashed on the rest, dropping entire front histories); the renamed collection keys (`frontStatuses`/`customFronts`, `frontHistory`/`fronters`, system profile under `settings` or `users[0]`); avatars stored as an `avatarUuid` plus owner id (constructed to the serve URL, still policy-gated); and 8-hex ARGB colours. Wrong-typed name/description/colour fields are coerced away instead of crashing, and the import detail page now logs what the export contained alongside what imported so a partial import is diagnosable at a glance. Cross-referenced against the Prism importer's handling of the same quirks.

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "sheaf"
version = "1.0.0"
version = "1.0.1"
description = "Open-source plural system tracking"
license = "AGPL-3.0-or-later"
requires-python = ">=3.12"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "web",
"private": true,
"version": "1.0.0",
"version": "1.0.1",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
Loading