Tvuj pristup je prilis akademicky - v praxi narazis pak na to, ze ti bude chybet nektery radek z paru ktery tvori prevod, takze vznikne nekonzistentni system a budes tezko hledat co se ztratilo.
Muj pristup (kdyz jsem delal vlastni sw na ucto) je tento:
TABLE users - id, .... ;
TABLE accounts - userid, typ, nazev-cislo;
TABLE transfers - src, dst, amount;
Kazdy uzivatel (u me subjekt) ma evidovany jeden nebo vicero uctu - uctem se mysli reference na externi ucet (lokalni, mezinarodni, paypal), pripadne docasne ucty - u tebe to jsou interni stavy.
V tabulce prevodu pak mas prevody mezi dvouma* uctama. At uz se jedna o externi platby (dobiti, vyplata), nebo interni platby (za zbozi a provize). *Ve tvem pripade bych se nebal to rozsirit na tristranny prevod 1-na-2 (platba na prijem a provize), udelat to sumarizaci slozitejsi, ale zas se nemusis starat o transakce a rollback pri castecnem selhani. V pripade potreby multi-menove obsluhy je potreba mit alespon 4 sloupce u transferu - zdrojova/cilova castka/mena (a dalsi metadata jako kurz, datum, puvod kurzu). Ja tam mam i reference na radek bankovniho vypisu (paypal, fio) pro snazsi trasovani.
Z takoveho modelu muzes vzdy nechat spocitat balance na kazdem uctu (a v kazde mene), pro kazdeho cloveka. Vse, co mas vedeno jako interni ucet, si pak muze nekdo z uzivatelu narokovat.
Pro pripad rucnich kompenzaci si samozrejme musis zalozit vlastniho uzivatele, s uctem, nabit ho z externiho, a pak delat az kompenzaci. Pripadne nabit muzes i dodatecne, pokud akceptujes zaporny zustatek u sebe.