RustBox 0.2.8 release manifest 0.2.8 feature/configuration changes: - fixes folder unread counts by treating IMAP STATUS UNSEEN as authoritative and never using SELECT/EXAMINE UNSEEN as a count - falls back to UID SEARCH UNSEEN when STATUS is unavailable for the selected mailbox - reconciles MESSAGES/UNSEEN even when HIGHESTMODSEQ is unchanged and rejects out-of-order stale counter writes with compare-and-set/retry - updates individual message rows and folder counters optimistically/live for read/unread/flag events instead of rebuilding the message list, then reconciles them to authoritative IMAP state - shows wide folder badges as total / unread, hides the unread suffix at zero, and switches to compact counters in narrow sidebars - exposes IMAP header-cache and deep-index backlog through the activity indicator and tooltip - keeps counter STATUS separate from the CONDSTORE cursor, falls back to full UID/FLAGS reconciliation when needed, and refuses to apply partial IMAP streams - keeps security_headers_enabled opt-in, centralizes the RustBox-added browser security profile behind that switch, and applies the full document-only profile only to HTML/XHTML - uses external same-origin JavaScript with `script-src 'self'`, disables inline script attributes, restricts stylesheets to `style-src 'self'`, and permits only dynamic style attributes via `style-src-attr 'unsafe-inline'` - applies no-store, nosniff, same-origin CORP and an anti-framing `frame-ancestors 'none'`/X-Frame-Options policy to private API responses; the full document CSP plus Permissions-Policy/COOP remain HTML-only, and assets receive same-origin CORP where applicable - leaves HSTS to the HTTPS/TLS-terminating deployment layer - minimizes the public auth policy to rememberMeEnabled and moves optional feature availability behind authenticated /api/auth/session-policy - adds/extends regression coverage and offline release checks for the changed behavior - adds runtime migration V048 on SQLite/MySQL/PostgreSQL for monotonic folder-counter generations; V049 remains next Architecture: - database_backend = sqlite | mysql | pgsql selects authoritative SQL only - blob storage and search are independent from the SQL engine - PostgreSQL/MySQL single-node deployments may continue to use data_dir-backed filesystem/Tantivy - cluster mode clears an implicit/default data_dir; explicit data_dir is not forbidden, but local-only capabilities are rejected Blob storage: - filesystem: local single-node or shared POSIX with storage.shared=true - shared POSIX examples: NFS, CephFS, GlusterFS - s3: AWS S3 and S3-compatible endpoints such as MinIO/Ceph RGW - attachment rows use logical storage keys and SHA-256 metadata - storage migration command: rustbox storage migrate --from filesystem:/path --to configured [--dry-run] [--verify] Search: - local_tantivy: single-node only - opensearch: cluster-capable external index - disabled: no full-text index - OpenSearch operations are tenant-scoped by user_hash - durable SQL outbox provides claim/lease, retry/backoff and dead-letter handling - rebuild command: rustbox search reindex Database/schema: - migrations/{sqlite,mysql,pgsql}/schema.sql contain the current fresh schema - compatibility baseline remains V046 - runtime migration V047 adds attachment checksum metadata and search_outbox - runtime migration V048 adds `folders.counter_generation` for race-safe authoritative IMAP counter writes - next migration number: V049 Docker examples: - docker/compose-single-sqlite.yml - docker/compose-ha-garage.yml (2x RustBox + Envoy + Valkey + PostgreSQL + OpenSearch + Garage S3) - docker/compose-postgres-s3-opensearch.yml (PostgreSQL + SILO/S3 + OpenSearch) - docker/compose-mysql-nfs-opensearch.yml (MySQL + real NFS volume + OpenSearch) Operations/docs: - README.md documents 0.2.8 configuration - docker/README.md documents Compose variants - docs/STORAGE_SEARCH_OPERATIONS.md documents failure modes, shared-storage requirements and migration behavior - TODO.md leaves live SILO/MinIO/AWS/Ceph and real multi-node acceptance validation explicitly pending Build/release metadata: - `scripts/package-release.sh` runs the full Rust release gate before creating ZIP/SHA256 artifacts - Cargo.toml version = 0.2.8 - rust-toolchain.toml pins Rust 1.99.1 - Cargo.lock is retained for reproducible application builds; the release gate generates it only when missing - CI and scripts/build-release.sh use the retained Cargo.lock (generating it only if missing), then run locked tests/Clippy/release build