Turn everyday learning into visible growth.
A family learning check-in PWA for learning, records, and sync in one place.
v1.3.12 · MIT License · Vite + Vanilla JavaScript + Supabase
简体中文 · Open Shadow Mate · User guide · Release notes
Shadow Mate is designed around a family's daily learning routine: what was learned today, which tasks were completed, and how consistently the habit is growing.
The screenshots use local demo data and contain no real family information.
- Four learning modules: Chinese, mathematics, English, and picture books; tasks can be checked in or cancelled independently.
- Growth records: completion is summarized by learning module over the last 30 days, with daily progress shown as
completed/4. - Points calendar: behavior points are recorded separately from learning modules and can be reviewed or backfilled by date.
- Family space: one parent manages multiple learners, with records loaded for the active learner.
- Shared account sign-in: email verification and shared email-password authentication for Shadow products.
- Duplicate-action protection: rapid repeated submissions, syncs, deletions, and check-ins are guarded against duplicate changes.
- Offline-first: learning, check-ins, points, and picture-book records work locally before sign-in; cloud sync is optional after sign-in.
- Cross-device recovery: optimistic versioning and conflict protection reduce accidental overwrites across devices.
The growth calendar counts each learning module once per day. For example, Chinese character practice, poetry, and writing are separate tasks but count as one Chinese module; picture books are the fourth module. A 4/4 day means all four learning modules were completed.
The points calendar distinguishes no points, positive points, negative points, and mixed activity on the same date. It does not change the four-module growth calendar.
| Page | Measures | Date states |
|---|---|---|
| Home | Learning modules completed today | completed/4 |
| Growth | Learning-module completion over the last 30 days | 0/4 to 4/4; yellow border marks today |
| Points | Behavior-point records for the current month | none, positive, negative, or mixed; yellow border marks the selected date |
npm ci
npm run devOpen the local URL printed by Vite. Do not open index.html directly with file://; browser modules require the development server.
The local privacy page is available at http://localhost:5173/privacy. It is served by the same Vite development server as the main application.
npm run check
npm run build
npm run test:fast
npm run test:uiFor database-backed checks, start Docker Desktop first:
npm run local-dev
npm run local-dev -- plan --projects shadow-mate --jsonThe canonical local entry coordinates shared Supabase, Mailpit, database tests, and Edge Functions. It reuses healthy resources with matching identity and only starts missing resources:
npm run local-devThe shared local Supabase API is local-only and Mailpit is available at http://127.0.0.1:54324. A feature worktree that starts Vite directly does not automatically start Mailpit or switch to local Supabase; configure its loopback Supabase URL and publishable key explicitly.
Non-production and Preview sources must not connect to production Supabase. Remote production access is blocked unless an explicitly authorized temporary verification override is provided. Never put production credentials or service-role keys in this repository.
Compatibility wrappers remain available when only the split entry points are needed:
npm run supabase:local:start
npm run supabase:local:functions:serveDo not run a bare supabase start in the repository root as a replacement for the shared local entry.
For local database linting:
cd ../shadow-size/merchant-admin
npx supabase db lint --local --schema public --level warning --fail-on errorChoose the smallest sufficient validation scope for ordinary changes. Run npm run test:full before merging or releasing.
Browser-local state
│
├─ Signed out: offline learning, check-ins, points, and picture books
│
└─ Family sign-in
│
├─ Learner-scoped records
├─ Versioned multi-device sync
└─ RLS and product-boundary protection
- Local learning state is stored in browser storage and scoped to the active learner.
- Cloud state is stored as versioned JSON snapshots. Network failure must not destroy local state.
- If a learner switch cannot confirm the complete active scope, the application fails closed and pauses local and cloud writes. The protection survives refreshes until a parent explicitly clears local data.
- Clearing local data keeps fail-closed protection until both local storage and Growth Loop IndexedDB have been cleared successfully.
- Deleting a family removes Shadow Mate's associated family data without deleting the shared Auth identity.
- Full identity deletion is enabled only in an isolated Supabase project with an explicitly authorized server-side flow.
src/app.js UI rendering, interaction, and local state
src/learning-state.js Learning state machine and module grouping
src/cloud.js Authentication, family space, sync, export, and deletion
src/action-lock.js Duplicate-action and async-operation guards
src/icons.js Lucide icon rendering and hydration
supabase/migrations/ Migration proposals and isolated CI test copies
supabase/functions/ Account-level server functions
tests/unit/ Pure-function and state-machine tests
tests/e2e/ Offline, cloud, and data-lifecycle tests
The browser uses only a publishable Supabase key. Data isolation is enforced by Supabase RLS, household membership, and product identity. Never expose a secret or service-role key in browser code.
This repository contains migration proposals and isolated CI test copies. Production migrations are managed by the Shadow Portal control plane. Do not run production db push, migration repair, --include-all, linked SQL, or manual schema_migrations edits from this repository.
The local Supabase profile and migration sources are checked by the shared local-development contract. This local contract does not grant production migration permissions.
Shadow Mate is an open-source family learning PWA. It has no advertising and no independent child accounts. Anonymous, aggregated page-visit data may be collected through Vercel Web Analytics. See Privacy for data scope and deletion behavior, and Security for private vulnerability reports.
“Listen” prefers an English system voice when one is available. Devices without a usable English system voice, especially Android devices without GMS, use local Piper in the browser. The first use downloads and caches the en_US-ljspeech-medium model from voice.shadow.wang; after that, synthesis works offline. The system TTS path may depend on the device and browser, and Shadow Mate does not collect microphone recordings.
The speech fallback uses these open-source projects:
- piper-tts-web (MIT): browser Piper engine wrapper
- rhasspy/piper (MIT): lightweight neural speech synthesis
- ONNX Runtime Web (MIT): browser inference runtime
- rhasspy/piper-voices: the
en_US-ljspeech-mediumvoice model distributed throughvoice.shadow.wang
See THIRD_PARTY_NOTICES.md for source, version, and license details.
| Document | Purpose |
|---|---|
| Chinese README | Complete Chinese product and development guide |
| User guide | Sign-in, family space, check-ins, sync, speech, and installation |
| Logo usage | Adopted Shadow Mate Logo usage |
| Release notes | English user-facing changes |
| Chinese release notes | Chinese user-facing changes |
| Release Notes template | Authoring rules and structure |
| Third-party notices | Included libraries and assets |
| Privacy · Security | Data and responsible disclosure policies |
I share product and AI-building work across several channels:
- X: @Gollumgulu
- WeChat Official Account: Ward 的 AI 产品实战
- Xiaohongshu / Weibo / Douyin: Ward 的 AI 产品实战 — Xiaohongshu · Weibo · Douyin
- Product site: Shadow Nexus
- Email: wardlu@126.com
The code is released under the MIT License. Third-party content, models, and trademarks remain the property of their respective owners.


