calendar
All repositories: gitoria
10.6 KB
# calendar.worldapi.orgThe creator's calendar (CONCEPT.md), in Hybriel on hl:web. The month view at `/` — prev / next buttons on top, month nameand year between them, today marked, weeks start on Monday, names in the browser's language — and, since ticket #2,**login with ident and private events**. https://calendar.worldapi.org## Use- Signed out: the month view and "Log in with ident" (top right; the identity selector or the button).- Signed in: click a day to add an event, click an event to edit or delete it. An event has a title, "At a time" (from /to, date and time) or "All day" (from / to, dates), a place and notes. It shows on every day it covers (a day shows fourchips, the fourth says "+N more"). Only the owner sees, changes or deletes an event.- Events are stored as **WorldAPI Events** (https://worldapi.org/standards/event): `$type $version $kind $title$description $start $end $timezone $location $status $visibility $created $updated` plus `owner` (users `@id`). Timedevents: local wall-clock `$start`/`$end` + `$timezone` (the browser's); all-day: `$kind = 'allday'`, date `$start`, exclusivedate `$end` (left out for one day); `$created`/`$updated` are UTC instants; `$visibility` is always `private`.- **Short ids (ident#23, antcolony mission 039)**: `users.identity` holds what ident's exchange answers — since ident#23 the identity'spublic 5-character short id (`a68sz`), before that the per-app id (32 hex); `users.hl isIdentId` accepts both (the old`isHex` check refused short ids). The switch: one-off `tools/migrate-short-ids.hl` (old → short id, idempotent, never`finish`), gate `node tests/short-id-switch.mjs` (ports 8722/8723, no browser), runbook`antcolony-docs/docs/short-id-switch.md` (Byrodin: `/CONTAINERS/projects/antcolony/docs/short-id-switch.md` once synced).## Reminders and notifications (ticket #4)- **Reminder settings** (button under the month, signed in): the calendar's default reminders — 1 hour before and the day before at20:00 until changed. Every event without reminders of its own gets them. In an event, "Calendar's" / "Own" chooses; "Own" is a listof rows (N minutes before, N hours before, N days before at HH:MM), also none at all.- Stored as WorldAPI Event `$reminders` (`{ $before: 'PT1H' }`, `{ $days_before: 1, $time: '20:00' }`); no `$reminders` = inherit; thedefaults are the Calendar's `$reminders` in `storage/mpackdb/settings.db` (one row per owner).- The page keeps the events of the next days with the reminders that apply (`soon`, part of the page state — the offline layer stores it)and sets one browser timer per reminder of the next 7 days (`arm()`; set again after every save / delete / paging and every 10 minutesof use). A timer shows the notification (hl:web `notify`, through the service worker). "Turn on notifications" is the click the browserwants before it allows them.- **Offline:** the timers need no network, and the offline page has `soon`. An event saved while the server cannot be reached shows at once,its reminders are set, and the save waits in hl:web's emit queue until the connection is back.- **Limit (Hybriel):** a timer lives while the app (or its tab) is open; a fully closed app cannot be woken without a server push (later,via ident's push notifications, ident#8). `notifyAt` cannot cancel, so `arm()` uses `setTimeout` directly and calls `notify`.- Code: `components/month-view/reminders.hl` (rows ↔ `$reminders`, describe, time-zone instants, the plan) shared by `events.hl` (settingstable, `upcoming`) and `month-view.hl` (editor, timers).## Layout- `project.hl` routes, the ident login return (`/login/callback`, `/login/failed`) · `styles.hl` all CSS (tokens from`shared/tokens.hl`, accent = light blue) · `components/main.hl` shell with the login · `components/calendar.hl` the pageand the faces `calLoad` / `calSave` / `calDelete` · `components/loginfailed.hl`.- `users.hl` users table (`storage/mpackdb/users.db`, ident identity → user `@id`) and the ident exchange ·`events.hl` events table (`storage/mpackdb/events.db`, index `owner`), strict validation, every function takes the owner.- `components/month-view/` the month view, vendored from components.hybriel.worldapi.org and EXTENDED here (events on thedays, the editor; `dates.hl` = date helpers shared with the server; it carries its own `Style`). Re-vendoring needs these changes carried over.- `login.js` ident selector ↔ shell bridge (the only hand-written JavaScript). The month view reads the browser's today / language / time zone itself (Hybriel `Date` / `Intl` in a handler, on the first pointer / focus / touch), no `month-view.js`.- PWA (ticket #3): installable and offline through hl:web's own support — `appIcons`, `appThemeColor`, `offline = [ Calendar ]` in project.hl (manifest link in the head, `/__hl/manifest.webmanifest`, `/__hl/sw.js`); icons in `icons/`. No JavaScript of ours.- `bin/hybriel` + `plugins/` (core crypto data fetch fs http http1 mpackdb proc time web) are vendored = hybriel **master06617221** (2026-10-03, antcolony mission 074: plugin allocators 3a781359 + 413f60e4 (#126, plugins allocate with malloc viaplugin_api.zig), mpackdb 2cb7ae5e, http1 773de63e, f0ac2d2d (plugin ABI field — bin and .so must match); no lambda semanticschange), sha256 `21059cc7…d77bdb`, built the same way from `git archive 06617221` (`~/scratch-074/src`, removed); previous copy(190aa11d) in `.scratch/pre-074/`. Gates: `CALENDAR_GATE_PORT=8760 CALENDAR_GATE_IDENT_PORT=8761 CALENDAR_GATE_CHROME=8762-8769node tests/browser.mjs` 78/0, `CALENDAR_SWITCH_IDENT_PORT=8760 CALENDAR_SWITCH_PORT=8761 node tests/short-id-switch.mjs` 18/0.Memory: `LOADS=N PAGES=N node .scratch/w074/memtest.mjs <app dir> <mpackdb copy> <label> 0muh8y8myb5z` (port 8760, Chrome8761–8769; RSS marks every 250): 1000 loads + 1000 pagings new 194 → 214 → 218 MB, old 190aa11d 194 → 227 → 231 MB.Before: master 190aa11d (2026-10-02, antcolony mission 072: fc838894 GC correctness (string index / plugin error read freed memory),038d84b3 #126 returned closure scopes, #127 d98926c6/04df4428; no lambda semantics change since 8efba065), sha256`860f5e61…0a23626`, built read-only from `git archive 190aa11d`; previous copy (8efba065) in `.scratch/pre-072/`. Gates:`CALENDAR_GATE_PORT=8720 CALENDAR_GATE_IDENT_PORT=8721 CALENDAR_GATE_CHROME=8722-8729 node tests/browser.mjs` 78/0,`CALENDAR_SWITCH_IDENT_PORT=8730 CALENDAR_SWITCH_PORT=8731 node tests/short-id-switch.mjs` 18/0. Memory:`.scratch/w072/memtest.mjs` (port 8720, Chrome 8721-8728, same args): 200+200 new 194 → 214 → 215 MB (old 283 → 368 → 376),1000+1000 new 229 → 233 MB — flat.Before: master 8efba065 (2026-10-02, antcolony mission 069: #126 memory freed by bytes too, #48 lambda parameters COPY; earlier ff51cf46 #113,#115/#116, #118, client SVG namespace, hl:markdown #111; #103–#106, #94, #83, #82, #95–#97). Built from aread-only `git archive master` (`zig build -Doptimize=ReleaseFast -Dtarget=x86_64-linux-gnu.2.39` in `native/`, zig =hybriel's `native/zig-toolchain` link), sha256 `56b108f3…f4f201ea`. **No local patch**: re-vendor = copy binary + theplugins above, run both gates. Previous copy (ff51cf46): `.scratch/pre-069/`.- **Lambdas copy their arguments (hybriel #48)**: `f = (x) => { x.n = 1 }` changes a COPY; a lambda that must change thecaller's hybrid/list takes `&x`. Audit 2026-10-02 (`python3 .scratch/w069/lambdas.py` / `lambdas2.py`, 64 lambdas): nonewrites a parameter the caller reads — `project.hl` failed/loginCallback save `req.session` themselves, the rest build newvalues. Probe: `bin/hybriel .scratch/w069/probe48.hl`. New lambdas: use `&` when the caller relies on the change.- Memory check (#126): `node .scratch/w069/memtest.mjs <app copy> <mpackdb copy> <label> <users @id>` (port 8730, Chrome8722-8729; env LOADS/PAGES): RSS at boot, after N signed-in page loads, after N month pagings (calLoad), after 5 s idle.- `components/calendar.hl` `validWindow` / `soonOf` are plain members called from the server faces (no `static` since #115/#116,antcolony mission 048; the gate checks both).- Language of the first render (calendar#6): `components/calendar.hl` declares `headers = null` (hybriel #105) and hands`headers['accept-language']` to `MonthView { acceptLanguage = requestLanguage }`; `names.hl` knows en de fr es it nl pt,any other → neutral names until the browser fills in its own. Names written by the server stay while paging.- Reminder timers: `arm()` creates the `setTimeout` closure inline in its `while` loop — `let p` is a new binding per pass(hybriel #106). On an older Hybriel the closures shared `p` and only the last reminder fired (antcolony mission 037 proved it:gate on 13ef4f9b → "the notifications came on time" FAIL, only "Has its own reminder" came).## Run, test, deploy- `CALENDAR_PORT=8700 ./bin/hybriel project.hl` (env: `CALENDAR_WATCH=0` no watcher, `HL_HOST`, `CALENDAR_SESSIONS`,`CALENDAR_STORAGE`, `CALENDAR_PUBLIC_URL` default https://calendar.worldapi.org, `IDENT_URL`, `IDENT_EXCHANGE_URL`,`IDENT_API_KEY`, `IDENT_API_SECRET` — `.env` beside `project.hl`, never read by workers). A login needs the ident key.- `node tests/browser.mjs` — the gate: own ident (a copy without `.env`), own server + storage, headless Chrome(ports 8700 app, 8701 ident, 8702–8709 Chrome; `CALENDAR_GATE_PORT`, `CALENDAR_GATE_IDENT_PORT`, `CALENDAR_GATE_CHROME`).Second gate: `node tests/short-id-switch.mjs` (ports 8722/8723; `CALENDAR_SWITCH_IDENT_PORT`, `CALENDAR_SWITCH_PORT`).`GATE_SKIP_EVENTS=1` skips the events part (40 checks run instead of 76, ~1.5 min instead of ~4). The language checks (`languagePart`)open a tab per language with CDP `Network.setExtraHTTPHeaders` Accept-Language de / en and the browser's own language(Intl locale + navigator.language) set to the OTHER one; first page, server HTML, next/next/prev.- `./deploy.sh` on Loreana (architect): gate → backup → rsync → `docker compose up -d --build` on Byrodin (127.0.0.1:45005).## First deploy of ticket #2 (architect)Register the app in ident with the origin `https://calendar.worldapi.org` and put `IDENT_API_KEY` / `IDENT_API_SECRET`into `.env` on Byrodin (as notes does), otherwise the login button has no key.## History and worker briefs- `LOG.md` — append-only history, one dated line per step (moved here from the antcolony LOG on 2026-10-01).- `missions/NNN-*.md` — worker briefs for this app; `reports/NNN-*.md` — their reports (same name). Numbered perproject since 2026-10-01 (antcolony#40); older text, code comments and commits use the old antcolony numbers →map: `/media/STORAGE/projects/antcolony-docs/docs/mission-map.md` (Byrodin: `/CONTAINERS/projects/antcolony/docs/mission-map.md`).
Branches
- mainmain branch
Latest commits
- c6fbd011calendar mission 001 (1/4): code order — files moved: lib/events.hl, lib/users.hl, components/styles.hl (imports only); gates 78/0 + 18/0, live-data run identicalmre
- d6c59290calendar: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gates 78/0 + 18/0mre
- 7bd0337ccalendar: Hybriel master 190aa11d (fc838894 GC correctness, #126 closure scopes, #127); gates 78/0 + 18/0mre
- ff41310ccalendar: Hybriel master 8efba065 (#126 memory, #48 lambda copy; audit: no & needed)mre
- 14ba08c7antcolony#40: mission references point to the moved missionsmre
- 99c73346antcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
- 76edaa62calendar: Hybriel master ff51cf46 (re-vendor round, static workaround removed)mre
- 90a3fc2cdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
- 6722b72ddeploy.sh: never send .git or .gitignore to Byrodinmre
- be099807State of 2026-09-27, before the move to gitoriamre