A family task schedule that syncs peer-to-peer between your devices β no servers, no cloud, no third-party services.
π App: https://alihkhawaher.github.io/task-schedule/
π¦ Source Code: https://github.com/Alihkhawaher/task-schedule
- Devices connect directly via WebRTC (Trystero + Nostr for signaling)
- All data stored in browser localStorage β you own everything
- Sync happens between your devices only β nothing leaves your network
- No CDN, no external dependencies β everything bundled locally, works fully offline
- Installable PWA β works on phones, tablets, and desktops
- Runs from GitHub Pages β no server, no build step, no deployment needed
Zero telemetry. Zero analytics. Zero tracking. Your data never leaves your devices.
- Standalone β No external service dependencies. All libraries bundled locally. Works offline.
- Data is everything β Multiple persistence layers (memory, localStorage, P2P sync). Data survives everything.
- P2P is core β Devices connect directly via WebRTC (Trystero). No cloud, no servers, no middleman.
- User control β No telemetry, no tracking. You own your data, your devices, your network.
Uses Trystero library for WebRTC peer-to-peer connections via Nostr network signaling:
- Nostr relays are used only for peer discovery (signaling)
- Actual data flows directly between devices via WebRTC (encrypted)
- Both devices must be online simultaneously for connection
- Once connected, data syncs in real-time
- Existing device β click "Ω Ψ΄Ψ§Ψ±ΩΨ© Ψ§ΩΨ¬ΩΨ§Ψ²" (Share Device) β copy link or show QR
- New device β open link β auto-fills family code
- New device logs in β admin approves β P2P connects
- Family data syncs automatically
- Both devices on the same WiFi (or internet for cross-network)
- Both devices must have the app open at the same time for initial connection
- π Calendar view β month and week (7-day) views with color-coded user avatars
- π€ User dashboard β tap any avatar to see per-task progress bars and overall completion
- π Per-user tasks β each task is assigned to one user with start/end dates and weekday schedule
- π Day detail panel β tap a day to see all users' tasks with checkboxes
- π¨βπ©βπ§βπ¦ Multi-family support β each family has isolated data
- π P2P mesh sync via Trystero/WebRTC β no server needed
- π PIN-based check-in with configurable grace period
- π Start date β schedule begins from your chosen date
- πΎ localStorage backup β data persists locally
- π· QR code + share link device discovery
- π± Device naming β name each device (e.g., "ΩΨ§ΨͺΩ Ψ§ΩΨ£Ψ¨") visible to other peers
- π Runs on GitHub Pages β no server or deployment needed, just open the link
- π¦ Complete package β no CDN, all libraries, fonts, and icons bundled locally
Open https://alihkhawaher.github.io/task-schedule/ in your browser.
Enter family name + your name + PIN β get family code + recovery code.
Click "Ω Ψ΄Ψ§Ψ±ΩΨ© Ψ§ΩΨ¬ΩΨ§Ψ²" β share the link or QR code with family members.
Open shared link β family code auto-fills β enter name + PIN β admin approves β start using.
| Layer | What | Survives |
|---|---|---|
| In-memory | JS objects | Current session |
| localStorage | Browser storage | Logout, refresh, restart |
| P2P peers | Other devices' storage | Device offline |
| Action | Always asks? | Grace period |
|---|---|---|
| Enter settings | β Yes | No |
| Settings actions | No | Yes (refreshes) |
| Data reset | β Yes | No |
βββ index.html # Login page (Create Family + Connection)
βββ manifest.json # PWA manifest
βββ README.md # This file
βββ app-design.md # Comprehensive design document
βββ mockup/
β βββ calendar.html # Calendar view mockup
βββ app/
βββ index.html # Main app (calendar + settings overlay)
βββ app.js # Core logic (calendar, P2P broadcast, task check-in)
βββ config.js # Settings logic (users, per-user tasks, PIN, device name)
βββ p2p.js # Trystero/WebRTC P2P module
βββ styles.css # Styles (calendar, avatars, panels, RTL)
βββ icons/ # SVG icons for PWA manifest
βββ libs/ # All dependencies (bundled locally)
| Component | Technology | Purpose |
|---|---|---|
| P2P | Trystero (Nostr + WebRTC) | Direct browser-to-browser sync |
| Database | Gun.js (local only) | Local data structure |
| Auth | Web Crypto API (SHA-256) | PIN hashing |
| UI | Bootstrap 5 + Tajawal | Arabic-first responsive design |
| QR | qrcode.js | Device discovery |
| PWA | Web App Manifest | Installable on mobile and desktop |
| Hosting | GitHub Pages | Free static hosting, no server needed |
The app implements a three-layer security model designed for a family P2P app where all approved members are trusted.
When a family is created, a cryptographically random room ID (32 bytes, hex-encoded) is generated using crypto.getRandomValues(). This room ID is used as the Trystero/WebRTC room name β not the human-readable family code. Nostr relay operators see only a random hex string.
When a new device joins the Trystero room, it does NOT receive any family data automatically. Instead:
New Device Admin Device
β β
βββ Joins room (via room ID) βββββββββ€
βββ Sends "join-request" βββββββββββββ
β βββ Shows approval dialog
β βββ Admin taps [Approve] or [Reject]
ββββ Receives approval + data βββββββββ€
βββ Shows login form β
- No data is sent until admin explicitly approves the new device
- The approval dialog shows the requesting device's name
- Admin can reject unknown devices
Once approved, a device receives a cryptographically random approval token (32 bytes). This token enables seamless reconnection without re-approval:
| Storage | What | Purpose |
|---|---|---|
| Approved device | Raw token (localStorage) | Present on next connection |
| Admin device | SHA-256 hash of token | Verify without storing raw token |
Reconnection flow:
- Previously approved device joins room β sends
join-requestwith stored token - Admin device receives β computes SHA-256 of incoming token β checks against stored hashes
- Match found β auto-approves (no dialog) β sends family data
- No match β shows approval dialog (new/unknown device)
Revocation: Admin can remove any approved device from Settings β Connected Devices. The device will need re-approval on next connection.
| Attack Vector | Protection | Layer |
|---|---|---|
| Relay operator sees family code | Random room ID replaces family code | Layer 1 |
| Anyone with share link gets data | Admin must approve before data is sent | Layer 2 |
| Approved device reconnects | Token-based auto-approval (no dialog) | Layer 3 |
| Stolen share link | Still needs admin approval | Layer 2 |
| Device lost/stolen | Admin revokes token | Layer 3 |
PINs are used for UI-level identity verification within the app (not as a cryptographic gate):
- SHA-256 hash with fixed salt (
task-schedule-salt) - 4-6 digit numeric PINs
- Grace period: after entering PIN, won't be asked again for configurable duration
- Settings entry: always requires PIN (no grace period)
- Data reset: always requires PIN (no grace period)
Data is stored in plain JSON in localStorage. This is acceptable for a family app because:
- Each family member has physical access to their own device
- Browser isolation prevents cross-origin access
- No cloud backup means no server-side data breach risk
- WebRTC DTLS: All peer-to-peer data is encrypted in transit by WebRTC
- Nostr relays: Used only for signaling (peer discovery), not data transfer
- No CDN, no server: All dependencies bundled locally, zero external calls
- Both devices must be online simultaneously for initial P2P connection
- Nostr relay servers used for signaling only (some may be temporarily down)
- Data is device-local β no cloud backup
- If localStorage is cleared, device needs a new share link to rejoin
- PWA background sync limited by browser policies
MIT