Deployment infrastructure for the Halkyon ecosystem.
  • PLpgSQL 55.3%
  • TypeScript 37.4%
  • Shell 7.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Tizian 「ティツィアーン」 a875b93a31 feat(streak): store the user's frozen rest days (#85)
The Home streak counts four things: flashcard reviews, learning-path
step completions, hand-authored card creations, and the days the user
froze as rest days. The first three sync. The fourth had no server table
at all, so a rest day only ever existed on the device that set it.

The effect is a streak that disagrees across devices, and disagrees by a
lot rather than by one: a frozen day bridges a gap in the activity
record, so the device that knows about it counts straight through while
the other stops dead at the gap. A user with a single zero-activity day
three weeks back sees a three-week streak on the phone and a four-day
one on the web.

`id` is derived, not random: `'<user_id>:<YYYY-MM-DD>'`, enforced by a
CHECK. A frozen day is set membership, so two devices freezing the same
date offline have to converge on one row. With client-generated UUIDs
they would each insert their own, and a later un-freeze would clear one
and leave the other — the day would stay frozen, and no amount of
syncing would fix it. The same natural-key trick studyset_study_settings
uses for `user:studyset`.

`date` is a DATE rather than a timestamp. The frozen unit is a local
calendar day as the user lived it; storing an instant would re-open the
timezone question on every device that reads it, and a rest day taken in
Berlin is that same day everywhere.

Un-freezing is a soft delete. Dropping the row would leave the other
devices still holding the day, and the next pull from one of them would
push it straight back — the delete has to be a change that propagates,
not an absence.

Realtime, for the reason reviews were opted in: the streak is a
dashboard surface, and a rest day marked on the phone should reach an
open web app rather than wait for a relaunch. RLS applies to Realtime
too, so each device receives only its own rows.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>

Reviewed-on: https://codeberg.org/project-halkyon/halkyon-infra/pulls/85
2026-08-05 12:56:25 +02:00
discovery Add instance-discovery document + serving guide (#68) 2026-07-01 13:53:17 +02:00
docker/languagetool feat(grammar): check-grammar Edge Function + LanguageTool + migrations (#60) 2026-06-21 14:15:06 +02:00
docs docs(architecture): backend architecture record (#67) 2026-06-26 02:28:50 +02:00
scripts feat(ops): instance backup + restore scripts (#76) 2026-07-05 23:23:26 +02:00
supabase feat(streak): store the user's frozen rest days (#85) 2026-08-05 12:56:25 +02:00
.gitignore feat(ops): instance backup + restore scripts (#76) 2026-07-05 23:23:26 +02:00
CONTRIBUTING.md Add SECURITY.md and CONTRIBUTING.md 2026-04-25 14:01:12 +03:00
LICENSE Initial commit 2026-04-23 13:13:59 +02:00
README.md docs(architecture): backend architecture record (#67) 2026-06-26 02:28:50 +02:00
SECURITY.md Add SECURITY.md and CONTRIBUTING.md 2026-04-25 14:01:12 +03:00

halkyon-infra

Deployment infrastructure for the Halkyon ecosystem.

📐 Architecture: docs/architecture.md explains the backend — the migration/RLS model, RPC conventions, Realtime, Storage, the Edge Functions, self-hosting, and the sync contract with the app.