Project summary · Last updated May 2026 · Current build v6.9 · All modules stable · Direction D visual overhaul complete
A feature-complete family management web app for chores, trades, tokens and rewards. Built entirely in vanilla HTML, CSS and JavaScript — no framework, no build step, no npm dependencies. Google Sheets serves as the database via a Cloudflare Worker proxy. The app is deployed on Cloudflare Pages behind Zero Trust access control, with a separate public-facing documentation site.
Designed initially for a single family as a cost-efficient proof of concept, with an architecture that can evolve to serve multiple families. Built solo over approximately 14 days (est. ~101 hours) with AI assistance throughout design, engineering and testing.
Four distinct layers, each with a clear responsibility. The app HTML never communicates with Google Sheets directly — all data access is mediated by the Cloudflare Worker.
The app's security model evolved significantly during development. The initial version had the Google service account private key embedded in the client HTML — readable by any authenticated user via browser DevTools. A three-tier hardening plan was identified and fully implemented in v6.0–v6.3, resulting in a defence-in-depth architecture where no sensitive credential is ever accessible client-side.
The Zero Trust layer was already in place and provides strong perimeter protection. The three tiers add security within that perimeter.
Content-Security-Policy — restricts resource originsX-Frame-Options: DENY — prevents clickjacking via iframe embeddingX-Content-Type-Options: nosniff — prevents MIME type sniffingReferrer-Policy: no-referrer — prevents URL leakage in referrer headersThe Super Admin role is scoped to platform administration only. A Super Admin can see that a family exists, its name and member count — but cannot access any family content: no chores, no trades, no rewards, no member personal data. This is a deliberate privacy boundary enforced at the application level.
Google Sheets is functional at current scale but is not a production-grade database for multi-family use. The planned D1 migration replaces Sheets with Cloudflare's serverless SQLite, keeping all data within the Cloudflare ecosystem. Because the Worker already mediates all data access, this migration requires no changes to the app HTML — only the Worker's data layer changes.
v6.9 delivered the Direction D visual overhaul — a full CSS rewrite layered over the unchanged HTML and JS. The visual language shifted from clean white/neutral to a warm "Soft Notebook" greige palette with handwritten headings, 3D pill buttons and shadow-based depth. All 42 screens updated with no logic changes.
<style id="dirD-overrides"> block layered after the base CSS. Every existing id, onclick and renderX() function kept working. The app looks brand-new; the engine is identical.border-radius: 999px on all buttons. Primary (peach) carries a 4px bottom shadow + 1px inset highlight. Active state translates 2px down and compresses the shadow, giving genuine tactile press feedback.--sh-tile and --sh-key shadow systems: bottom-edge shadow + inset top highlight. Cards appear to sit slightly above the page surface. Lift effect on hover for interactive tiles.[data-mascot] attributes. Five colour variants (peach, mint, lemon, lilac, sky) and two decoration modes (sparkle, cloud). Appears on login, first-run, PIN change, forgot-PIN and SA recovery screens. MutationObserver handles dynamically injected screens.fh_theme in localStorage. Persists across sessions on the same device. Reads and applies on page load before render to prevent flash.prefers-color-scheme media query checked on first load. If no saved preference exists, the app automatically matches the device OS setting.[data-theme="dark"] attribute on documentElement. Covers all badge variants, action buttons, inputs, select dropdowns, banners, trade cards and reward elements. Components using CSS variables adapt automatically.isDark() used where inline styles (e.g. reward banners) need programmatic colour selection. Keeps dark-mode logic consistent across both CSS and JS-rendered elements.Testing is primarily manual and role-based, supported by a dedicated test environment at test.nyefome.uk backed by a separate Sheets database. Every build is validated across all four roles before promotion to production. The two-environment gate is the primary quality control mechanism.
Given the single-file, no-framework architecture, there is no unit test runner or CI pipeline. Test coverage is behavioural — each feature is validated end-to-end through the UI as a real user would use it. This approach was chosen for speed of iteration during the initial build phase.
Three distinct environments serve different purposes. All three share the same codebase but point to different Sheets databases and API endpoints. Promotion always flows in one direction: test → production. The guide is environment-independent — it covers the app generally and is not tied to a specific build.
These limitations are the result of deliberate early-stage trade-offs — choosing speed of delivery and zero cost over architectural perfection. Each one has a known resolution path. The app works correctly within these constraints at current scale, and the architecture is designed to evolve without requiring a rewrite.
Terms used throughout the app, this document and the user guide.
--bg #DCD8D0 · --paper #F0ECE3), Caveat handwriting headings, DM Sans body, JetBrains Mono labels, 3D pill buttons with press-depth shadows, shadow-based cards (no borders), dashed nav borders, Marshmallow SVG mascot on 5 screens, greige dark mode re-map. All implemented as a CSS-only override block — zero HTML or JS changes, all 42 screens updated. Also: module tile badge fix — Chore Tracker tile on Admin and Parent dashboards now correctly shows mint green "View →" pill (matching Trades, Rewards, Reporting) when zone setup is complete. Previously showed grey "Module 2" badge regardless of state. Parent tile badge now has id="par-mod2-badge" for JS targeting; updateMod2Tile() updated accordingly.localStorage persistence via fh_theme key. System prefers-color-scheme auto-detected on first load. 45 dark-override selectors covering badges, buttons, inputs, banners, trade cards. isDark() helper for JS-rendered inline styles. Version bumped from v6.6.apiCall() function replaces direct sheets.googleapis.com calls. getGToken/importPK removed.Current phase — Trial launch
Near term
Medium term
Completed security roadmap
Completed UI roadmap
Key data model notes
Open backlog
Resolved backlog
Reference files