feat: add web push and sadhna tracker

This commit is contained in:
Krispire Admin
2026-06-08 15:47:44 +05:30
parent e352948fb1
commit f598770b32
31 changed files with 2267 additions and 2 deletions
@@ -0,0 +1 @@
DROP TABLE IF EXISTS sadhna_logs;
+30
View File
@@ -0,0 +1,30 @@
-- Sādhana streak: one row per user per day on which they chanted.
--
-- A "day complete" (what the streak + the growing-plant animation are
-- built on) is the conjunction of two daily disciplines:
-- 1. chanting today's target rounds → recorded here (chant_done)
-- 2. posting at least one quote today → derived live from the posts
-- table (a post whose created_at falls on the same calendar day)
-- so this table only needs to capture the chanting half.
--
-- log_date is a DATE (not a timestamp) so the streak rolls over at UTC
-- midnight without any timezone math, matching how the rest of the app
-- buckets "today". chant_done is stored explicitly — decided at save time
-- as rounds_completed >= the user's target THEN — so later edits to a
-- user's daily_chanting_rounds never retroactively rewrite history.
CREATE TABLE IF NOT EXISTS sadhna_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
log_date DATE NOT NULL,
rounds_completed INTEGER NOT NULL DEFAULT 0,
chant_done BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (user_id, log_date),
CHECK (rounds_completed >= 0 AND rounds_completed <= 1008)
);
-- The streak/growth computation walks a user's recent days newest-first;
-- this serves both that scan and the "today" lookup.
CREATE INDEX IF NOT EXISTS sadhna_logs_user_date_idx
ON sadhna_logs (user_id, log_date DESC);
@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS sadhna_reward_grants;
DROP TABLE IF EXISTS sadhna_rewards;
@@ -0,0 +1,36 @@
-- Sādhana streak rewards.
--
-- `sadhna_rewards` is the catalog of gift items (one row per reward),
-- seeded/synced at BFF startup from the embedded rewards.json so the
-- name / meaning / image_url stay in lockstep with the source of truth.
--
-- `sadhna_reward_grants` records which reward a user earned at which
-- streak milestone (a multiple of 7 days). The UNIQUE (user_id, milestone)
-- makes granting idempotent — a milestone hands out exactly one gift no
-- matter how often the dashboard is recomputed. `celebrated_at` is NULL
-- until the client has shown the confetti celebration, so a freshly earned
-- gift surfaces exactly once.
CREATE TABLE IF NOT EXISTS sadhna_rewards (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
key TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
meaning TEXT NOT NULL DEFAULT '',
image_url TEXT NOT NULL DEFAULT '',
active BOOLEAN NOT NULL DEFAULT TRUE,
sort INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS sadhna_reward_grants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
reward_id UUID NOT NULL REFERENCES sadhna_rewards(id) ON DELETE CASCADE,
milestone INTEGER NOT NULL,
granted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
celebrated_at TIMESTAMPTZ,
UNIQUE (user_id, milestone)
);
CREATE INDEX IF NOT EXISTS sadhna_reward_grants_user_idx
ON sadhna_reward_grants (user_id, granted_at DESC);
@@ -0,0 +1 @@
DROP TABLE IF EXISTS push_subscriptions;
@@ -0,0 +1,18 @@
-- Web Push subscriptions. One row per browser/device push endpoint a user
-- has granted. The endpoint is globally unique (it's a per-subscription URL
-- at the push service), so re-subscribing the same browser upserts. p256dh
-- and auth are the subscription's encryption keys (base64url). Dead
-- endpoints (404/410 from the push service) are pruned on send.
CREATE TABLE IF NOT EXISTS push_subscriptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
endpoint TEXT NOT NULL UNIQUE,
p256dh TEXT NOT NULL,
auth TEXT NOT NULL,
user_agent TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_used_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS push_subscriptions_user_idx
ON push_subscriptions (user_id);
@@ -0,0 +1,4 @@
ALTER TABLE users DROP COLUMN IF EXISTS last_quote_reminder_on;
ALTER TABLE users DROP COLUMN IF EXISTS last_chant_reminder_on;
ALTER TABLE users DROP COLUMN IF EXISTS sadhna_reminders_enabled;
ALTER TABLE users DROP COLUMN IF EXISTS timezone;
@@ -0,0 +1,14 @@
-- Sādhana reminder support.
--
-- timezone: the user's IANA zone (e.g. "Asia/Kolkata"), reported by the
-- browser, so reminders fire at their local clock time. Defaults to UTC
-- until the client reports a real zone.
--
-- sadhna_reminders_enabled: per-user opt-out for the daily reminders.
--
-- last_{chant,quote}_reminder_on: the UTC date a reminder of that kind was
-- last sent, so each kind goes out at most once per (UTC) day.
ALTER TABLE users ADD COLUMN IF NOT EXISTS timezone TEXT NOT NULL DEFAULT 'UTC';
ALTER TABLE users ADD COLUMN IF NOT EXISTS sadhna_reminders_enabled BOOLEAN NOT NULL DEFAULT TRUE;
ALTER TABLE users ADD COLUMN IF NOT EXISTS last_chant_reminder_on DATE;
ALTER TABLE users ADD COLUMN IF NOT EXISTS last_quote_reminder_on DATE;