# Kids Calendar A self-hosted weekly calendar for your family. Parents log in and edit; each child gets a read-only "kiosk" link for a tablet, where they can only tick off tasks that are already there. - Parents: sign up, invite your spouse, create a calendar per child, edit freely, print, duplicate a calendar for the next week. - Kids: open their kiosk link on a tablet (add it to the home screen). They can see the board and check boxes — nothing else. - Everything a child checks off shows up on the parents' devices within a few seconds, no reload needed. ## Running it Requires Node.js 22.5+ (for the built-in `node:sqlite` module — nothing else to compile, no native build tools needed). ```bash npm install export SESSION_SECRET=$(node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))") node server.js ``` Plain `node` doesn't read `.env` files — export the variables from `.env.example` yourself (as above), or use a process manager (pm2, systemd) that does it for you. Docker (below) reads `.env` automatically. Then open http://localhost:3007/signup.html. ### Docker (recommended for a NAS / home server) ```bash cp .env.example .env # set SESSION_SECRET docker compose up -d --build ``` Data lives in a named volume (`kids-calendar-data`), so it survives container rebuilds. To back it up, back up that volume (or bind-mount `./data:/app/data` in `docker-compose.yml` instead and back up that folder). **Running on Unraid specifically?** See [UNRAID.md](UNRAID.md) — it uses `docker-compose.unraid.yml`, which bind-mounts to `/mnt/user/appdata/kids-calendar` instead of a named volume, matching Unraid's usual appdata convention. ### Environment variables | Variable | Default | Notes | |---|---|---| | `SESSION_SECRET` | *(insecure dev default)* | Required. A long random string — see `.env.example` for how to generate one. | | `PORT` | `3007` | | | `DATA_DIR` | `./data` | Where the SQLite file lives. | | `COOKIE_SECURE` | `false` | Set `true` once this is behind HTTPS (e.g. a reverse proxy with a real certificate), so cookies are marked secure. Leave `false` for plain-HTTP LAN access, or login cookies won't be sent. | | `DISABLE_PUBLIC_SIGNUP` | `false` | Set `true` once your household(s) exist, to stop the `/signup.html` page from creating new ones. Existing invite links still work. | ## How access works - **Parents** have real accounts (email + password) tied to a household. The first person to sign up creates the household; from the dashboard they can generate an invite link (valid 7 days, one-time use) for a spouse to join the same household with their own login. - **Kids** never get an account. Each child has an unguessable link (`/k/`) that shows only their *active* calendar (set from the dashboard) and lets them toggle checkboxes — the server has no route at all for a kiosk link to edit text, add/delete tasks, or see other children's data. If a tablet is lost, regenerate that child's link from the dashboard to invalidate the old one. ## Exposing this beyond your home network This is built for LAN use by default (plain HTTP, cookies not marked secure). If you want access from outside your home: - Put it behind a reverse proxy (e.g. Caddy, nginx, Traefik) that terminates HTTPS, then set `COOKIE_SECURE=true`. - Set `SESSION_SECRET` to a real random value (never the dev default). - Consider setting `DISABLE_PUBLIC_SIGNUP=true` once your family's household(s) are created.