Architektura
Komunita
Legal
Plany
Changelog
Migrovane z
docs-old-cvrn/PLAN_EMAIL_NOTIFIKACIE.md.
0) Stav realizacie (aktualizovane 2026-02-11)
Toto je dokumentacny implementacny plan pre buducu funkcionalitu.
- Feature este NIE JE implementovana v appke ani DB.
- Ciel je mat decision-complete specifikaciu pred kodovanim.
- Tento plan doplna plan
reportedbicyklov.
1) Ciel
Pridat transakcne e-mail notifikacie tak, aby:
- appka posielala maily v mene
app@cvrn.sk, - kriticke udalosti o
reportedbicykloch prisli automaticky adminom, - reporter dostal potvrdenie pri vytvoreni a uzavreti reportu,
- odosielanie bolo spolahlive (retry, audit, bez blokovania core flow).
2) Scope
In scope (MVP)
- provider
Resend(API), - outbox model (
email_outbox) + inline send attempt + cron retry, - konfiguracia recipientov v DB + admin UI,
- zakladny admin log odosielania + retry akcia,
- plain text SK e-mail sablony,
- eventy:
reported_created_admin,reported_created_reporter,reported_resolved_admin,reported_resolved_reporter,reported_override_admin.
Out of scope (v tejto faze)
- reminder maily po 24h/72h,
- digesty (denne/tyzdenne),
- notifikacie pre allowlist zmeny a ine ne-kriticke eventy,
- SMS/push notifikacie,
- HTML templating engine.
3) Produktove rozhodnutia (uzamknute)
- Provider:
Resend. - Sender:
From=app@cvrn.sk,Reply-To=info@cvrn.sk. - Delivery model: outbox queue + inline attempt + cron retry.
- Recipient config: DB + admin UI (nie len ENV).
- User notifikacie: ano pre report create aj report resolve.
- Format: plain text, slovencina.
- MVP bez reminderov.
4) Architektura (high level)
- Biznis event vznikne v report RPC (
create/resolve/override). - V tej istej DB transakcii sa vlozia riadky do
email_outbox. - Po uspesnom evente sa spusti inline send attempt pre nove
pendingriadky. - Chyby idu do
retry_scheduledsnext_attempt_at. - Cron endpoint periodicky spracuje retry queue.
- Admin ma read-only log + manual retry akciu.
5) Datovy model (decision-complete)
5.1 Nova tabulka public.notification_recipients
id bigint generated by default as identity primary keyemail text not nulllabel text nullis_active boolean not null default truecreated_at timestamptz not null default now()updated_at timestamptz not null default now()created_by uuid null references public.profiles(id) on delete set null
Constrainty a indexy:
- unique index na
lower(email) - index na
(is_active, created_at desc)
5.2 Nova tabulka public.email_outbox
id bigint generated by default as identity primary keyevent_type text not nullevent_ref_type text not null(napr.bike_report)event_ref_id bigint not nullto_email text not nullsubject text not nullbody_text text not nullstatus text not null default 'pending'- allowed:
pending,sending,sent,failed,retry_scheduled,dead
- allowed:
attempt_count int not null default 0next_attempt_at timestamptz nulllast_error text nullprovider_message_id text nullcreated_at timestamptz not null default now()sent_at timestamptz null
Constrainty:
check (status in ('pending','sending','sent','failed','retry_scheduled','dead'))- dedupe unique key:
(event_type, event_ref_type, event_ref_id, lower(to_email))
Indexy:
(status, created_at asc)(status, next_attempt_at asc)(event_ref_type, event_ref_id)
6) API / RPC zmeny
6.1 Rozsirenie report RPC
report_bike_unrentable(...)- enqueue
reported_created_adminpre aktivnych recipientov, - enqueue
reported_created_reporterpre usera, ktory report vytvoril.
- enqueue
admin_resolve_bike_report(...)- enqueue
reported_resolved_admin, - enqueue
reported_resolved_reporterpre povodneho reportera.
- enqueue
admin_override_rent_reported_bike(...)- enqueue
reported_override_admin.
- enqueue
Poznamka:
- enqueue sa deje v tej istej transakcii ako biznis event.
- zlyhanie inline send attempt nesmie rollbacknut report/rental mutaciu.
6.2 Nove admin RPC
admin_list_notification_recipients()admin_upsert_notification_recipient(email text, is_active boolean, label text default null)admin_delete_notification_recipient(recipient_id bigint)admin_list_email_outbox(limit_count int default 200, status_filter text default null)admin_retry_email_outbox_item(outbox_id bigint)
6.3 Helper funkcie
enqueue_reported_email_events(...)(DB helper alebo server helper)email_compute_next_attempt(attempt_count int)pre backoff
7) Retry politika
- Max pokusov:
5 - Backoff:
- pokus 1: +1 min
- pokus 2: +5 min
- pokus 3: +15 min
- pokus 4: +60 min
- pokus 5: +360 min
- Po prekroceni limitu:
dead
8) Frontend / Admin UX
8.1 /admin sekcia "Notifikacni prijemcovia"
- pridanie prijemcu (email + volitelny label),
- aktivacia/deaktivacia,
- odstranenie.
8.2 /admin sekcia "E-mail outbox log"
- filter podla stavu (
pending/sent/failed/retry_scheduled/dead), - stlpce:
- event,
- to,
- status,
- attempts,
- last_error,
- created_at,
- sent_at,
- akcia
Retryprefailed/dead.
9) Integracia s providerom (Resend)
Potrebne env premenne:
RESEND_API_KEYEMAIL_FROM=app@cvrn.skEMAIL_REPLY_TO=info@cvrn.skEMAIL_CRON_SECRET
DNS onboarding (mimo kodu):
- SPF, DKIM, DMARC pre
cvrn.sk, - overenie sender domény v Resend.
10) Security a compliance
- cron endpoint musi kontrolovat bearer secret (
EMAIL_CRON_SECRET), - ziadne citlive udaje (
secret_code) v tele e-mailov, - logovat len technicke detaily chyb bez zbytocnych PII,
- RLS/admin guard pre recipient/outbox citanie a mutacie.
11) Test scenare
11.1 Funkcne
- Report create -> vzniknu outbox riadky pre admin + reportera.
- Report resolve -> vzniknu outbox riadky pre admin + reportera.
- Override rent -> admin alert mail event.
- Inline success ->
sent+provider_message_id. - Inline fail ->
retry_scheduled+next_attempt_at. - Cron retry -> uspesne dorucenie pending/retry mailu.
- Manual retry z admin UI funguje.
11.2 Security
- Cron endpoint bez valid secret vrati unauthorized.
- Bezny user nema pristup k recipient/outbox admin RPC.
- Dedupe key zabrani duplicitnym mailom pri race condition.
11.3 Regression
- Report/rent/return flow funguje aj pri vypadku provideru.
- Zlyhanie mailu nevracia report mutaciu naspat.
12) Dokumentacny dopad
Pri implementacii tejto funkcionality aktualizovat:
README.md(setup env + sekcia notifikacii),CONTRIBUTING.md(kde sa plan nachadza + scope),docs/checklist.md(feature-specific checks),docs/CHANGELOG.md([Unreleased]),/docs/plany/nahlasene-nepozicatelne-biky(cross-reference).
13) Rollout plan
Faza A: Schema + provider adapter
- DB tabulky, indexy, constraints,
- env setup, Resend adapter, text template builder.
Faza B: Worker + cron
- inline send attempt,
- cron retry endpoint,
- retry/backoff pravidla.
Faza C: Event napojenie
- create/resolve/override event wiring z report flow.
Faza D: Admin observability
- recipient management,
- outbox log + manual retry.
14) Predpoklady a defaulty
- Hosting je Next.js + serverless kompatibilne cron volanie.
reportedflow je implementovany a sluzi ako event source.- Provider default je Resend, ale adapter vrstva umozni vymenu neskor.
- Tento dokument je plan; runtime implementacia sa robi az v samostatnom kroku.
On This Page
0) Stav realizacie (aktualizovane 2026-02-11)1) Ciel2) ScopeIn scope (MVP)Out of scope (v tejto faze)3) Produktove rozhodnutia (uzamknute)4) Architektura (high level)5) Datovy model (decision-complete)5.1 Nova tabulka public.notification_recipients5.2 Nova tabulka public.email_outbox6) API / RPC zmeny6.1 Rozsirenie report RPC6.2 Nove admin RPC6.3 Helper funkcie7) Retry politika8) Frontend / Admin UX8.1 /admin sekcia "Notifikacni prijemcovia"8.2 /admin sekcia "E-mail outbox log"9) Integracia s providerom (Resend)10) Security a compliance11) Test scenare11.1 Funkcne11.2 Security11.3 Regression12) Dokumentacny dopad13) Rollout planFaza A: Schema + provider adapterFaza B: Worker + cronFaza C: Event napojenieFaza D: Admin observability14) Predpoklady a defaulty