Release Notes

The story of Zam!, one commit at a time.

Features
Security
UI/UX
Performance
Fixes
Show Lite
Expand All
v1.0 - "The Foundation + Cloud Sync"
May 31, 2026 launch; June 10-12, 2026 beta hardening

Zam! is in live beta. The goal now is honest validation: is the product useful enough to keep entering budgets, stable enough to trust with real data, and valuable enough that Premium support can at least cover infrastructure and continued development time?

Live Beta Honesty Report
Settings modal redesigned as a dashboard
App Settings now groups defaults, budget rules, appearance, data/privacy tools, and local erase actions into clearer cards with segmented controls, a local-only danger zone, and a sticky Save/Cancel footer that only shows an unsaved-changes notice after edits.
Public search indexing enabled
The marketing site now publishes indexable Zam metadata, extensionless canonical URLs, Open Graph and Twitter previews, structured data, a populated sitemap, robots.txt sitemap discovery, and a positive SEO audit while the app domain remains noindex.
Marketing rebrand preview started
The public website now uses the Zam! name, a temporary Z! mark, Cloud Sync terminology, and zambudget.com public contact addresses while preserving app behavior during the rebrand.
Cloud Sync naming restored
The sync feature now uses the plain Cloud Sync label across public website copy instead of the temporary product-branded sync name.
App login page rebranded
The app login page now shows Zam! in the page title, logo text, sign-in and signup messages, account-deleted confirmation, and footer while auth behavior stays unchanged.
App footer and support routing synced
The app shell and standalone app pages now use Help Center, Guides, and Contact Us links, hide unready social channels, and remove repository-posture copy from compact footer areas.
Cloudflare Worker target renamed
The marketing Wrangler config and GitLab deploy guardrails now target zambudget-website so the website Worker name matches the Zam deployment.
GitLab naming aligned
GitLab-facing app and website metadata now use zambudget-app and zambudget-website naming so the rebrand is clearer before the project paths are renamed in GitLab.
Website domain cutover started
The website Worker now attaches zambudget.com and www.zambudget.com directly. Legacy marketing custom domains were removed so the website no longer serves from the old brand domain.
App links moved to app.zambudget.com
Header buttons, footer launch links, signup CTAs, demo links, Premium entry points, and support guides now point to the Zam app domain.
Main app rebrand completed
The signed-in app shell, static app pages, safety dialogs, Cloud Sync recovery copy, Premium billing copy, export filenames, diagnostic reports, privacy, terms, support, and account-deletion language now use Zam! branding while legacy storage keys, Supabase table names, and compatibility identifiers remain unchanged.
Homepage comparison reframed
The homepage now answers why someone would choose Zam! with planning-focused switching guidance for users coming from premium finance platforms or simpler budgeting apps, without direct app-versus-app superiority claims.
Comparison table labels clarified
The homepage comparison tables now use Zam! Budget App as the product column label so first-time visitors and search engines get clearer product context.
Homepage comparison switch added
The switching comparison now uses two buttons, Big guys and Other guys, so visitors can view either the premium-platform table or the simple-app table without seeing both at once.
Homepage FAQ tightened
The FAQ now keeps the eight core who/what/when/where/why/free/privacy/update questions, uses one-sentence answers, and presents as a two-column accordion on desktop that stacks on mobile.
Accessibility Statement expanded
The Accessibility page now explains Zam!'s WCAG baseline, practical WCAG 2.2 review direction, supported accessibility practices, review checks, beta limitations, issue-reporting details, and last-reviewed date without claiming a formal audit.
Public GitLab readiness tightened
The marketing/docs repo now has a README, security contact guidance, MIT license notice, and public-readiness checklist. Internal support notes and the old theme-reference artifact were removed or converted to public-safe documentation, and public GitLab routing stays labeled as coming soon until source posture changes.
Premium value copy clarified
The Premium section now says core budgeting is free and explains that Premium helps fund sync, shared budgeting, reports, planning tools, support, and continued development without relying on ads, trackers, or selling budget data.
Planning-focused comparison refined
The homepage comparison now uses Premium Platforms and Simple Apps labels, adds forecasting to the premium-platform table, and avoids shared-budgeting claims until that capability is actually shipped.
Public contact and channel routing refined
The website now publishes dedicated support, billing, legal, and accessibility mailboxes plus the Zam! mail-only office address. Dev-test remains internal, social email and TikTok are not public routes, LinkedIn points to Andrew Struck, and the GitLab coming-soon link opens the closed app repository page. Sign-in and magic-link questions route through Support because the auth email is a no-reply/system address.
Source-code posture narrowed
The public website and docs can remain visible for trust and transparency, while the Zam! app, backend, Cloud Sync architecture, and infrastructure configuration stay private during beta.
Homepage footer simplified
The homepage footer now keeps Product, Support & Legal, and Contact as the main link columns, alphabetizes Product and Support & Legal links, uses SVG icon links for support email, LinkedIn, and GitLab under Contact Us, and keeps the one-line Zam! copyright and MIT License notice under the icons.
Support information architecture split
The oversized Support article is now divided into Help Center, Guides, Trust & Privacy Stack, and Contact Us. The public contact page stays focused on visitor-facing mailboxes and keeps dev-test/internal routing off the site.
Partnerships and cookie-policy pages filled in
The marketing footer now links to a real Partnerships page, the Cookie Policy explains browser storage and provider-session behavior, and Billing/Legal contacts live in a dedicated Support section instead of cluttering the legal footer.
Proton Mail email-provider disclosure added
The Trust & Privacy Stack now names Proton Mail as the public mailbox provider, links back to Proton's official pages for brand transparency, and reminds users to review diagnostics and keep recovery keys, magic links, passwords, card numbers, gift card numbers, PINs, and raw budget exports out of email.
Social mailbox route paused
The Contact Us page no longer publishes the social mailbox or TikTok placeholder. Public collaboration now routes through support or Andrew's public LinkedIn profile until dedicated launch channels are ready.
Beta testing is open and intentionally honest
Zam! is being tested with real budgets, real sign-ins, real Cloud Sync recovery, and real billing paths. Feedback matters now because the next decision is practical: keep developing if users find it useful enough and it can at least pay for its infrastructure, or scrap it if the time-to-value and support load do not make sense.
Gift-card payment method and balance tracker added
The app Add flow now includes Gift Card as a payment method. Users can save a gift-card number, total amount, current balance, and expiration date, then Zam! subtracts tracked gift-card expenses and previews the remaining balance before save.
Local-only gift-card merchant metadata cache added
Gift-card merchant hints now download as one full static bundle, cache locally, and search on-device so merchant search terms and suggestion selections are not sent to a server.
Gift-card removal added
Saved gift cards can now be removed from the Add More gift-card tracker without changing the core Expense and Deposit controls.
Live data-loss scare turned into Cloud Sync recovery hardening
Beta testing exposed a serious edge case where secure sign-out could clear local data and a fresh sign-in could land on a blank budget while the usable copy lived in Version History. Cloud Sync now treats blank local sign-ins as cloud-priority recovery, preserves a secure-sign-out recovery marker, and can recover the newest non-empty encrypted saved version when needed.
Trusted Cloud Sync browser key added
After a successful setup or recovery-key import, Zam! can store a non-extractable WebCrypto key in IndexedDB so the same browser can keep syncing after refresh without storing the raw recovery key in localStorage. The trusted key stays local to the browser, is not part of Account > Devices records, and cannot be displayed as the recovery-key text.
Data safety moved ahead of feature expansion
Auth, billing, Cloud Sync, secure sign-out, rough logout, conflict review, and recovery-key handling are now treated as production-critical work. New feature work is intentionally secondary until these paths keep passing real beta use.
Provider metadata legal copy clarified
The legal pages now plainly distinguish Zam-controlled privacy-minimal records from infrastructure, authentication, email, payment, and security-provider metadata. The disclosure now covers IP-related logs, approximate country or region metadata, user agent/browser hints, request metadata, OAuth provider metadata, delivery logs, billing records, retention limits, lawful requests, and the fact that encrypted Cloud Sync contents remain unreadable without the recovery key.
GitLab and Cloudflare deployment path stabilized
The project moved into GitLab with Cloudflare pulling from the main branch for deploys. This gives beta fixes a repeatable path from local patch, to commit, to push, to live Cloudflare deployment.
Calendar, category, savings, debt, and recent-flow polish continued
The calendar now supports the budget workflow without interrupting it. Categories gained ordering controls, savings and debt surfaces were tightened, and transaction slide actions were adjusted so destructive actions require clearer intent.
Premium support is framed as project sustainability
Premium is not being positioned as hype. The beta question is whether Zam! is good enough that users want to help fund reliability, billing, Cloud Sync, and infrastructure. If it cannot pay for itself, development may stop instead of growing into an unsupported product.
Premium moved to direct subscription pricing
Premium pricing is now presented as a direct $3.99/month subscription. Core budgeting and two active Cloud Sync slots remain free, while Premium is for users who want unlimited active sync slots, expanded encrypted version history, and to support continued development.
v1.0 Production Report
Cloud Sync moved into v1 production prep
Cloud Sync is now the core free backup and sync path for Zam! It supports encrypted cloud vault upload/download, conflict handling, recovery-key import, and a reset path for users who lose the recovery key and need to start their cloud vault over.
Multi-Device Sync Plus added to Cloud Sync
Free Tier now supports two active synced browsers/devices at a time. Premium unlocks unlimited Cloud Sync slots. The app uses privacy-minimal sync slot hashes and timestamps for the Free limit, without storing device names, user agents, IP-derived locations, or readable budget data.
Cloud Version History added to Cloud Sync
Cloud Sync now keeps encrypted vault snapshots so users can restore an earlier saved budget version, such as a previous day. Free accounts keep the newest encrypted safety snapshot, while Premium keeps the newest 10 encrypted snapshots. Snapshots are encrypted client-side with the same recovery-key model before storage, and restoring a snapshot happens locally before uploading the restored encrypted vault as current.
Zero-readable-budget cloud architecture
Budget contents are encrypted in the browser before sync using AES-GCM. Transactions, balances, budgets, categories, descriptions, notes, and amounts are inside the encrypted vault payload. The server keeps only operational metadata needed for sync, such as timestamps, schema/encryption version, and checksum.
Recovery key safety model
First-time Cloud Sync setup now starts a 72-hour recovery-key grace period instead of blocking onboarding. Recovery-key reveal now requires a short login-verification guardrail when Supabase supports it, falls back to local unlock when needed, auto-locks after 5 minutes or tab hide, and still enforces key safety before risky actions such as clearing the browser, signing out all devices, or resetting Cloud Sync. PIN/passkey-protected local key storage is marked as a top v1.1 priority.
Priority Recovery Tools
Added guided Cloud Sync Recovery Help with human-readable sync status, recovery-key checks, version-conflict guidance, device-limit guidance, diagnostic export routing, and safe reset direction. Zam! still cannot recover or decrypt a lost recovery key, but the app now gives users clearer next steps before they panic or reset unnecessarily.
Reset Cloud Sync replaces destructive account deletion
The lost-key recovery path now deletes the encrypted Cloud Sync vault and encrypted version-history snapshots for the signed-in account, keeps the Supabase login intact, clears this browser, and lets the user create a fresh vault with a new recovery key. Full auth-user deletion was removed from the normal reset flow after Supabase returned database-level delete errors, and normal Cloud Sync reset no longer depends on billing-profile reads.
Live beta billing guard added
Premium billing now has an explicit config switch. For beta, billingEnabled is false, so Upgrade and billing-portal actions stay visible but cannot redirect to Stripe until checkout, webhooks, portal management, and cancellation paths are intentionally verified for live billing.
Account Management redesign
The account menu now has a left-aligned identity header, local avatar fallback, welcome message, Free Tier/Premium badge, time-of-day greeting, two-row action grid, Devices, Settings, Support, and OAuth-aware password reset visibility.
Time-of-day account greeting
Added a small right-side account badge with Coffee budgeter, Midday money, or Night budgeter based on local browser time. The night state includes a moon icon, glow, and subtle looping starfield animation. The morning Coffee budgeter state now has matching motion with a warm glow, drifting light dots, and a subtle animated coffee icon.
Opt-in local diagnostics
Diagnostics moved into Account Settings and now require explicit confirmation before generating a local JSON report. The report is not uploaded automatically, does not opt users into tracking or future diagnostics, and excludes budget contents, transactions, balances, budgets, categories, descriptions, notes, amounts, recovery keys, access tokens, email, and transaction counts.
Device and session controls simplified
Devices is now focused on session risk and sign-out behavior. Known Zam! browsers are listed using privacy-minimal browser hashes, existing sync slot hash links, and timestamps, with browser-icon rows, right-aligned individual sign-out controls, and a separate full-width Sign Out All Devices action. Logout, revoked-browser cleanup, Cloud Sync reset, and Sign Out All Devices now show a Clearing Session screen while local storage, session storage, accessible cookies, and stale page state are cleared before refresh. Manual upload/download controls only appear when Cloud Sync detects competing changes on another device.
Account management modal flow polished
Cloud Sync account-management dialogs now transition smoothly between Devices, Privacy Details, sign-out confirmations, and Back actions. Device sign-out rows give immediate visual feedback, confirmation screens return users to the Devices list instead of dead-ending the flow, and reduced-motion preferences are respected.
Cloud Sync slot cleanup
Free Tier capacity now shows as sync slots instead of devices, and Account > Devices can map known browser access records to the existing opaque Cloud Sync slot hashes that already enforce the Free limit. Free sync slots now behave like active browser leases: if a browser does not check in for 60 minutes, the slot can be released automatically. The cleanup does not add device names, user agents, IP-derived locations, recovery keys, or readable budget data.
Privacy and legal review notes added
Privacy copy and production notes now distinguish encrypted budget contents from operational metadata. The checklist flags legal review for account/auth records, sync timestamps, schema/encryption version, checksums, billing records, and lawful-provider request language.
OAuth password reset gating
OAuth-only users no longer see the Password tile in Account Management. The reset handler is also guarded directly, so password reset cannot be triggered for accounts that do not have a Supabase email/password identity.
Support page and footer-page headers finalized
Added a dedicated Support page, wired Account Management Support to it, removed broken or disabled public footer actions, and tightened footer-linked page headers so they expose only theme controls, live signed-in status, and a styled Back to App button. Static page headers now inherit the saved theme and accent color from the main app, and footer-linked pages no longer carry the Settings control. The support path points users toward Recovery Help, Devices, Version History, Diagnostics, and the beta support email without asking for recovery keys.
New Features
Deep Drill-Down Views
Click any category to see budget vs. actual spending, inline budget editing (just click the "Budgeted" row), quick emoji shortcuts for fast entry, and a full transaction history - all without leaving the screen.
3-Way Theme Engine
Light, Dark, or follow your OS. The toggle lives in the header and your preference persists across sessions. System preference changes are detected in real-time.
Income Breakdown Panel
A dedicated section that shows where your money comes from - each income source, its total, and its percentage of overall income. Updates instantly as you add transactions.
10 Quick-Add Categories
Housing, Food & Dining, Transportation, Entertainment, Subscriptions, Shopping, Health, Education, Savings, and Debt - all one tap away with preset icons.
Security & Auth
Supabase Authentication
Full email/password auth powered by Supabase. Sessions persist across tabs and browser restarts. Unauthorized users are redirected to the login page - no ghost sessions.
Password Recovery Flow
"Forgot Password?" link on the login page triggers a Supabase email with a secure reset link. Users land on a dedicated reset page to choose a new password. Minimum 6 characters enforced.
Clean Logout & Redirect
Logging out destroys the Supabase session server-side and redirects to login. No stale tokens, no "ghost" logged-in state if someone hits the back button.
UI/UX Polish
Avatar Dropdown Menu
Replaced the clunky "Log In / Sign Up" text links with a single, color-coded avatar circle. Click it to reveal your display name, email, profile editor, and logout - all in a smooth, animated dropdown.
Editable Display Name
Click "Profile" in the avatar dropdown to set a custom display name. Stored in Supabase user_metadata so it syncs across devices. Your avatar initial updates instantly.
Mobile-First Responsive Layout
The dashboard grid collapses cleanly on phones. Quick-add categories reflow to 3 columns. Transaction list is scrollable. Drill-down modal goes full-width. No horizontal scrolling - ever.
Rainbow Accent Bar
That thin gradient strip at the top of the page? It's a 4px tall status symbol. Purple -> Green -> Blue. Subtle, but it ties the whole design together.
Performance
Zero-Dependency Rendering
No React, no Vue, no virtual DOM. Pure vanilla JS with direct DOM manipulation. The result? Sub-50ms renders for hundreds of transactions. The app weighs in at a single HTML file.
Instant Local Persistence
In the original browser-only build, every transaction and category was saved to localStorage immediately. The current signed-in beta uses Cloud Sync as the encrypted recovery path.
Precision Fixes
Fixed: Layout Shift on Browser Back Gesture
When navigating back from the login page using a trackpad swipe or Alt+Left, the browser would restore the page from bfcache with stale layout calculations - causing the entire UI to shift off-center. Fixed by adding a pageshow event listener that detects bfcache restoration and forces a full layout recalculation via display: none -> reflow -> display: ''. Also set scrollRestoration = 'manual' to prevent scroll position conflicts.
Fixed: Custom Categories Missing from Dropdown
The transaction form's category <select> only showed the 12 built-in options. Custom categories were being added to the array but never re-rendered into the dropdown. Fixed by calling updateCategoryDropdown() after every category creation and deletion, and preserving the previously selected value across re-renders.
Fixed: Duplicate Category Creation
Clicking a quick-add button twice would create two identical categories. Fixed by adding a case-insensitive duplicate check (name.toLowerCase()) before pushing to the array. Now shows a toast: "Category already exists!"
Fixed: Delete Category Left Orphan Transactions
Deleting a category removed it from the list but left its transactions floating in the ledger with no matching category. Fixed by filtering out transactions that belong to the deleted category before removing it. The confirmation dialog now tells you exactly how many transactions will be removed.
Fixed: Auth State Ignored on Dashboard Load
The login page set the Supabase session correctly, but the main dashboard had zero Supabase code - it never checked if you were actually logged in. The header always showed "Log In / Sign Up" regardless. Fixed by adding initSupabase() to the DOMContentLoaded handler, which calls sb.auth.getSession() and conditionally renders the avatar or sign-in link.
Fixed: Password Field Cleared on Failed Login
If you typoed your password, the login form cleared both the email and password fields - annoying if you have a long email. Fixed by only clearing the password field on error, keeping the email intact for a retry.