Commit Graph
2 Commits
Author SHA1 Message Date
connor 82d05dc67a Add the database schema and repository layer
The per-calendar JSON blob is gone. v1 kept every calendar's colour, every
visibility toggle and a custom palette inside one calendar_colors TEXT
column, so hiding one calendar rewrote the whole document -- which is where
"Fix calendar visibility preservation during event updates" came from.
Those are rows now, and set_visible touches visibility alone.

Foreign keys are switched on. v1 declared external_calendars.user_id as
INTEGER against a TEXT users.id; SQLite enforces neither the type nor the
constraint unless asked, so it was decorative and could never match.

Session tokens are stored as SHA-256, never in the clear, so a copy of the
database cannot be used to impersonate anyone. The CalDAV password is the
one secret that cannot be hashed -- it has to be replayed to the server --
so it gets an encrypted column with the algorithm recorded alongside, and
one way in and one way out instead of v1's eight localStorage reads.

Preferences are one column each with CHECK constraints, so a bad view or a
nonsense time increment is refused whatever route it arrives by. A NULL
display timezone means "follow the browser", which is a state v1 could not
express -- as with a NULL calendar colour meaning "defer to the server",
which is why it hashed paths to invent one.

Feed caching stores a content hash beside the ETag, because a published
Outlook feed sends neither ETag nor Last-Modified and staleness has to be
detectable anyway.

Thirty tests against real in-memory SQLite, not mocks. One caught that
create() returned nanosecond timestamps while the column stores
microseconds, so a session never compared equal to itself read back.
2026-08-26 15:54:28 -04:00
connor bf63024711 Set up workspace skeleton
Five crates: runway-core (pure domain), runway-caldav (protocol),
runway-server (axum), runway-web (leptos), runway-cli (smoke tool).

runway-core is feature-gated into model/ical/recurrence so the frontend
can depend on the shared types without pulling icalendar and rrule into
the WASM bundle. The previous iteration shipped reqwest, ical and regex
to the browser for a dead module; the feature split makes that mistake
structurally hard to repeat.

Guardrails are compiler- and CI-enforced rather than aspirational:
workspace lints deny unwrap_used/expect_used, dead_code and unsafe_code,
clippy.toml caps function length and arity, deny.toml pins licences.

Toolchain is pinned per-project so the machine-wide default is untouched.
Cargo.lock is committed this time.

docs/legacy-audit.md carries the marked-up feature decisions and is the
spec for the rewrite.
2026-08-26 12:07:44 -04:00