Migrovane z
docs-old-cvrn/plans/PLAN_DYNAMICKY_KOD.md.
1) Ciel
Automatizovat proces zmeny zamku kodu tak, aby:
- admin nemusel manualne menit kod raz za mesiac,
- system vedel evidovat historiu kodov na kazdy bicykel,
- existoval audit "kto, kedy, z akeho kodu na aky kod menil",
- pri probleme bol dostupny recovery postup (posledne kody + stav overenia),
- onboarding usera obsahoval povinne potvrdenie pravidiel pri prvom prihlaseni.
2) Rozsah
In scope
- evidencia historie kodov,
- automaticka rotacia kodu pri vrateni bicykla,
- potvrdenie funkcnosti kodu pri nasledujucom prenajme,
- admin obrazovka pre audit/recovery,
- terms acceptance (prve prihlasenie + verzovanie pravidiel),
- stavovy model pre "kod overeny/neovereny/podozrivy".
Out of scope (v tejto faze)
- hardverove smart lock API (zamok sa stale nastavuje manualne clovekom),
- push notifikacie/SMS,
- pokrocile anti-fraud mechanizmy.
3) Vychodiskovy stav (teraz)
bikes.secret_codedrzi aktualny kod.- Pri rent sa kod zobrazi userovi.
- Pri return sa kod nemeni automaticky.
- Historia kodov nie je oddelena tabulka.
- Terms acceptance flow zatial nie je implementovany.
4) Cielovy stav (po implementacii)
- Pri return:
- system vygeneruje novy 4-ciferny kod,
- user potvrdi, ze kod fyzicky nastavil na zamku,
- system ulozi rotaciu do historie.
- Pri dalsom rent:
- user potvrdi "kod fungoval pri odomknuti",
- system oznaci poslednu rotaciu ako
verified.
- Ak user oznaci "kod nefungoval":
- bicykel prejde do
code_status='suspect', - admin vidi posledne kody a moze riesit recovery.
- bicykel prejde do
- Pri prvom prihlaseni:
- user musi potvrdit aktualnu verziu pravidiel.
5) Datovy model (decision-complete)
5.1 Upravy existujucich tabuliek
public.bikes
Pridat stlpce:
code_version int not null default 1code_status text not null default 'verified'- allowed:
verified,pending_verification,suspect
- allowed:
last_code_change_at timestamptz nulllast_code_changed_by uuid null references public.profiles(id)
Constraint:
check (code_status in ('verified','pending_verification','suspect'))
public.rentals
Pridat stlpce:
unlock_verification text null- allowed:
ok,failed,not_provided
- allowed:
unlock_verified_at timestamptz nullunlock_verified_by uuid null references public.profiles(id)code_version_used int null
Constraint:
check (unlock_verification in ('ok','failed','not_provided') or unlock_verification is null)
public.profiles
Pridat stlpec:
training_completed boolean not null default false
5.2 Nove tabulky
public.bike_code_history
Audit historia kodov:
id bigint generated by default as identity primary keybike_id bigint not null references public.bikes(id) on delete cascaderental_id bigint null references public.rentals(id) on delete set nullold_code text not nullnew_code text not nullold_version int not nullnew_version int not nullchanged_at timestamptz not null default now()changed_by uuid not null references public.profiles(id)change_source text not null- allowed:
return_flow,admin_manual
- allowed:
verification_status text not null default 'pending'- allowed:
pending,verified,failed
- allowed:
verified_at timestamptz nullverified_by uuid null references public.profiles(id)verification_note text null
Indexy:
(bike_id, changed_at desc)(verification_status, changed_at desc)
public.terms_versions
id bigint generated by default as identity primary keyversion text not null unique(napr.2026-02-v1)title text not nullcontent_md text not nullis_active boolean not null default falsepublished_at timestamptz not null default now()created_by uuid null references public.profiles(id)
Constraint:
- partial unique index na
is_active=true(max 1 aktivna verzia)
public.terms_acceptances
id bigint generated by default as identity primary keyuser_id uuid not null references public.profiles(id) on delete cascadeterms_version_id bigint not null references public.terms_versions(id) on delete cascadeaccepted_at timestamptz not null default now()ip text nulluser_agent text null
Constraint:
unique(user_id, terms_version_id)
6) Stavovy model kodu
bikes.code_status
verified: posledna rotacia bola potvrdena dalsim uzivatelom.pending_verification: kod bol zmeneny pri return, ale este nebol potvrdeny dalsim rentom.suspect: niekto nahlasil, ze kod nefunguje, alebo verifikacia zlyhala.
Prechod stavov:
- return + rotacia ->
pending_verification - next rent verifikacia OK ->
verified - next rent verifikacia failed ->
suspect - admin recovery/manual reset ->
pending_verificationaleboverified(podla admin rozhodnutia)
7) API / RPC zmeny
7.1 Nove RPC
rotate_code_on_return(note_text text, confirm_changed boolean)- predpoklad: user ma aktivny rental.
- ak
confirm_changed=false: return odmietnut (biznis pravidlo). - vygeneruje novy kod, update
bikes.secret_code,code_version+1, statuspending_verification. - vlozi
bike_code_historyriadok (pending). - uzavrie rental (
returned_at,return_note,code_version_used).
verify_unlock_result(rental_id bigint, result text, note text default null)result in ('ok','failed').ok: posledna rotaciaverified, bikeverified.failed: posledna rotaciafailed, bikesuspect.- update
rentals.unlock_verification....
admin_get_bike_code_history(bike_id bigint, limit_count int default 20)- vrati posledne rotacie daneho bicykla.
admin_mark_code_recovered(bike_id bigint, working_code text, note text default null)- admin potvrdi realne fungujuci kod po fyzickej kontrole.
- update
bikes.secret_code,code_version+1, history rowadmin_manual. - status
verifiedalebopending_verification(defaultverified).
get_active_terms()- vrati aktivnu verziu pravidiel.
accept_terms(terms_version_id bigint)- ulozi akceptaciu pre usera.
has_accepted_active_terms()- bool pre middleware gating.
7.2 Zmena existujucich RPC
rent_bike(...):- po uspesnom rent vrati aj
code_statusacode_version.
- po uspesnom rent vrati aj
return_bike(...):- nahradit za
rotate_code_on_return(...)(alebo ponechat ako fallback pre admin emergency flow).
- nahradit za
8) Generovanie kodu (presne pravidla)
Format kodu:
- 4 cifry
0000-9999.
Bezpecny generator:
- Postgres
gen_random_bytes/gen_random_uuidderivacia alebo generovanie v server action cezcrypto. - Preferencia: generovat v DB RPC (single source of truth).
Pravidla pre vyber:
- zakazat opakovanie poslednych
N=5kodov pre dany bike, - max
K=20pokusov o random draw, - ak sa nepodari, fallback: linear scan od nahodneho startu.
9) UI/UX zmeny
9.1 Dashboard user
Pri aktivnej jazde:
- zobrazit aktualny kod ako dnes.
- pri vrateni pridat checkbox:
Potvrdzujem, ze som fyzicky nastavil novy kod na zamku.
- po submit zobrazit "Novy kod bol ulozeny v systeme."
Pri najblizsom dalsom rent (po odomknuti):
- modal s 2 tlacidlami:
Kod fungoval,Kod nefungoval.
9.2 Admin
Na /admin pridat sekciu:
- tabulka historie kodov (bike, old/new version, changed_by, verification_status, changed_at),
- filter podla bike a statusu,
- quick action
Mark recovered+ zadanie realne fungujuceho kodu.
9.3 Terms acceptance
Nove route:
/terms- zobrazi aktivny text pravidiel + accept tlacidlo.
Middleware:
- prihlaseny user bez akceptacie aktivnej verzie -> redirect na
/terms.
10) RLS a bezpečnost
Pravidla:
- bezny user nevidi globalnu historiu kodov.
- bezny user moze vidiet iba aktualny kod svojho pozicaneho bicykla.
bike_code_historyselect len admin.- terms read pre authenticated, write acceptance len pre vlastneho usera (cez RPC).
Audit:
- kazda zmena kodu ma
changed_by,changed_at,change_source. - kazde zlyhanie verifikacie ma
verification_note.
11) Migracny plan (bez downtime pre MVP)
Faza A: Historia bez zmeny flow
- DB migration:
- nove tabulky + nove stlpce.
- Admin UI:
- historia kodov read-only.
- Manual zmena kodu adminom zapisuje aj history row.
Outcome:
- okamzite mas audit trail, aj ked flow pre usera sa nemenil.
Faza B: Automaticka rotacia pri return
- Nove RPC
rotate_code_on_return. - UI return flow s potvrdenim.
bikes.code_statusprejde napending_verification.
Outcome:
- admin uz nemusi mesacne menit kod.
Faza C: Verifikacia pri dalsom rent + recovery
- UI potvrdenie "kod fungoval/nefungoval".
- RPC
verify_unlock_result. - Admin recovery ak
suspect.
Outcome:
- system rozlisuje doverovany a podozrivy kod.
Faza D: Terms acceptance gate
- terms tabulky + route
/terms. - middleware gate.
- admin publishing novej verzie pravidiel.
Outcome:
- pravna/operacna disciplina pri prvom login a pri zmenach pravidiel.
12) Testy a akceptacne scenare
12.1 Funkcne scenare
- Return s potvrdenim:
- vytvori sa history row,
- bike ide do
pending_verification, - rental sa zavrie.
- Next rent verifikacia OK:
- posledna history row ->
verified, - bike ->
verified.
- posledna history row ->
- Next rent verifikacia failed:
- history row ->
failed, - bike ->
suspect, - admin vidi alert v dashboarde.
- history row ->
- User bez acceptance:
- po login redirect
/terms.
- po login redirect
- User po acceptance:
- standard flow na
/.
- standard flow na
- RLS:
- bezny user nedokaze citat
bike_code_history.
- bezny user nedokaze citat
12.2 Edge cases
- dva paralelne return requesty na rovnaky bike (transaction lock),
- bike v
servicesa neda pozicat, - generator kodu nenajde kod v random pokusoch (fallback funguje),
- admin manual recovery pocas aktivneho rentalu (zakazane).
13) Operacne metriky
Merat:
- pocet rotacii kodov za den/tyzden,
- podiel failed verifikacii,
- pocet bicyklov v
suspect, - median cas od
pending_verificationdoverified.
Alert podmienka:
- ak bike ostane
pending_verificationviac ako X dni, - ak failed verifikacie prekrocia limit za tyzden.
14) Otvorene rozhodnutia (default nastavene)
- Dlzka kodu:
- default: 4 cifry (ponechat).
- User moze vratit bike bez potvrdenia zmeny kodu?
- default: nie (blokovat return bez confirm checkboxu).
- Kolko historickych kodov odporucat adminovi v recovery UI?
- default: poslednych 10.
- Admin recovery po fyzickej kontrole nastavi stav:
- default:
verified.
- default:
15) Minimalny implementacny backlog (poradie)
- SQL migration pre
bike_code_history,terms_versions,terms_acceptances, nove stlpce. - RPC:
rotate_code_on_return,verify_unlock_result,admin_get_bike_code_history. - Update
actions.tsa dashboard return flow. - Admin page: historia kodov + filter + recover action.
- Terms route + middleware gate.
- Testy scenarov + rollout najprv na malej skupine userov.
16) Kompatibilita s planom reported bicykla
Plan PLAN_NAHLASENE_NEPOZICATELNE_BIKY.md zavadza os stavu
bikes.status='reported', ktora je odlisna od bikes.code_status.
Integracne pravidlo:
status(available/rented/service/reported) = operacna pozicatelnost bicykla,code_status(verified/pending_verification/suspect) = doveryhodnost kodu zamku.
Tieto osi sa nesmu zamienat ani prepinat jedna druhu implicitne.
Ak je bike reported, kodovy flow moze bezat iba v rozsahu, ktory neobchadza
operacny blok prenajmu pre bezneho usera.
On This Page
1) Ciel2) RozsahIn scopeOut of scope (v tejto faze)3) Vychodiskovy stav (teraz)4) Cielovy stav (po implementacii)5) Datovy model (decision-complete)5.1 Upravy existujucich tabuliek5.2 Nove tabulky6) Stavovy model kodubikes.code_status7) API / RPC zmeny7.1 Nove RPC7.2 Zmena existujucich RPC8) Generovanie kodu (presne pravidla)9) UI/UX zmeny9.1 Dashboard user9.2 Admin9.3 Terms acceptance10) RLS a bezpečnost11) Migracny plan (bez downtime pre MVP)Faza A: Historia bez zmeny flowFaza B: Automaticka rotacia pri returnFaza C: Verifikacia pri dalsom rent + recoveryFaza D: Terms acceptance gate12) Testy a akceptacne scenare12.1 Funkcne scenare12.2 Edge cases13) Operacne metriky14) Otvorene rozhodnutia (default nastavene)15) Minimalny implementacny backlog (poradie)16) Kompatibilita s planom reported bicykla