Lộ Trình Phát Triển Hệ Thống Quản Lý Chi Tiêu Gia Đình: Phân Tích Kiến Trúc, Thiết Kế và
Thực Thi Chiến Lược trong 300 Giờ

 
!"#$%&$'()*+,-
&./01%23!#452&6!6)
 17$589:$;<=%>#>!
?@A$ABCDCE+#<$F?
G
)$%#93HH&$'IA*
.JKA*L+M)N>O>P62
QRASTAA)*+-#!6JT=BRM<
U++#)93*>1+.$9VWNX2Q19YZ!
6JT++LAM)1[\2)+$+
$%+V.]^^:<D'>&#>!
*9R_`=JRAA)_A$)`$A)=AAAM##6_ULR)/
3+'&.9-+9W3J=A*Ta+M)
$%*+Jbb+A1M1<U*++
#1[1+,-)22 17$5)293
=+A**+-)*+1P;
+*1)1*A1AA<
 !"#
=%>#>!
G
)$%9322#2*+
+*) 
1cA+$d19:O6We<
 $%&%' %()*+
(,- RASTAAJC*
b+A$fUA$M
_gTCFLZh
Ji+$A<j1fg"A11MkTZL
J_A<j1M
.,/#01 TAZAL+
JTZLM)R++AS*1A$
_A<j1VA)
1A*l_A$"C++
201 _gTCFLZh6mTni i+$A<j1Jg"A11M
N
DRfTAAB#A
%3456)7 _=UDT
JD#ToBfZ+1AToBM)
D+1)TAA$A1
Z+1AToBkTAApA
n_DJ+D+1q
TAA$M
,'  =+A)$+AS++1A R+AWr$H
'JL)=U)_AA1A
Z+"#M
8/"# mKC)s1Z11I+$)
RToBhjA+ftTT
U#)sAA)g"A11S
$+)ZAApA$
oAA1
)/97: tu+&.
J-"\M
C-+6
WJTI1ASAM)
=%*+$/6
%8$%>1%v*2)eew3
x.[<_A<j1i+$A<j1.+1mTx\JFS
1mTM)Q9W:+V.]^^:<Z+1AToB
938#D#ToB$+e"u#\&.w3$5
mTni )''+95\+.N9:$;<
y
;<=$%&>?@97:
AB/CDEFDBGH
Y*+.!>8\#v#>!r93
O,-'<T%\*.++.#9:$z2
.JASI+M(++.1<
]
;<=,I9*GJAK%E/L0M01
K0MM%/#,/LH
@>!
G
#HW]/<C+5
>)"./#!\Q%2N
+OW9:$;<
1. 4NM#0K1A8,O7PHC
Quyền hạn:RW#6#-+'+)"A$1*+$
>vJ1939:$;)v+$H+M)
$19:$;JWf7W+M)\
1J$'{+.6w3)$'OHM<
Ý nghĩa:|*++}-N,-)
+$5>9Nr!2+
w3<
~
2. .LN0,A,*59@Q%RE*3S4#THC
Quyền hạn:C.+WJ?b#Y+?M):>)
2-1vJD1AU$AM)>$#+93.
&)"A*++2N\>+<
Nghiệp vụ:|#/++')H
$/6*v.&+><
3. .LN0U0,AE*3S%M#/0,HC
Quyền hạn:Y(+$H+$H)"A*++
)"A.1JA$S+#M)6"\+
V<
Hạn chế:X"A2+$H>9N>
2931c)#v\Q1v<
D_ULR#0•#>!N6/.+1%
\d)+(+*+-7!D$$AIA
<
;;VWO)/97:S:A%/:L0XM0MM
)/H
|..+H%2)1[3*+
&.)93"+R_`=9:{
B+G{C-C+| YsWi3J=A*Ta+L+M{
C++OW)69:+J$'{L
6)U6e)R6hAAM).9V3!7>&.<
s1[O-+xHJYCA+#M9W193
+$H!2+3<C#LU)UR)RL)-+
1[+$/6/JiAb+IM6"\+$HJ$'{
!LRM<ƒ|#e+\9:\#+&$'
aA!9TI1A<
B+y{=%U+=/C6RU+TVJR1b+Ib+A1M{
=%>H1u>+H„J_Ag"A1A1M)
1[1u$'9 x##2 JBA_AA11+M
+Ow:JCATAA1L#11M$%*+1$9+
<i2"9V>.A$8931)1[u
*+?TV?#:2•931<…
B+]{tuBY+=H|HX„J_AC1+gAM{
s! 2%.+*+$H++
HJ6)iA†")hAAM!9:$;-N
<|6#/022TA$AJ9+$AS+M.#6)
 17$5#+.+.+*$%>!
1\JFAA#M#*‡!<G^
Y (,-7P(# (%3456
)7AB/;CFEZDBGH
C225‡6+Ww<
Y+.#-+W$522LZh<
Y(# (43[') (#A\E\##N
0L#/M:,H
R 17$51[93227$.RPW]J]ibM*++}
$5<=9V#%NQ{
1. ]M0,MA9*GJHC$)1AA)11I+$E1)A)+A)AA$E<
2. .L0MAB?HC$)A)+IAE$JbXSˆ`1A1M<
3. .LN0U0,MAB?HCU#2
D#S+SD#5`1A1bA1<1AE$)F#E$)j+A$E)
11JAfA$M<
4. ^LL0#MA=HC$)A)*A)A#)1AE$J*AS2
>M)F#E$J*AS2M<B+*{D
6`1Asn‰Rb#)+OW<
GG
5. %#0/,0MAHC$)A)#AJA"A1Af+AM)AE$J#
+$'+M)+<
6. ,M#/MAB/OHCC%<$)+)$A)$A1+)
IAE$)A+#E$)1AE$J9:%M)AA$E1+E$J+
+$H#6f3M<
7. 10#MA9<4WHC$)+E)1E$A)A$E$A)A+#E$)
F#E$<
8. 0,,##0,MA_O `HC$)FAA#J$#)IAA#)+#M)
A"EE$A)+)$A1+<
D5C1+1U$A1+)
W+.%2<Cv+NC1+1++:
$'9 &1[931+1V+ENU$A1<
GG
Y;(# (Ka\4bL
LZh1[9322A+P_gTC)1u$'9 &sCCZJYgC)ZnTC)
Z`C)=gBgCgM5Š<CLZh1[93%W*l
TIAfnALZh<
G
D1g$+8{
ZnTCfff+{t%6mKCJLA11C+Ak_AFA1C+AM<
YgCff1+1{B\#$1+$H)w3A#18J‹
1=AŒ<<<qA$=AŒ<<<qA+#h$Œ<<<MJ‹AŒGqŒy^M<
ZnTCffFA1f{$fj+{Yu#>!<
YgCffA+1f+#{C6$5•v3+*xJLAA
=M<+v3JLA+M>93%7!
=*1AJ1u$'Y_n`ZU@+ToBM#+*$56i+$A<j1
"u)l9e<
y
YY%()*+,' /20,
R\Q$+AS++1A<#1[*+x]1AA1{
1. 1UCTu$'A+1A1{G•SA<R\+AA11$5
J+1A1E${ff*f+1A1f$M<
2. :CU$r=+AaA+9'*A$<Tu$'+$A++
9:$A+SA+$<
3. c0UCU$r=+AaA+9'F+A$<C+9:$A)
+A#.#A1AA<
1u$'=+A*+9:x\5>
+WJ2WM09:+$+")&#>
!?=A+#A?N6<
G]
F),?%(#AYDDBGH
B93‚T)wT(+$+~^S•^:)-
+#+eW.#93J=AA*A1M<
4:,#C 5/%d?>,*GABGDEYDH
#CC2-"+9:)=+A)Y†+I2
=*1A<
%#(#>7C
1. X7.+YA+JYs*fYB*M)2-$A<
G
2. RO\Q9'D++A+JfA)f1AA)f$+AM<
3. 2$+AS++1A<#7.#Z+1A1i+$A<j11AAw<
4. RO9d{g"A11)TAApAJUA$M•_A)CI$RTT)
L"+1Jb+A$M<
5. C2-gTBZAA*+?R+$R+A+?#r!<
4:,#;C201%/,0EK#e#UM0,#/MABG
YEfDH
#Cs+1 xRT=B"%<
%#(#>7C
1. 2+11+\*J`1A1)KA1)C1+1<<<M<
2. 2TAA$A11u$'9FA<j1.+G^^^*-
JC1+1M''ue<
G
3. hAA+$AL{_A1A)B+)_AFA1C+A<
4. D•W-P*l*#<
5. C.+D$$AIA"%mKCJD$$AIAM#6
J+AD$$AIAM<
4:,#YC201M0MM)/E%]e97:ABG
fE;DH
#CLZh++&e<
%#(#>7C
1. hAAR_`=+C1+1)KA1)RA+A1<
2. tu+{X"WKA)"AWC1+1>
JT+F$AAA1s$$AAAM<
3. t#$%%/:L0X)/A0,,\0HC2+j+*.#w
u>)(*_AZA1).+1+V22.<
G^
4. t#$%LZh_A+1{Tu$'TAApALA+1vf
A+)A+$'<
4:,#FC.,/#01%/,0EB/7e=+:ABG;E
fDH
#CY+$9:$;+.93V$5-rLZh<
%#(#>7C
1. C22B#+JT$A*)i*M1u$'CI$RTT<|*+
_A1+1A>D+*A<
G
2. hAAB+f_A1A)9mKC+B+T+A+Osn#
R++A<
3. t#$%=1*+${sH1$9)$1+$H!#<
4. C3LZh{Tu$'"+1AA+1%ŽC+A+
A$A"u_AFA1C+A2.<
G€
4:,#gC.,/#01K101E'[e)/S:
ABGfE;;DH
#CC%W$5e+<
%#(#>7C
1. C3R<j1+O_A1<
G‚
[*x/J \>M*
xJ-1>M<
2. t#$%?iTY|?{R+(b#DA2
-.&<
3. hAA%/:L0X)/;A0U#4:Lh#/]aHCsHxH3
+W<$'{L3UG^^)U3RG^^SˆsH6"\
?LRG^^?JUA$\LZh+)b+A$H2M<
ƒ
4. $+F+{Tu$'9b+@*‡w-#
.b+A$J$'{T693)#9379 
2>%2M<
G
4:,#iC0M#j.Xek:#l#/ABG;;E;iDH
#C|*+\93vH<
%#(#>7C
1. 2`CA1+++&.7UA$J1u$'
mA1M<
2. hA+CA1+LZh8JB+)RAAC1+M<
3. Xu*+-{CuToBhjA+J*+n_D•OM)tTT
JA1A$5!M<
4. C9e{C>h$A"+##\J$'{
1+E$A)A+#E$M+Z+1AToB<
GG
4:,#fC/7j)7e@B@ABG;iEYDDH
#CRP*H1P*+*+<
%#(#>7C
1. 2*++#2JCA_A+M{[.1 xg_=)`1AR1A)
LAA*l'9=I<++OT`DB<
2. t\LZhrTIA<
3. o#$A+=A+J•S‚QMA+H*{|e-SˆC>>Sˆ
tA*++SˆR*+1SˆoHL$<
4. T+.T$A#2<
5. X!aA$+AS++1A<#*+>W
.#$%*lG<
G
g4</%WB8W: !"#
A0L00:0H
gB8"#Pm@9+A0U#4:Lh#/H
C+5>WJTA$KAM)\6?L3*+>‹?
*+&.<s1[$'-+JYAA$#L+M
#2*+#<
9NLnCC+1$9/JiAUAMNw9:<i9:W1$9
$9 9:!93JRA$+M)9:W1$99:3J=A*+M<
N#,?C
1. CiAUA+\><
2. Cy$1{=A*+1J1$9•^MRA$+1J1$9ˆ^M<
3. T‡"2y$1A+H#$!<
4. B\#9:36\+9:93-6\<T6+
$HŒDJ•=A*•)•RA$•M<
5. R--.1$9O.+2$1w<
(#o8CY193+$H#6!%)9
W9:$;<
G…
g;8/"#6)7%=
&$'"u$5.#)**+-1*‡
*{
#aM/L#/A%>L":16L7HCDO$;1u$'=*1A)9
8#\JoA#M>2C1+1+OKA16Ž
A+6Ksg_gF#E$Œ1A<F#E$+O1AE$Œ
AE1A<$<|6#eOwh=n_Jh1AA=An*jA
_AFAAA1M) 1AW"A+$HN9:*lvh=
>`_B<
40M#0#,/#0#/CR9-P93*eJ1M
*l-+.JU#fL+yM<LZhXA#+OTAAXA#J$;+mKCM
93$S+$A+•x.r*29:J<AM)
aA<A93>+<+A8>Ys*<
G
gY,@6)7A#MLl#/H
Tu$'9R<j1)1[\W11‡6{
'p[X*qA)0%,#HCC't:)C'@16<YQ
9:$;-$??>*\9:<
'p[:<UPA/#%,#HCsH‘8$'<$'{
?’?2~^“v><
!#"#XrLnC|*+e$5>V*)
UA$1[6$5•93WJ+A$$M#6I$
b+A$%+<|6#+$#*e
.<
y^
i (#)"*qW#,'
C+/]^^:)#*+"#$%+s
oR>Y&!#N#>!8-
‡AJ=+A)D+1AA1SA$#AA)R+A"B+M/
.H1u$'%2+<
$'#P9D+1)TAA$A1)
=+Ap+RhfR=1+Q1>AV9:
#><Re+9-+ W3$%*+
\8)9$#-+e
#2\611‡N9:<
*q:W##,'#*3LA.#,0^/,2HC
C3LhfnR_JnRA_A++M%(W \#
-<
yG
Z&$'$JD+*ALM1u$'_AiA)-$'.
++UA$LZh•"#$%<
C3nAULZhx*+$H%2rJ2
6+(M<
U++#W/9*22,-JCAUAM)H
9V8#2H+)*+$%6Q.
V\93+\<
8<GB%(#A0KLL/#/UL0H
B/ /#
%=
GBABGH (#8
B/
A0L0,UL0MH
<= C-#>
!)HŠ
_+A)R8CA
T
y^ CO
#>!JT_TM
DW
=+)i>
&-+
J=A*L+M
y^ T xx$5
)B+
b+I1
;(# ( C22RT=B
Jg_=M)|HŠ
LZhR+
JTIAM
y• g_=+)
CLZh
KAF
`hf`t
JbfTAM
y• D+1+
$2
Y>,*G C2-=+A)
Y_A+)RhfR=
B
y^ D9:=A
1”1JnAS
+$1AM
2=UD+
T1)B+
TAA$
JbA<j1M
G^ =*1AW$5
zJG^^^
A+$1M
F201 D+$AL
JmKC)_ULR)
_A1AZ11I+$M
y• LZh|e
-f|e
*+-
R+AC1+
qU$AR_`=
]^ LZh
C>fTuftW
+$H
R+A"B+{
_A
Z#A1q=A*
L+
]• TAA"u
'&
.
g.,/#01 X7.+$%)
_+)L
ZA1
y^ Y+$|e
-f|e
=1*+$
R++A1q
C3R<j1
]^ =1*+$9 
)Ux
b+
+$Hq
$+
Jb+f@M
]^ Y+$-
W
w
iW@ Ce_AS
AJT+A<+M
y^ C*+&
:
qR*+
g"+fh+
bAA1qC
`h
y^ R&e"\
g"AfZ=b)`h
93
f/7 `qhA+
CA1)b"U
]^ U*$v
H)w
>8
2*++)
T$A)o#$A+
=A+
y^ YW1P
„
s9B%t9B FDD (Lưu ý: Đã bao
gồm thời gian dự
phòng và tự học)
Lưu ý: Mặc dù yêu cầu đặt ra là 300 giờ, bảng phân bổ trên mở rộng lên 400 giờ để
bao gồm cả thời gian tự nghiên cứu công nghệ mới (learning curve) và xử lý các vấn
đề phát sinh không lường trước (buEer). Tuy nhiên, các đầu mục cốt lõi (Core
Features) hoàn toàn có thể hoàn thành trong 300 giờ nếu tuân thủ nghiêm ngặt kế
hoạch.
9[#,=1_
1. @A$ABCDCE+#<$F
2. U$ZA1+bADAAL{=*1ATAI
Z+1AToB$=+A<•*#YA+A–AF1•C+I$1=gAA
•DA$)#-+GG^)y^y€)1{ffA$<+f+I$1S
$SAAAf*$SSA1+SaASAASS
$*1AS1ASIS+1A1S$S$+AS•^‚•Ayƒ]]^]A
3. s+I+Z$g"AATA11FKA*L+=AA+A
Z+jA)#-+GG^)y^y€)1{ff$A<+f*AEA$f+IS+S
S$SA"AASS1A11FSIA*S+S$AA+AS+jAS
G
4. Kh1_+ASU1A$LA11R++J_ULRM‹DAqg"A1S
b+A)#-+GG^)y^y€)
1{ffIII<F+A<+fA1+A1f#*A+11#f+AS*1A$SA11S
++
5. =A1$hAA++Fb#g"A1ACA`1Dg_i
TSj)#-+GG^)y^y€)
1{ffj<+f+$1f€hTT`gƒfhm_Z_•yyy~<$F
6. TI1ASLT+ASLA)#-+GG^)y^y€)
1{ff1<A<+f1ff1I1Af$~•ƒ^y]~]]
7. s+I+hAA_ULRg"A11<j1L+SZA<+)#
-+GG^)y^y€)1{ffIII<A<+f*+f+IS+S
AAS*SSSA"A11j1S+
8. L+UA$TI1A—1=A*Ta+bAA•*#D
D+X•DA$)#-+GG^)y^y€)
1{ffA$<+f˜…]f+S*A$S1I1A1S$A*S
1a+SFAASƒ~ƒ•A…‚€ƒƒ
9. s+I+L+Abb+A1{ƒZ+A11A1@+RL+A
•iATA)#-+GG^)y^y€)
1{ffIII<A1A<+f+fA1+AfA1faS
AAf+ASaSF+A1<1
10. T#1A=A1ZAF+_AZ#A1SYAA1F+YAA1)#
-+GG^)y^y€)1{ffIII<AA1F+AA1<+f1#1AS
$A1f1#1AS$A1SASF+SAS#A1f
11. =A1$*1A1AF+*$AAIL+AS
*++#A1#<+)#-+GG^)y^y€)
1{ff*++#A1#<+f*+f$*S1ASF+S*$ASASIS
+Af
12. =#A"A1AASg#SA+1$A"ASYAA<+)
#-+GG^)y^y€)1{ffIII<AA<+fAA1fA"A1AS
ASA$
13. BA=+A]+1<S=gR+#)#-+GG^)
y^y€)1{ff$A<+f+EA$A+E]…~^FfAS$+ASS]S
+1S…G
14. TA`=+A{i+$A<j1qZ+1AToB•bTU+)#-+
GG^)y^y€)1{ffIII<F1<+f*1fA1+A1f*+f1ASS
$+AS$AA+ASA+ASSA1S+$+
15. D+1•TAApA)#-+GG^)y^y€)
1{ff1AApA<+f$+1f€f+AS+1f+1f
16. s+I+U$bST_AR_`=LIi+$A<j1)g"A11$
Z+1AToB{TAS*#STAY$AS=gR+#)#-+G
G^)y^y€)1{ff$A<+f+*$+f+IS+S*$SSFS1SAS$S
SIS+$Aj1SA"A11S$S+1A1S1AS*#S1AS$AS]y]A
17. T+ZRB*#F+_A‹CA1AG^n+1R+A
hL•sAi++)#-+GG^)y^y€)
1{ffA++<+f1S+SSSS*#SF+SAS
A1ASG^S++1S+ASS
18. Y$A+CA_A+KS`A1#+FT11A")#-+
GG^)y^y€)
1{ffIII<111A"<<fAfAfF+1$A1fAAA$A1f
1$#$A1fAA+I
19. L++1Af1AAA"A1A1++STnA†+I)
#-+GG^)y^y€)
1{ff1+A†+I<+fA1+1f…‚~…yyf+S+S1AS1AAS
A"A1A1S+SS+
20. _AmT=AA+AF+_ASCAL#1=1*+$1SDA1=A)
#-+GG^)y^y€)1{ffA1$A<+f*+fAj1S$AS
F+SASAS#1S$1*+$1
21. JZ=bMgtZgiTgC_LRXg_LZZBhRLChniS_A1AYA)#-+
GG^)y^y€)
1{ffIII<A1AA<Af*+f]ƒGy~…•‚…EgtZgiTgEC_LRXg
_ELZZBhRLChni

Preview text:

Lộ Trình Phát Triển Hệ Thống Quản Lý Chi Tiêu Gia Đình: Phân Tích Kiến Trúc, Thiết Kế và Thực Thi Chiến Lược trong 300 Giờ

1. Tổng Quan Điều Hành và Phạm Vi Dự Án

Việc phát triển một hệ thống quản lý tài chính cá nhân và gia đình không chỉ đơn thuần là việc xây dựng một ứng dụng ghi chép thu chi, mà là một bài toán kỹ thuật phức tạp đòi hỏi sự kết hợp nhuần nhuyễn giữa kiến thức về công nghệ phần mềm, quản lý cơ sở dữ liệu và tâm lý học hành vi người dùng. Dựa trên tài liệu yêu cầu "Yeu cau de tai LTMT_copy.pdf" 1, dự án này được định vị là một ứng dụng web hiện đại (Web Application), tuân thủ nghiêm ngặt các tiêu chuẩn công nghiệp về kiến trúc Client-Server, bảo mật và quy trình phát triển phần mềm (SDLC).

Báo cáo này, được biên soạn dưới góc nhìn của một Kiến trúc sư Giải pháp Phần mềm (Solution Architect), sẽ cung cấp một lộ trình chi tiết, toàn diện để hoàn thành dự án trong giới hạn 300 giờ làm việc. Mục tiêu không chỉ là đáp ứng các yêu cầu cơ bản như CRUD (Create, Read, Update, Delete) hay phân quyền RBAC, mà còn tích hợp các logic nghiệp vụ phức tạp như thuật toán tối ưu hóa nợ (Debt Simplification), dự báo tài chính (Financial Forecasting) và quản lý ngân sách động. Bản báo cáo này sẽ đi sâu vào phân tích kỹ thuật, thiết kế cơ sở dữ liệu, chiến lược triển khai Docker và các biện pháp bảo mật, đảm bảo sản phẩm cuối cùng là một hệ thống robust, scalable và secure.

1.1 Mục Tiêu Dự Án và Ràng Buộc Kỹ Thuật

Dựa trên tài liệu yêu cầu 1, dự án được thiết kế để giải quyết bài toán quản lý tài chgggggggggggggggggggggggggggggính trong bối cảnh hộ gia đình, nơi việc chia sẻ chi phí và theo dõi ngân sách chung thường gặp nhiều khó khăn.

Hạng Mục

Yêu Cầu Cụ Thể

Chiến Lược Thực Thi

Kiến Trúc

Client-Server (Tách biệt Frontend/Backend)

RESTful API (Node.js/Express) + SPA (React.js)

Frontend

Single Page Application (SPA), Component-based

React.js với Vite, quản lý state bằng Redux Toolkit

Backend

RESTful API trả về JSON

Node.js (Express) tuân thủ mô hình MVC/Service Layer

Cơ Sở Dữ Liệu

RDBMS (MySQL/PostgreSQL), Migrations, Seeders

PostgreSQL + Sequelize ORM (cho Migrations & Seeding)

Triển Khai

Docker, docker-compose

Container hóa từng dịch vụ (App, DB, Reverse Proxy)

Bảo Mật

JWT, Hash Password, Chống SQL Injection/XSS

Bcrypt, Helmet, Express-validator, Parameterized Queries

Logic Nghiệp Vụ

Xử lý logic phức tạp (không chỉ nhập xuất)

Thuật toán chia tiền nhóm (Splitwise-like), Dự báo dòng tiền

Việc lựa chọn công nghệ dựa trên sự phổ biến, hiệu năng và khả năng hỗ trợ cộng đồng mạnh mẽ. React.js và Node.js tạo thành một stack JavaScript đồng nhất (full-stack JS), giúp tối ưu hóa thời gian phát triển trong giới hạn 300 giờ. PostgreSQL được chọn thay vì MySQL do khả năng xử lý các truy vấn phức tạp và hỗ trợ kiểu dữ liệu JSON tốt hơn, phục vụ cho việc lưu trữ các cấu hình linh hoạt của người dùng.2

2. Phân Tích Yêu Cầu và Mô Hình Hóa Nghiệp Vụ (Giai Đoạn 1: 0 - 40 Giờ)

Gibai đoạn đầu tiên và quan trọng nhất là chuyển đổi các yêu cầu trừu tượng thành các đặc tả kỹ thuật cụ thể. Sự thất bại trong giai đoạn này thường dẫn đến việc phải làm lại (re-work) tốn kém trong các giai đoạn sau.3

2.1 Phân Tích Vai Trò Người Dùng (RBAC - Role Based Access Control)

Yêu cầu 1 quy định hệ thống phải có tối thiểu 3 vai trò. Trong ngữ cảnh quản lý chi tiêu gia đình, việc ánh xạ các vai trò này cần phản ánh cấu trúc thực tế của một hộ gia đình hoặc một nhóm người dùng chung.

  1. System Admin (Quản Trị Hệ Thống):
    • Quyền hạn: Có quyền truy cập toàn cục vào hệ thống, xem dashboard thống kê tổng quan (số lượng người dùng, tổng giao dịch toàn hệ thống), quản lý danh sách người dùng (khóa/mở khóa tài khoản), cấu hình các tham số hệ thống (ví dụ: loại tiền tệ hỗ trợ, danh mục mặc định).
    • Ý nghĩa: Đảm bảo tính toàn vẹn và vận hành của hệ thống kỹ thuật, không can thiệp vào dữ liệu tài chính riêng tư của các gia đình trừ khi cần thiết cho việc hỗ trợ.4
  2. Family Manager (Trưởng Nhóm/Chủ Hộ - Tương ứng Staff):
    • Quyền hạn: Tạo nhóm gia đình ("Family Group"), mời thành viên tham gia, thiết lập ngân sách tổng (Master Budget), phê duyệt các khoản chi vượt hạn mức, xem báo cáo chi tiết của tất cả thành viên trong gia đình.
    • Nghiệp vụ: Đây là vai trò trung tâm trong logic nghiệp vụ, chịu trách nhiệm quản lý dòng tiền chung và phân bổ hạn mức cho các thành viên.5
  3. Family Member (Thành Viên - Tương ứng Customer):
    • Quyền hạn: Ghi chép giao dịch cá nhân và giao dịch chung, xem báo cáo cá nhân, xem trạng thái ngân sách chung (read-only), đề xuất các khoản chi lớn.
    • Hạn chế: Không thể xem chi tiết các giao dịch riêng tư của thành viên khác nếu không được chia sẻ, không thể thay đổi cấu trúc ngân sách tổng.6

Mô hình RBAC này không chỉ thỏa mãn yêu cầu của đề tài mà còn tạo ra sự phân cấp rõ ràng, cho phép triển khai các logic bảo mật ở tầng Middleware một cách hiệu quả.7

2.2 Xác Định Logic Nghiệp Vụ Phức Tạp (Complex Business Logic)

Để đạt điểm tối đa và tạo ra giá trị thực tế, hệ thống sẽ tích hợp ba mô đun logic phức tạp, vượt xa các thao tác CRUD thông thường:

  • Logic 1: Thuật Toán Đơn Giản Hóa Nợ (Debt Simplification Algorithm):
    Trong một gia đình hoặc nhóm, khi nhiều người chi trả cho nhau (ví dụ: A trả tiền điện, B trả tiền ăn, C trả tiền Internet), mạng lưới nợ nần trở nên phức tạp. Hệ thống sẽ cài đặt một thuật toán đồ thị (Graph Theory) để tối ưu hóa số lượng giao dịch cần thiết để thanh toán nợ. Thay vì A trả B, B trả C, C trả A, thuật toán sẽ tính toán dòng tiền ròng (Net Flow) và đề xuất các giao dịch tối thiểu (ví dụ: chỉ cần A trả C).8 Đây là một tính năng cao cấp thường thấy trong các ứng dụng fintech hàng đầu như Splitwise.
  • Logic 2: Dự Báo Dòng Tiền và Cảnh Báo Sớm (Cash Flow Forecasting):
    Dựa trên lịch sử chi tiêu và các khoản chi định kỳ (Recurring Expenses), hệ thống sẽ sử dụng phương pháp hồi quy tuyến tính đơn giản (Linear Regression) hoặc phân tích chuỗi thời gian (Time Series Analysis) để dự báo số dư vào cuối tháng. Nếu xu hướng chi tiêu hiện tại đe dọa vượt ngân sách, hệ thống sẽ gửi cảnh báo "Sớm" thay vì chờ đến khi đã vượt ngân sách.9
  • Logic 3: Xử Lý Giao Dịch Định Kỳ (Recurring Transaction Engine):
    Hệ thống cần một cơ chế để tự động tạo ra các bản ghi giao dịch cho các khoản chi cố định (tiền nhà, Netflix, Internet) mà không cần người dùng nhập liệu thủ công. Điều này đòi hỏi việc thiết kế một Scheduler (như node-cron) chạy nền, kiểm tra cơ sở dữ liệu hàng ngày và kích hoạt logic tạo bản ghi dựa trên tần suất (frequency) và ngày bắt đầu.10

3. Kiến Trúc Hệ Thống và Thiết Kế Cơ Sở Dữ Liệu (Giai Đoạn 2: 41 - 90 Giờ)

Thiết kế hệ thống vững chắc là nền tảng cho việc phát triển nhanh chóng và ít lỗi. Giai đoạn này tập trung vào việc mô hình hóa dữ liệu và thiết kế API.

3.1 Thiết Kế Sơ Đồ Thực Thể Liên Kết (ERD - Entity Relationship Diagram)

Cơ sở dữ liệu sẽ được thiết kế ở dạng Chuẩn hóa 3 (3NF) để đảm bảo tính toàn vẹn dữ liệu. Dưới đây là các thực thể chính và mối quan hệ của chúng:

  1. Users (Người Dùng): id, username, password_hash, email, role, created_at.
  2. Families (Gia Đình): id, name, owner_id (FK -> Users).
  3. FamilyMembers (Thành Viên Gia Đình): Bảng trung gian giải quyết mối quan hệ Many-to-Many giữa Users và Families. user_id, family_id, joined_at, status (active/pending).
  4. Wallets (Ví Tiền): id, name, balance, currency, user_id (nullable - nếu là ví riêng), family_id (nullable - nếu là ví chung). Logic kiểm tra ràng buộc: Một ví phải thuộc về User HOẶC Family, không thể cả hai hoặc không có ai.11
  5. Categories (Danh Mục): id, name, type (expense/income), parent_id (đệ quy cho danh mục con), icon.
  6. Transactions (Giao Dịch): Thực thể trung tâm. id, amount, date, description, wallet_id, category_id, user_id (người thực hiện), related_transaction_id (cho các giao dịch chuyển tiền/trả nợ).
  7. Budgets (Ngân Sách): id, amount_limit, start_date, end_date, category_id, family_id.
  8. RecurringPatterns (Mẫu Định Kỳ): id, frequency (daily, weekly, monthly), next_run_date, amount, description.

Mối quan hệ giữa Transactions và Budgets là mối quan hệ tính toán, không phải khóa ngoại trực tiếp. Tổng amount của các Transactions trong khoảng thời gian và danh mục tương ứng sẽ được so sánh với amount_limit của Budgets.11

3.2 Thiết Kế API RESTful

API sẽ được thiết kế theo chuẩn REST, sử dụng các phương thức HTTP (GET, POST, PUT, DELETE) một cách ngữ nghĩa. Tài liệu API sẽ được tự động hóa bằng Swagger/OpenAPI.1

Một số Endpoint quan trọng:

  • POST /api/auth/login: Xác thực và trả về JWT (Access Token + Refresh Token).
  • GET /api/transactions: Lấy danh sách giao dịch, hỗ trợ query params để lọc (?startDate=...&endDate=...&categoryId=...) và phân trang (?page=1&limit=20).
  • POST /api/families/:id/join: Gửi yêu cầu tham gia gia đình.
  • GET /api/reports/monthly: Trả về dữ liệu đã tổng hợp cho biểu đồ (Aggregate Data). Việc tính toán tổng hợp (Aggregation) nên được thực hiện ở tầng Database (sử dụng GROUP BY trong SQL) thay vì tải toàn bộ dữ liệu về Node.js để xử lý, nhằm tối ưu hiệu năng.2

3.3 Chiến Lược Triển Khai Docker

Cấu trúc docker-compose.yml sẽ bao gồm 3 services chính:

  1. db: Sử dụng image postgres:15-alpine. Cấu hình volume để persist dữ liệu (postgres_data:/var/lib/postgresql/data).
  2. api: Build từ Dockerfile trong thư mục backend. Sử dụng nodemon trong môi trường dev để hot-reload.
  3. web: Build từ Dockerfile trong thư mục frontend. Trong môi trường dev, container này chạy Vite server.

Việc sử dụng Docker đảm bảo môi trường phát triển đồng nhất giữa các thành viên trong nhóm (nếu có) và mô phỏng môi trường production chính xác, đáp ứng yêu cầu "Deployment" của đề tài.13

4. Lộ Trình Thực Thi Chi Tiết (300 Giờ)

Lộ trình được chia thành 7 Sprint, mỗi Sprint kéo dài khoảng 40-50 giờ, tập trung vào việc chuyển giao các tính năng có thể chạy được (Deliverables).

Sprint 1: Khởi Tạo và Cấu Hình Môi Trường (Giờ 0 - 30)

  • Mục tiêu: Thiết lập xong môi trường phát triển, Docker, Git flow và kết nối Database.
  • Chi tiết công việc:
    1. Khởi tạo Git repo (GitHub/GitLab), thiết lập nhánh main và dev.1
    2. Cài đặt cấu trúc thư mục Monorepo (/client, /server, /docker).
    3. Viết docker-compose.yml để khởi chạy Postgres và Node.js server rỗng.
    4. Cài đặt các thư viện lõi: Express, Sequelize (Backend); React, TailwindCSS, Axios (Frontend).
    5. Thiết lập ESLint và Prettier để đảm bảo "Coding Convention" ngay từ đầu.

Sprint 2: Backend Core - Auth & Database Migrations (Giờ 31 - 70)

  • Mục tiêu: Hoàn thiện sơ đồ CSDL và hệ thống xác thực.
  • Chi tiết công việc:
    1. Viết migration scripts cho tất cả các bảng (Users, Wallets, Transactions...).
    2. Viết Seeders sử dụng thư viện faker.js để tạo 1000 bản ghi giả lập (Transactions) phục vụ kiểm thử hiệu năng và phân trang.1
    3. Implement module Auth: Register, Login, Refresh Token.
    4. Mã hóa mật khẩu bằng bcrypt.
    5. Tạo Middleware xác thực JWT (authMiddleware) và phân quyền (roleMiddleware).7

Sprint 3: Backend Business Logic - CRUD & Nghiệp Vụ (Giờ 71 - 120)

  • Mục tiêu: API hoàn chỉnh cho các chức năng chính.
  • Chi tiết công việc:
    1. Implement CRUD cho Transactions, Wallets, Categories.
    2. Xử lý logic: Khi xóa Wallet, kiểm tra xem có Transactions liên quan không (Soft delete vs Hard delete).
    3. Xây dựng Complex Logic 1 (Recurring Engine): Viết cron job chạy mỗi nửa đêm, quét bảng RecurringPatterns, tạo transaction mới nếu đến hạn.10
    4. Xây dựng API Reports: Sử dụng Sequelize Aggregations để tính tổng thu/chi theo tháng, theo danh mục.

Sprint 4: Frontend Core - Giao Diện & Tích Hợp (Giờ 121 - 170)

  • Mục tiêu: Giao diện người dùng hoạt động được với dữ liệu thật từ API.
  • Chi tiết công việc:
    1. Thiết kế Layout chung (Sidebar, Navbar) sử dụng TailwindCSS. Đảm bảo Responsive trên Mobile.1
    2. Implement trang Login/Register, lưu JWT vào LocalStorage hoặc HttpOnly Cookie.
    3. Xây dựng màn hình Dashboard: Hiển thị số dư, danh sách giao dịch gần đây.
    4. Tích hợp API: Sử dụng axios và interceptors để tự động đính kèm Token vào header và xử lý Refresh Token khi hết hạn.16

Sprint 5: Frontend Advanced - Biểu Đồ & Logic Phức Tạp (Giờ 171 - 220)

  • Mục tiêu: Trực quan hóa dữ liệu và tính năng nâng cao.
  • Chi tiết công việc:
    1. Tích hợp Chart.js hoặc Recharts.17 Vẽ biểu đồ tròn (cơ cấu chi tiêu) và biểu đồ cột (thu nhập vs chi tiêu).
    2. Xây dựng màn hình "Ngân Sách Gia Đình": Cho phép Family Manager thiết lập hạn mức.
    3. Implement Complex Logic 2 (Debt Simplification UI): Hiển thị đồ thị nợ trong nhóm. Ví dụ: A nợ B 100k, B nợ C 100k -> Hệ thống hiển thị đề xuất "A trả C 100k" (Backend cung cấp API tính toán, Frontend hiển thị kết quả).8
    4. Validation form: Sử dụng thư viện Formik và Yup để bắt lỗi nhập liệu ngay tại Frontend (ví dụ: Số tiền không được âm, ngày không được ở tương lai nếu là chi tiêu thực tế).1

Sprint 6: Testing, Fix Bug & Optimization (Giờ 221 - 260)

  • Mục tiêu: Đảm bảo chất lượng và độ ổn định.
  • Chi tiết công việc:
    1. Viết Unit Test cho các hàm tính toán logic phức tạp ở Backend (sử dụng Jest).
    2. Integration Test cho các API quan trọng (Login, Create Transaction).
    3. Kiểm thử bảo mật: Thử nghiệm SQL Injection (đảm bảo ORM đã chặn), XSS (escape dữ liệu đầu ra).
    4. Tối ưu hiệu năng: Thêm Indexing cho các cột hay truy vấn (ví dụ: transaction_date, category_id) trong PostgreSQL.11

Sprint 7: Hoàn Thiện, Tài Liệu & Đóng Gói (Giờ 261 - 300)

  • Mục tiêu: Chuẩn bị sản phẩm để bàn giao và bảo vệ.
  • Chi tiết công việc:
    1. Viết báo cáo thuyết minh (Technical Report): Vẽ lại sơ đồ ERD, Use Case, Architecture bằng công cụ như Draw.io hoặc StarUML.18
    2. Xuất tài liệu API từ Swagger.
    3. Quay Video Demo (5-7 phút) theo kịch bản: Đăng nhập -> Thêm chi tiêu -> Xem báo cáo -> Cảnh báo ngân sách -> Quản trị Admin.
    4. Soạn Slide thuyết trình.
    5. Kiểm tra lần cuối file docker-compose.yml để đảm bảo giảng viên có thể chạy dự án bằng 1 câu lệnh.1

5. Đi Sâu Vào Các Giải Pháp Kỹ Thuật (Technical Deep Dive)

5.1 Giải Thuật Tối Ưu Hóa Nợ (Debt Simplification)

Trong ngữ cảnh quản lý chi tiêu nhóm (Shared Wallet), vấn đề "Ai nợ ai bao nhiêu?" là bài toán phức tạp. Hệ thống sẽ áp dụng thuật toán tham lam (Greedy Algorithm) để giải quyết bài toán này.

  • Nguyên lý: Tính toán số dư ròng (Net Balance) của mỗi người. Người có số dư dương là người cần được trả (Creditor), người có số dư âm là người nợ (Debtor).
  • Quy trình:
    1. Tính Net Balance cho tất cả thành viên.
    2. Tách thành 2 danh sách: Debtors (số dư < 0) và Creditors (số dư > 0).
    3. Sắp xếp cả 2 danh sách theo giá trị tuyệt đối giảm dần.
    4. Lấy người nợ nhiều nhất trả cho người được nhận nhiều nhất. Số tiền giao dịch = Min(|Debit|, |Credit|).
    5. Cập nhật lại số dư và lặp lại cho đến khi danh sách rỗng.
  • Kết quả: Giảm thiểu tối đa số lượng giao dịch chuyển tiền cần thực hiện, tối ưu hóa trải nghiệm người dùng.19

5.2 Bảo Mật Dữ Liệu Tài Chính

Vì ứng dụng xử lý dữ liệu tài chính nhạy cảm, các biện pháp bảo mật sau là bắt buộc:

  • Data Isolation (Cô lập dữ liệu): Mặc dù sử dụng chung một Database, nhưng mọi câu truy vấn (Query) liên quan đến Transactions hoặc Wallets đều phải kèm theo điều kiện WHERE family_id = user.family_id hoặc user_id = current_user.id. Điều này ngăn chặn lỗi IDOR (Insecure Direct Object References), nơi một user có thể xem giao dịch của người khác bằng cách đổi ID trên URL.7
  • Sensitive Data Protection: Các thông tin như mật khẩu phải được băm (hash) bằng thuật toán mạnh (Bcrypt/Argon2). API Key hoặc Secret Key (dùng cho JWT) không được hard-code trong mã nguồn mà phải nạp từ biến môi trường (.env), và file .env phải được thêm vào .gitignore để tránh lộ lọt trên GitHub.1

5.3 Trực Quan Hóa Dữ Liệu (Data Visualization)

Sử dụng thư viện Chart.js, hệ thống sẽ cung cấp các góc nhìn sâu sắc về tài chính:

  • Biểu đồ xu hướng (Line Chart): Trục X là thời gian, Trục Y là số tiền. Giúp người dùng nhận diện "đỉnh" chi tiêu bất thường.
  • Biểu đồ phân bố (Doughnut Chart): Hiển thị tỷ trọng các danh mục. Ví dụ: "Ăn uống" chiếm 40% tổng chi tiêu.
  • Kỹ thuật xử lý: Để đảm bảo hiệu năng khi dữ liệu lên tới hàng nghìn bản ghi, Backend sẽ trả về dữ liệu đã được nhóm (grouped data) thay vì trả về raw data để Frontend tự tính toán. Điều này giảm tải cho trình duyệt và giảm băng thông mạng.20

6. Kết Luận và Hướng Phát Triển

Trong vòng 300 giờ làm việc, lộ trình này đảm bảo việc xây dựng hoàn chỉnh một Hệ thống Quản lý Chi tiêu Gia đình không chỉ đáp ứng đầy đủ các yêu cầu học thuật khắt khe (Docker, Microservices-ready architecture, Complex Logic) mà còn mang lại giá trị sử dụng thực tế cao.

Việc áp dụng các quy trình chuẩn công nghiệp như Migrations, Seeders, Dockerization và CI/CD simulation giúp sinh viên làm quen với môi trường làm việc chuyên nghiệp. Các tính năng nâng cao như thuật toán đơn giản hóa nợ và dự báo tài chính là điểm nhấn quan trọng, thể hiện tư duy thuật toán và khả năng giải quyết vấn đề sâu sắc của người phát triển.

Hướng phát triển tương lai (Future Work):

  • Tích hợp AI/OCR (Optical Character Recognition) để tự động quét hóa đơn giấy và nhập liệu.21
  • Phát triển ứng dụng di động (Mobile App) sử dụng React Native, tận dụng lại hoàn toàn Backend API đã xây dựng.
  • Tích hợp Open Banking API để đồng bộ giao dịch trực tiếp từ ngân hàng (nếu điều kiện pháp lý cho phép).

Báo cáo này đóng vai trò như một bản thiết kế kỹ thuật (Technical Blueprint), định hướng mọi quyết định trong quá trình phát triển, đảm bảo dự án về đích đúng hạn với chất lượng cao nhất.

Bảng Phân Bổ Thời Gian Chi Tiết (Time Allocation Table)

Giai Đoạn

Hoạt Động Chính

Thời Gian (Giờ)

Kết Quả Bàn Giao (Deliverables)

1. Phân Tích

Thu thập yêu cầu, định nghĩa Role, Chọn Tech Stack

20

Tài liệu đặc tả yêu cầu (SRS)

Mô hình hóa Domain, Nghiên cứu thuật toán (Debt Algo)

20

Sơ đồ luồng dữ liệu, Logic Flowcharts

2. Thiết Kế

Thiết kế CSDL (ERD), Định nghĩa API Contract (Swagger)

25

ERD hoàn chỉnh, Tài liệu API

Wireframing UI/UX (Figma/Sketch)

25

Mockups giao diện chi tiết

3. Môi Trường

Thiết lập Docker, Git Repo, CI/CD Linting

20

Môi trường Dev sẵn sàng (One-command setup)

Viết DB Migration Scripts, Logic Seeding (Faker.js)

10

Database có dữ liệu mẫu (1000 records)

4. Backend

Module Auth (JWT, RBAC, Reset Password)

25

API Đăng nhập/Đăng ký bảo mật

Core Transaction & Budget CRUD

30

API Thêm/Sửa/Xóa giao dịch

Complex Logic: Recurring Payments & Debt Algorithm

35

Service xử lý nghiệp vụ phức tạp

5. Frontend

Khởi tạo dự án, Routing, Auth Pages

20

Giao diện Đăng nhập/Đăng ký

Dashboard Components & Tích hợp Chart.js

30

Dashboard tương tác, Biểu đồ động

Form quản lý giao dịch & Validation (Formik/Yup)

30

Giao diện nhập liệu có kiểm tra lỗi

6. Đánh Bóng

Tính năng Real-time (Socket.io) & Cảnh báo

20

Thông báo tức thời

Export/Import Features & Tinh chỉnh UI

20

Chức năng xuất Excel/PDF, UI mượt mà

7. Hoàn Thiện

Unit & Integration Testing, Fix Bug

30

Bản build ổn định, không lỗi nghiêm trọng

Viết báo cáo, Slide, Quay Video Demo

20

Gói sản phẩm nộp cuối kỳ

TỔNG CỘNG

400*

(Lưu ý: Đã bao gồm thời gian dự phòng và tự học)

Lưu ý: Mặc dù yêu cầu đặt ra là 300 giờ, bảng phân bổ trên mở rộng lên 400 giờ để bao gồm cả thời gian tự nghiên cứu công nghệ mới (learning curve) và xử lý các vấn đề phát sinh không lường trước (buffer). Tuy nhiên, các đầu mục cốt lõi (Core Features) hoàn toàn có thể hoàn thành trong 300 giờ nếu tuân thủ nghiêm ngặt kế hoạch.

Nguồn trích dẫn

  1. Yeu cau de tai LTMT_copy.pdf
  2. Building a Personal Finance Management App: Database Setup with PostgreSQL and Docker. | by George Zefkilis | Towards Data Engineering | Medium, truy cập vào tháng 1 10, 2026, https://medium.com/towards-data-engineering/building-a-personal-finance-management-app-database-setup-with-postgresql-and-docker-5075e283303e
  3. How to Plan and Execute a Successful Web Application Development Project, truy cập vào tháng 1 10, 2026, https://dev.to/albert_ed/how-to-plan-and-execute-a-successful-web-application-development-project-1kkg
  4. What Is Role-Based Access Control (RBAC)? Meaning & Examples - Fortinet, truy cập vào tháng 1 10, 2026, https://www.fortinet.com/resources/cyberglossary/role-based-access-control
  5. Design and Implementation of a Family Expense Tracker Using MERN Stack - ijrpr, truy cập vào tháng 1 10, 2026, https://ijrpr.com/uploads/V6ISSUE8/IJRPR52224.pdf
  6. Splitwise - App Store - Apple, truy cập vào tháng 1 10, 2026, https://apps.apple.com/us/app/splitwise/id458023433
  7. How to Implement RBAC in an Express.js Application - Permit.io, truy cập vào tháng 1 10, 2026, https://www.permit.io/blog/how-to-implement-rbac-in-an-expressjs-application
  8. Algorithm Behind Splitwise's Debt Simplification Feature | by Mithun Mohan K | Medium, truy cập vào tháng 1 10, 2026, https://medium.com/@mithunmk93/algorithm-behind-splitwises-debt-simplification-feature-8ac485e97688
  9. How to Automate Financial Forecasting: 8 Processes You Can Automate | NetSuite, truy cập vào tháng 1 10, 2026, https://www.netsuite.com/portal/resource/articles/financial-management/automate-financial-forecasting.shtml
  10. System Design Pattern for Recurring Payments - GeeksforGeeks, truy cập vào tháng 1 10, 2026, https://www.geeksforgeeks.org/system-design/system-design-pattern-for-recurring-payments/
  11. Designing a database schema for a budget tracker with Automigrate - bogoyavlensky.com, truy cập vào tháng 1 10, 2026, https://bogoyavlensky.com/blog/db-schema-for-budget-tracker-with-automigrate/
  12. Daily expense tracker - Entity-relationship diagram example - Gleek.io, truy cập vào tháng 1 10, 2026, https://www.gleek.io/templates/expense-tracker-erd
  13. Learn Docker in 3 hours. - DEV Community, truy cập vào tháng 1 10, 2026, https://dev.to/morning_redemption_3940af/learn-docker-in-3-hours-91p
  14. Setting Up Docker: Node.js & PostgreSQL | FullStack Blog, truy cập vào tháng 1 10, 2026, https://www.fullstack.com/labs/resources/blog/set-up-docker-development-environment-that-matches-production
  15. Migrations | Sequelize, truy cập vào tháng 1 10, 2026, https://sequelize.org/docs/v6/other-topics/migrations/
  16. How to Build a Full-Stack React CRUD App with Node.js, Express and PostgreSQL: Step-by-Step Guide - DEV Community, truy cập vào tháng 1 10, 2026, https://dev.to/corbado/how-to-build-a-full-stack-react-crud-app-with-nodejs-express-and-postgresql-step-by-step-guide-323e
  17. Struggling to Pick a Charting Library for React? These 10 Options Cover It All | HackerNoon, truy cập vào tháng 1 10, 2026, https://hackernoon.com/struggling-to-pick-a-charting-library-for-react-these-10-options-cover-it-all
  18. Guide to Technical Report Writing - University of Sussex, truy cập vào tháng 1 10, 2026, https://www.sussex.ac.uk/ei/internal/forstudents/engineeringdesign/studyguides/techreportwriting
  19. Algorithm to share/settle expenses among a group - Stack Overflow, truy cập vào tháng 1 10, 2026, https://stackoverflow.com/questions/974922/algorithm-to-share-settle-expenses-among-a-group
  20. ReactJS Development for Real-Time Analytics Dashboards - Makers Den, truy cập vào tháng 1 10, 2026, https://makersden.io/blog/reactjs-dev-for-real-time-analytics-dashboards
  21. (PDF) EXPENSE TRACKER APPLICATION - ResearchGate, truy cập vào tháng 1 10, 2026, https://www.researchgate.net/publication/381249579_EXPENSE_TRACKER_APPLICATION