chore: Initial

This commit is contained in:
ulflow_phattt2901 2025-05-14 09:42:59 +07:00
commit 11ce970ce1
28 changed files with 2294 additions and 0 deletions

184
Diagram/Diagram Image.md Normal file
View File

@ -0,0 +1,184 @@
---
excalidraw-plugin: parsed
tags: [excalidraw]
---
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠== You can decompress Drawing data with the command palette: 'Decompress current Excalidraw file'. For more info check in plugin settings under 'Saving'
# Excalidraw Data
## Text Elements
app ^bRI0Cx2O
go app ^Txdl3wmz
Postreql ^bXgL6BoQ
db_dev ^e4jYepQE
8080 ^JEEt9AtB
5433 ^MIZrF7rN
adminer ^qcAKkTjk
adminer ^RFMkUi6c
8081 ^wr4RORZd
condition: service_healthy ^ckNWsRVo
healthcheck ^4f628p0Q
Postreql ^bAwykO3I
db ^V1uC7eTF
5432 ^g76zgWYB
pgdata_dev ^zY2qJySJ
db_data ^kfKzKMh0
Staging ^6znrPaDk
%%
## Drawing
```compressed-json
N4KAkARALgngDgUwgLgAQQQDwMYEMA2AlgCYBOuA7hADTgQBuCpAzoQPYB2KqATLZMzYBXUtiRoIACyhQ4zZAHoFAc0JRJQgEYA6bGwC2CgF7N6hbEcK4OCtptbErHALRY8RMpWdx8Q1TdIEfARcZgRmBShcZQUebQBObR4aOiCEfQQOKGZuAG1wMFAwYogSbggAYVJMACUeADYARwAVTCMARgA1AA56gEFGwgAZADF6gHYU4shYRHLA7CiOZWCp
ksxuZwBmOPH29oAGLf2AVm74re7+EphNgBZx8e1u7pOt8YOTu5P4+LuL66QCgkdTcdoneraCEvdo8f7xOHjPgFSCSBCEZTSbgfbRbCa/d48LZbE7tCaAiDWFbiVAHCnMKCkNgAawQFTY+DYpHKAGJ2gh+fy1pBNLhsMzlEyhBxiOzOdyJDyAGYq1XCiBKwj4fAAZVgqwkgg86oZTNZAHUQZJuMjphBTSyEHqYAb0EayhSpZiOOEcmh2hS2HAxWpb
v6DnSURBJcI4ABJYh+1D5aaQYhx7rOEakACKynqAHEAEIVZyaABaBwAGgBVO46jaAyDNE4F5oAWWa9TYNcI7QAolWAJrEGrtraaOONCAogC6FKV5AyCe4HCE2ophBlWHKuCG6qlMp9zCTRTtsxpWxRAF96QgEMRuPETgc7p96q8KYwWOwuP74lcUbfqwnAAHKcGI3AQvEH7HCc4ybswAAiaRQA+3BKgQYQUpowgyv2wQZFkSZrhuUZCHAxC4Ghj7
+uM3z1CcTEvvUfwUkQHDMqu674OxbDiuhaCYfgYQFLeBRnpAZQSDqcb1M0nRDAACjAABWFD4AA0jm8SYMQmA8EIAD6mjqhe8wIIsVKrBSGxoM43RQjsDw8J8xLtI8DwUmGqDON8TyIuc4x4u03QHO08QUsCxCguGiTxB8Xx3K5jz1Ac5JRmiGJYmg7zPOcEZwvUcLhWl9QUtZNKRnaDqsnKXK8oKApIDhYoSoesocg1EiMtYzDBoEWTqpq2rOq69
och6Ua1QgloxdaaC2iUM1jTSE3Gp6wjer6YKBsG2ChmCEYUjGFEJkmKZ2vE+g1PESr4MQSFVvoBydP2zRGQAUsQQ4VMwBbCmmGZZrm+bFqWFbVnWDaAxALZtp23a9gOw6juOk7TnOC5LggK5oKRvFRluxA7hIuDtgeeHEMep4ojM8CXjed6CagsLjN0PDs18kVAUwIF/qgOxLZAwG/uBHCQf6rHgkc4IIUTyGoSzwnYVGuHSsQBHpJk2R5HTkklN
J6CNNgfSacyzSqVxTb03MPVYFAM6pteWPkZR1Esx5DHMSxbFRhxXH4zxfECbRqAqwgYnXJJpRhxAJtmxbVtmQz5RoZgju2Udzw8Dw3TEscLmc3cWzefcL7PEcWwwe0WzpeFtdRVa2LtEkPwXFsDxkuMME83aWWYo7i0nBVyyutVy2Mo69UKugfLNUKrXiqdMoz2n5AcP1uCDZnUYjbq+pre6j70lPFrN4tp9mk6h/lMflN+JINO7VGQYhrAR0T5A
p3xomeuphAa6t17qPWeq9d6X0fp/QBk2CA6ZMzZjzIWEsZZKy1nrI2OmcNWwdi7D2Psg4RxjgnFOJ2xR5x7xxnjVABNNzbjsugXAoEH5Hh2kHMiNV7xh1rvBA45wPJfj5r+G0AFBE/jAhBGkH4WJ13qAGBWKFgg0QwlhBAOEqZayIrrdhhM7QUSosoui3tmLpT9naAO3EOElE5KHFRIk1FRnTkPRhxB9BbiYAeSgzQHa7lce47kC5OBQB1IQIwNJ
XKBKyCMXAbj8A+RHo4h2fQiDKAFhAMQWQPFiKgOYAgySMRpLccQYgNkox6CyLgfx1CICyXkopFS6ktI6T0gZYyplAykAxFuAg3iM6+LcT6AJUZcBCCgGwGo4RQk0kZEIBx5j3EAAl0SDzBG3KOEkiZx1UjWJCNQDiNCUhwIY3R2wrB8ApSQ5oKjKBTnbdACwljUnVAwvyJwEifAOLneoddgrFTLvZf4AU8RfCJExNmTd5rcF6EkCMFxvkJVCnneW
/dlk5UFgku0lVuBf3tGfNkXVZ4QHnk1dUopl4dTXoqFUllfjDS1AfF0R9Jon2mniuasVeBX0dKtO+zKH7bRPC/O0b8Dof3DDin+51/52ngSDJB4NUFQwwbDeGuCkYENRsQjGZCwAULtIuGJuMw60KJvQ3cAB5Fh1M2GoANtAVOuUmbTS4WCQ48I85vDEfzbgddAJ2lFhIiWNJ9iPHoo8cKiFFEIEMeHVR6iNaaJ1hdfWdMpJxxqCMdszJez1GwID
W2a0nE6rAOJVMBs03lE+s0PoSF2jms0EYegdwhjjHoCMYgBZQInGUHGIc+b7V3MpKQJkVA6Yu2mHqko+iPbcPohCH2pi7jsS3IHGhwd/b8VZGHCO6zigxyNhADNWac15opOZe2fSs72UuNoEu3weD7HxN0O45Uow+T8giJIwLkoklJJzCFHK9htwJJ3PY+JWIUgHmingGKShYrQDimalK55NUXmrNqK9Oryl5NS7AtKFz0p5YaPlXLz6Qsvqy6+R
G3QkajF6J+Nr5HCv2odcVJ0pS/2TQA2ViCwYoMhugmGsDVWI3wSjIh6NSGu31VQ41667TE1JowpSVrn46OZmHauhIkSwZFkIzgPrG683ERwcWktWYIgjO0f4xJI1K23XGtWGjCJJssboqd7sY1e3nSY1iS7/YrrcyHLddjVbnh8WTPxgzPEUF6c4ykUWsl7yCSEsJNocVKiCdE2J8Sz1JJSWkjJaEhn+qYDk9w+TUnlCKSUlqZSgmVMGdU7Zuz9m
HOOac/A5zOiXOueqLkXSOA9Iiy4gZSXMWjPGZMtLaAZlzOsYs1FzjW4wd3YUTZ5RmjYFUgsvEUA+j0A4OMUCSp9BbBGJgZg5YO23LWg8rFV7WYrdYkcZ9hc5HhVLm++41moRfFhPEaz9QX0kgAwtVAwV8rwoRPET4+dGKQaWz63TlIx5VVI/i7DipUN1btGS9qVNkNEs0DwJUPBNDtL3oR2+xGNqUcdOy8HwtcVUZpzRundp6NqdZntd+PlDgSo4
1KtAl0SgibwcjQhaMSGYwndjQ11CTUKbNWTHMqmbV2vPYLJ1nCWYvvvdZgExnvX+ghF6sWkiwQfn2HcbooUmOG0Vko5Wjm8fOe1sRaVe7U2x3KBQUgdwajmpqNd/tWvoA+LHdJjzBjPZzsYr5sxC3OJBY3bYoSqi1v7rjv7wPwfQ9nodegItj24RQg5jBtKHNYRaf83ad9b5EhMTuADoHIOUfRQ5Q8YDMFq7nBg+zB3qIkfD1Hk8hDGOifEuaqSj
DFKCW8hJ2TindLRps/WlNGqbKL6cvp6yajG+WWc62gxwV/peeiv58dKMkq/4i6weL9V4npfauj5AA1y45NWKkirxhNR1dn5rrf72guqLS1zA527VzIolABoCw17m6BrmbjBpQvjVwwZ2bO4Ob2Lxr4Quae7qZuyx6zrGJMSLrLop4EHmKbou7YGJJ9ISBhR24xZxblCMHtDDQpZTLpaRJQDZZai5Z0H7YFblBFbjYwFla5L4CVaFIkC1bqjlJRBV
JxxbY7Z7YHZHYnZnYXZXY3YdKDbDb0HoBsHqgjJjITKsAzaoBzbkEIBLLZTLZrLFClrrYKZxyHaaTKDKA1DtBIRwAUAHBGA1j0AchQDYDMAnC7znhF4QD3Zo7PJW5PD5yPAFwHB/APrM4N4vC3pvhMTsw/ofjPhg5ggQhQgfh25wi/CIjM5QbOI4h4g9wXBIjEikgZSYpxET576Y7dQoYLy44lD46YZT6qhqgEZr6Mq8oc6TzXyM42gY4H73ybSP
zc5D4QAiqsaszX52i35cZ2jlhxjND9hDCdDfBGQID1jmqdD4A5hxhDB1xsCwygT0DYDmgtqSDjDMBGQwDsy4BFgjCmY5hGD/5v4aiyap7K4kwMKUg6gAG0wAJa5XjTDOECCgGoAvqA4RSdx9ziEmY2jJQIGmaW6LSfJEgfbfAYHRo0Fhb9Hu5aIkTyYx4zpgjx4Lp+bkGrpK7WLUFYGiROHRwbYSALIwAnDthVhKhGQ6jtg1CdBVhVg6jECSCNDj
DMjmpIS3YWRWRxGPYRRxClQ8AIgt4vgt5knfYAoTCVy+ovpnAeQ/BFFxQJCJR3DJQHCpTpTQHD72E+qJEFSfIvolRkjpRj7jyT4L7Y69Gz7kqE4hnF4bxbw7yr4MrjQLGdEzEUZb6s7jG06b4lBc6MYX7rEC7saxjC7JhYIcBbD6AVDmoLJwBsCfHMhGQ8BFjmi4BbAcB3BCDOCwx7EHFHEnFnE6gXFXE3F3EPFPEvHjBvEfFfHdA/F/GgQAlAly
6UIK5f7uY/4Qm7jNAwncCa5F4Im8nOoswPqHBMQASg7G7CK5TA74lmbBoPCkikhyzkkxoRw4Gax4HaIlllo+7h4l4+4HqtAlJbAUD6BGDFrjrkIUjTpebMmJ517J7sn0mQA2IhYZ72JZ78noCAX4DAWgVqkXqRHrA2i/bPjghvZMSgZm4mm+QvqtwkivD5zJSsTjCkjwVAg77A7aCpG/BpQ7B7C26OmI4emj7DLtG0jBlY49EkpLwE4axE69SbwD
Q6zxnzG0ZpkM477M4rTr5JnH5LG5mvwsZiobGC5Fl35fl2hlkVlVk1l1kNlNktltkdldn7GHHHEnCnHnGXHXG3EHD3GwKPHPGvHvGfHfG/H/GAk6qTrv6gmUGGy/6Ug1jblxXImewQF1zOmFEXkGa5S243mEm8Cwi9APAcxYlSRO4UncnzYig0muYi7RUQDQVx4kG+xsUQAWIpXtVcmhbVUR6GHRhsCoC4BwBwDMEjYDVDUjUcFZCpbhIZZZYxL8
FQR5YZzSEiE6xiF6akDlZ5LCESA1alJ2gKGNZMDVKCnCminimSnSmynymKnKmql6H+AGHxbKCDXDWjUVSTbmFcGzakCzI2F2ErL+iOElp8muHlBGRDh3BsDEB6lKTmgnD6C9qdBCCgQ1iaTtjmh9EFrqmPKHVEWm53DaDA7vAt5JHFRfb16bAvhPA9weR6mMQyxuq2moDQquSpF4hQGIrdBulSAj7oqBno6dFT447hmyWrxRlEq4b4ZU5jGJlqVT
EaXka77qX746WK2QA5mAErFrHGUFk35C7mWi6QDdluV9leVDm+X+VYKBXjmTmhUznhXzmRXAkf5GpgnxUblkydDJW2pYLwk67LQonfLcyvg2nZUCwkjM6wG3ncBviOkPrFQrGEAVUvmu7UkJofk7He6pi40EX9oHqaA1BxgHAVAGSWpjpNjlq+4SBbDlg1imCdAnCSCfTmiaRqCaTmpGTEDdDMikBbk2wDprTbwjrgXAlNXEE+akGskBYUFAFrld
Xp6xroUHm52GxxzF2l3l08CWqF6Dp/l2gML25JCJ0wZ6kvhHAo7vovi7CA5IgwQPnhSvis07AJC/C9y25wgPq80o41E2go7wbiUi1S3T5oZ45z6RmSXS1Kg0rxAqUa2TECDb4q1aV4qqVIMxEn7LF5n62bElDbFe6m2uW9keX9mDk+UjkBVjnBVTlhVzkLlRXy6f6e3rlKaUjmh+0cmpVhwXDwR5z3n4k+ppT5VBrFHvDOQSPPmUm9Xqy4Ee6fnc
ONWebNXT2tVsmsNL2oUr1UkzDjUfVjX9UGM8GzXcHJZRKLVxLLWCFrUSCiElbYk7VSF7XoAHU43pINZKGQ3Q2w3w2I3I1Dio3o2Y3Y39adLPX4AsFkxTVfVmHTbTL/W9UcS2EC0rYnAYUQ0SBVgHCqTtC4A1BwBFg1DUz5zMBCDNDKCMip34X3KWT43uMMLHnPAeRhR5y/AcyfL/I0UwbaCHAXBkiJ1JEd476Q4vDQ56lw7ApCXA2C2iXj7ANq1d
GEpgPuMDHz7QM8hL7k6U76rU4Zns5ZnIPTGaVzGIOHNYP6U624NX6mVnTG2200MTkhXTmzkRWLmQXLksOdWKaQm4BVh+27l3L7lg2HlhyMTJQ/C1wrGwFgiiKR1x3+jHnIEASPDSNVVvmJr4EWXr1REH0+JD0HqfT9j9hQDxB9BQBFjj1Ll6IqNT0J4z1J7IWBadUoUyMZMb2VrEukvkuUv72Fr4tRiNO5zaDIGHAtNHCw77BdN+SuS9Oc0DPJRD
Os2kjv08V/AczJShQsXTPQaANiWIZ4qi1hkyWDGgNbMr6jEJlMqYMzQpmq1K3q37OH78qn5Ji61GU3OFl3M52QB220OO2vMu3vO6rMMe3fMJW4B9qLGsKAFKNhAsyA7A6/DpTQv6ZwF7CiPmYeTIG/LFRlWlBp0yMYvZ2aOT1MktVkFz2IXAGsvouCGsF8IHCGPxaMFNsmO/W8DzUWM5bWPharUuPpIbUONbVOO2OuOyEE2QDHVeNZM5N5MFNFMl
NbBlMVNVM5BPXdKRPjWtsmHfXxPcDWFz0pPCWsyg3OHZ4iHMigTmjMBSk224v8uXqCubBkiOTVzhSvAt6HAfArHvppStz/C9BvA9zMQfis0watyvAATWmvgvB5w6vOLoFzNBkgMbNi0mvrPdHE6k7bMINOu6UOuzQnOdEH5UTMBohH7ZnYMGXMZ86fxeucZ5ANXu2K5IWlARs7NUcazc5xsokhqdz+meqR1QqpsmYIuduPAnCcwRhU2O5Rrp20Fu
5Z0KM+s10HpsALJ9BDBIQ8AjA1gVDnbjKNAnDOBGR7BQBgVD3h6j1sCjrOzV3/lxxVo1p1oNpNotptodpdo9pRs/nRE2d2eIkOd5213oD12N30DN2t3t2d3d29392D1+eDoBdUsfM0tEHls+Y24TB+oIWaO1s9UrXxblKOA5KcBoBhCkBmBiBGRogEDqC3CeheLjUldqC/gVdMDVcIC1chD4ANfTXBIdsRLmO8GWMCF9tCEFLlDBBKiEUjuSFjvQ
BBjyGeNNarkbtDZbv9WtdlccAddVfmDdd1d9eSCNfDJ7sWEJMA1HtA1oppPssVoSB3BKjFTdBwAHBq58tpwCtH0/atzA7Ok/sZXgHSuWnPDfAQi/KwhFSs37BbC4gf0eRpQwbvuvooontIdtHzMGvXxGvSXoYRlyVms4cWty1WsTHnO2vEeLOkehAUcus4OGV0dsaG1mUXTMexUL10Le2MKnp0ZUw8dsfxvcK5xnBNHBRCNoB4nwsFUQ8PrsyosK
L2aFdObKe0lENqdxwadac6d6cGcjBGcmdmftAWdh7+fDq2epchuEGMlGI+bcXfCydMvz1KMFdoW6N9XxbHfqDYBojijNvlDe+SC++WTWwjemNEk8F8FWNoAo5OKLczdzcMASEVYDtjKfX1YVIztc+vzhObtRPoBB8h/++xNTaXcHuJOA2pNnvg0csSDa/ae6f6eGc1DGemfmeWeOLm9j2PbbDfLZHvjfJNGfACLUV+RIgk2A/J2kVeRRid7g4RRP
BHCvjZshp7DOkIeuqJH1DwpvATA5dfBC3YoSVYcrPi2msbPmucfv57MK02soMcpoPpnjRkf0+LECpuvXP0es/etMehusfAEfmviAFgHSLw8Ag6PDKFN8lMTvBROJuNmnAItxiNY+ybaOp+CV6YEVeSneRur06pls7eCeQ4JzF5oaMWW3Vd3r1RrJbhPyJtE2mAC/jFADgdMaKmADoHOAngibS4McFcjPgIwEdPOs4H2CtwPglmI4JzFgjpNUwLAu
gaFESA24jg3wWHNXhtiCCPIzwHftXD345tP2zA4EvgFCBQB2Q+gNxDIAfBKQ2A1AzRgyG3gUtiYW4G5GgDtRpAtE1SZ7q93e6fcsEmWbAEICTDOADgvTIkEFBgwsQnSbTWBMoGGrcBIQyBB9Oq2JAIhv64AoLlGEyDEAiwdg5YDuSwTOCdY1ScUNe1vadB72+qfiL4OxS4gci9cGvAPn/Zulv4UQ2PgkC5og4PgRpZ0u0AgG4obBfQC3hQDq7rdU
hMoXoSOgGG7g+h6oIILhAoBss16LhOvugGc61p60jaZtK2nbSdpu0vaGpkOh77Ptr0iQTmJ3FKqcwQOTEaVhCBiEVEAegOSonzXn64lngH9U8h8FeA7A/6AtRiAkDOA7Bf0ecHYK0Tgz6sT+yzdDgTwlpYZT+V/PDnf0p4P8mcpzJ1q/3Qjv9XWQqEoHrU9Y/9GO9Vf/oMPBLsNcA7jDqNzkBbhIuhwvMEI6WsznAEhkvVEjiljoFV3g8ECKL0BT
qFs622A98ip1La0tMu9LdRlW3y7kCdGlAiwVi1oGpoGB9A5gU2DoFl5zgvwF4XwjeCY9UwXw58PnFBRSdtREwXQdS2sQGCjBJgmiOYMsGdVrB21DITKHsHZCAEuQrIPkKvY3s72sMbweUIQxcVLgDQcEDl3ziw5AxumBoaNTQCJBkiBRD4CSGBweRgWSJDADKBtGOAshjgnIR+Waw7I9kByI5CcjOSRMesVyG5LAg9F+CAhzpZ0sSDAyJ1PkSINi
iGOxAJABmsIKTsVD2C80KRUQbaiMNs5jDOqaQ7sf0JCBxwUuFIKYbZ1mEgscWoXCAOFybot026HdKAF3R7p90B6OwkcfsNQBnA5W+cQqB8BgwcxcukAG+l8OfR79pOH7PKnPx3xuokgEwM4DGOSgAR84m/WPpCGTZ5xgcwUN1LnCP4dFFmePGfBhygZQiSe1/DULf2tZwjjmqDRES/zp4oj+elzT/kz0vzf8tiRtdnniM0ZACyYSoEAXCTAEUi+O
2ox3n03pHnCZeyA1mC9gSh+Z82qdeTkW1V44C6qOfdLrb1ZiwUGWbVDquxM5LL1XyUYKgZKLph0CZRTAqQfKNTS3iGgLFYqtZj1IvAnexQEoh+OKrfjXwucA0WlyNEMgTRagM0RKOcRxtOxtg20SmP9oOj0xccAoa6OKHuiyhpYhHu8D4RhQf2L4cEGVXrHhgSaaowHKkWA5xDxgXQtIUmLtGpjrJCjapFDRhpw14gCNJGijTRoY0saONd/E5M2B
lju4nyXmuUWtxJEIhjQ3gCTUuBhQW8LFH9M+B34diehfQ3sfxMgD9j6pQ48YXsLtBjiZhVVB7tOK6A1giwJwcsAiE1hwAaw9QKAOajQgnA4AmgacF9wkCxEnkvfPOI5AmCO9Xuig6zNfXuC81SiqRBikxDg5HiIADw03JCGhDlF3ULkV8RDgCH1ECQTREkN3D/ELNCOgE8Bv0UgZE8NmwxFUDCKgmUcjmytR/nBIBkM8aOGIj1uhIIaYSiGEAIYE
OAoCaQqwkgdsmXRzBwAjAnwUCNgGaCaRsA7BWBIU0lKEAcwNQIUkEEUhKhnAiwVOkqDbZYJVI/UKGqpHNBPQeAbAT6OanwAHAawBvOMEZE4Zu1OeSjXCYwn0DdACJD7H1MRKPLfsEUzY+kWSBRxMjqJbIlivUXOBossBmdViViyUb4CuJxiORA8HoikDGpWjCcee0woQBQIFQbAPoM0D1BnAlyJSAZ2ZDmhSAQ4JCPQHiDrsu+g6RaZOwgAvIGgx
Nf4D8EeAtMEUGRe4MgShDJsAI8EYqLkTR4lBTpGxeKA6SdIulAR7pGZnlBeCw4fSxUN8P6TTmQAgGOPaeKAzBEQNCektaBgpVjLKVLWGDaCcDIREkczmgMi5h/3RGQBMR0M7+LDPvwAJmAy7OAJmEaDKACwJkJCDABgDOB6ApATSBQHiBGRYYCMpGSjLRkVAMZWMk4DjLxkEzYYxMmoKTPJknBKZQwambTOYD0zYYTMuACzLZlVgOZXMnmXzLYAC
yhZhomKiuRwkRt9AMCJCTG1hLSzHUKQ3XGHHOCk05Eo/UrDiUWhhRM2waJiN8jWkRRtZFA4tryLHnTBNe5QTQH0AoAwBlSWwOMGbzxZ9Io8/85RhlwIEYLrMnkc2a71FE7o5hF7CQCQrIUUKqF804vD90Jq+QYMZYsKAVLtzfjtpAKHEOCEUHBRvgnwYZirTty9Nq4z4EKDsHKIfCMeerbHiCMajGtwRF/LDs3KUpDQ25Pck0PCNmLdz8OmtPuWi
PPyoT8y+DEeWzzhkTz+o082efPMXnLzV568zebAm3nIzUZQgdGZjOxm4z8ZhMrBOfMvkUz8AVMmmTkgfkMyAEz81+ezM5nczeZ/MwWUw0+ZhsLZYsykPoF9rRtrUsbIXnxyH5yIoC9IlHmgthaA5c43sHBWKLwW4CLZhs7zAnhNmsLhRZAwSRnT0b9VzBpoBAI0HwAB8JAUyxkDMrmXttLCw3Uod2yWqx8iui3exuqG/CjsB2bjFblnzW7lA7ZDs
3AE7Jdnmg3ZWwD2V7J9l+ywm+hLbvFkWWBBZlu7OJuXz+rXd5kPoW7g4VWxcKbZQwUgDqEkD1BywqkLYPQCYjmh8A9AVSGFHboxMA5d2Opg9k3HbBwo6g14KcIhCXBH6Fw9KI2IfTJzGI4Uf4Mq1bilQXgzpOEL0FsyZQBaeINuJlURRUq/kyHYWgBNrnGL65EIoYrAzwzwMrFDi+/jBJBn2LYRvc7WihNo5oSWeGEzxQQpKBhLd5kS/edEqPmxL
T5RMosCTLJnJLUl98x+bAmyVDhWZuSz+QUp/lFLhZgC8NjzwqUrKwFNSiBSUEDrQLg6nsOEI3irwqy02NoPEK0v9B8UoO/TLpUJO5GYsaBKaELgek6DtAhAFQcYAgGaAjBqFj7R2HQt0mQB+lsFIZWbJGUWy3eYonqcmtTXprM12awRZ73iL2QkUCQNKM6Q5iXAPwDEUlStl6CisWKSPUKOB3h4RR2mr7P4G8EVmsq9FL06uXVAFX48hVpi5ZjLX
FVk925vcqnrBNlVgzURjPJVW4tuY4jsWkATVREqiWHzj5cSs+Uaovkmrr5KS2+WkrpmZK7QVqm1e/LyVfzClf8gtSCWdVlKI2XAapYL2AKUiwxDS79nzRhaLQ9S4ap7BXl5qOkUcjE5XrgpYk8jelBs/kUwohAsLS1AK6tovQrWxrvV41YgOBPICxZyN4EzLDNSG5dtRuPbbZTYwHZ7LskC3I5RO3cbTszlEgcFZCuhWwr4VJwRFcitRWaR0VwqP
PptwL5wJwJphMvh20PYArj2Mze7qCsybGx+wSoboOMjuDYAdQpAPoBUCLChBiA7YcsJgALAnAdhQchppsDhBvJ4IjeeiIDiFhkhQedcXEL0GfAt5k2jK1mqM2ZWVFYcPwhHNOoLn6KUO/KtDoKs+kNzIRyzaERKrlU2LpVXcmntYr3UQzB5UMlVTDLVUnqIAiS+9TfLvnpKLVjM5mdarfkfz8l383+cUpkwAbRZQG0BXpXAX2jIF2uX1ZALQBtq8
4QQ/NjBtQBG4kF/McTltICnMQ+aqGzAehrjUlt1V8wrTdGGQJGBlA5oIcLyyS65rwKwXABAeiEDjA4A9QJUBwCHBGQawmgUCBGCEBVhKkIwfAMyGA17a2plvfNdbw4kwVjZRUb5GwrY4kbM8mmhYetvqCbbttu2nrY2uWnEgRWb4ZSYvx+ACNQePTTtX5tHURgkQyrAIXEISjljuBuimZuqMrnAjUOp/OuQluFXE9l8tGyCRT03W2LUyhHDdeDKu
auK8GR64sibRK23qklD6s1ZVtfUlB31dWr9faqa1OqvmgG11dYCqUerQNi9cDWzQ5jsx21I2kNbHyd7J8xOBVXgY6VhyK8FMnInWTVTV5sTsNjCo2T5hLW8TmW5ajheMsbUSAvgOweZegDd3JBVlc1KPmN17Zkb+2U3OxkO32Up9dqwe8dsUmDm8bTqccRoDpr001ADNRmkzWZuYAWarNNml5REzk1e7vlSmywipuTxqa7uNfDZGtqMBDAYAOAAs
OyCED7ACxcYOMDqC2B9BzQngmHfZqbW+RlZTkcOmFvEHOkK5EABvPsG9HwQpOAECHpWNZoAQoQ4IIIb6JSgb9ItaKdlWIvpocxuVW02dYYtDKLrqdy6nDEqDwx4Z/pjO9LZ3LsVZbJV5zBVQPNWL5aTKDHHndVpfm1bbVDWn9c1pKAsd8RXtQkSUK1oC8NcoAoFrLLDi25QoJcfOMGuQWFV4Dk2gqh5DJA15ZBMa53XI0w1sSTaRCiQMyCVCaQjA
mNSQCLu9XREi0X2hqkWuNn4b7dLvIHU7tXqTjVt04wg8QdIMi7h633J9r93shywSaSIO3JzXDrHSG8nwW9IcBJAfA9gGVf9NeNUV31fgTpMkP+yoro8Sd0WvlW9IXVASTFmHFdafviDn7Utu65MtT1Z3ZakJ/clxQeq52v77mWSmrR+vq3fqHVv677X/pFlsdylUQkDTal44sxnIyk3ONBq12sw648GiKF/S5VzbTdi23WTgf1lsdaDtu+g4Dprb
MGPeRaCQBRp7rURcAHu+TQUaiADcI+nbP3cxq3E7K2Noejjan0j0QBjlFIWPaQGqRV6a92AOvcIEb2XJm9re9vZ3oxEyaXq5QfIwYiKOl8fqReyvjd2r4grWD3C9ANdrjDMAiw9QQgAsjjDRIiwqkeIDmCQhZB6AWkOzVis1I4qW1Pcf4MDiUknlf2jmj8FCByIIgvJs22HiUQumwgrpOOtfbUTun4hGiRIJ6XnNRwGKKdoI+LSKC+mNzT+v0/CW
Ycv0Y47WT/blNYb0q2GecnOrEaqt/4rb4ZCyc0BRtZlVhVIygOsO0BrDmgzNJwPMN7qwTxAYAYoKQlACHBGA2ARYKsHcH0CkmeAvvXAAIqwSNADIygToKQCLAFhnAuAHgDmFID4B4gCAcsLgHNTMh4G0u0pW1rl1zTFdYBwiRAb60gFPY/CYHI7010IGGgjItNlNs5g/AdgIaTA4pySPxrVOjncoCdrO0XartN2u7QcAe1PaXtb2kLtZwmHUGoKO
Gm3YMv+066+J7CsZSwetlraTg/YSIeaiHBk5sAnQJCPoAaA1AhA2ATQCMHiD/MG13e5af3zkQA9SQ+pZ9Pm3fQD4oQCvWDg0U/FtUM5fTe0p8GrG5y+a/9XKF6WLlFQ/SZUPfRCaMWH7oTiW+SjGQsVJ994bO5E5YaBmOs0tOWjnfYZxOFa8TxWo4HsHiBQA/EfQamALKUhQAlQBYToFsES4AIhghJ4k+aFJPkmW8VJmk3SdhiMnmT5LNkxya5M8
nVIfJyQAKdhjCmeAop8U5KelOyn5Tip5U6qd/0AKZdmpwkcOwuZdbIpPWuMRphtBEhfgSIKVsJz7Mx0rTBVVyGlHkm+aHTHvbA86Y16umeFVYZQEMHqBFg2AwxmHVQedgT1wzAyjBa5DkmZHiN2RyOKDse7oBNA9Fxi8xdYs8GC6y0/4DCn2D7TnwTmxBTcEc0qta4TpPELbiRDswR9GctRbXGVFaK84U6zQ7qxHOxbKdUJiAGsxAmEpzF28Vueu
vROEcUToMpEzYecVYn1zw86MKPO3OwC9zB5o80ZBPNnmLzV5u0DeaJOaASTZJik8+dwC0nlA9JgBO+Ydmfn2TnJ7k7yf5OCmAEwF0CxKalMym5TCppUyqbVP0L/9QCuXf7M62eqrBKJYQyodBT0jO4I+1WVmxfT95ZEHIpiVyKdPLa+lXF4tbxdBMxmmDcZnI+NQ+XLLijc1r5T7rMYbKmNWymo6xqaPsbjMhypoy0cz6KE+Nnu5M8qbTN8nMz2Z
+oLmfzOFnizufV5XJsWvuqJsPy5TXMdU1ArVkixhM2DqVCaBXtNYcsDywoBjTlAzITQAcFCs6hnA9QM4xqSWk4qSQ8PZAoB1fATBgo5wGRaIt2n8JkC1cD8B+FDSw8jgIrGHJ2a+QAQsqZl5xBvtpqA5t9LEZnFXP31SV9DS6wwyfrgYX7MyTOjLTfqsN375V1HNc5DOZ4v7sRb+687ediv3n4rT56k0ldfOwJ0rLJr89ld/P/nALsCQq2KeKsQW
yr0Fyq3Bf/UIXfDEbJPiSN1PoXIDYIO3CxEOAvj8L6KS03rrVlnBbcOwT5P1bQ3dKMN1FlbfgfQBnFVIQ4BAHABzD9gc1vBvNRxfoVpHIznyCaw7tjPaNOFSxm2cHdDvh3I7Daw+iIu2Dsr84rweuEXNSLSshtd4zBWFGbwdX7hHFeKBosuFUrUeN00nWCZi26G4t45myzCaS2c2xV3Ng5rzev0s6lzN8QW+zsVWi3lV4t3E8et53RW7zD5hKwre
SupWroTJjK6yays/ncrAF/K3aB1tgWSrkF8qzBaqt/qarLqwkUIC4Z1KWY6NnOVTexLwDMS8GwHL6TeAJQKLsjWqikeALx2eLidvmpNayPTXequR9ABMYQD0Bij0D2B8tcj4jdo+43QPZNyqwh7MkyFg5Zxr2vcaTlh1uPeUD+sA2gbFLEG/UDBsQ2obMNnPfnxo090YHBemY1dySaLYT2Gm9O2tvNDKAM9HIBAP2B1DnbnAOYeoMyAoC4B+w0pT
hiWfOMI3+Doix0iTQnUhDYO9FNqnWfH14hGIKBRO2FBWIZzgt4zMLfDmJ3r7tDx/UcwfrZtH6ObioFLc5YnsLnt1t+lc55f3XT3D1jhn1oAk3uq2d7OVv83laAsindb4F0q1BYquwX1TAAxen4YQc6nACZImWQaZV2nBGIgOeCGafgEwH4NrkE8klBQ0JHfbS2/BSesDsQB2wcYcsKQBGDjBSAzCKzpQcjyx2/1gDiEONZAfJ2prqdkHVw7B1VOa
ndThpzsLzuQBQ5xwBIC3jrj/ZxBO/PmnWbJXaOIQHyBoPo9Zq25cQDRSFulGQ3HBW7Fj/8Z3asvd3bL300CXTsHvOtnHMq1x+YYxNeX3WYtg2nPclsb2Pz29784E81sH2SgR9vWxE7PtG2YnABthr8yoABHalYG5qy8DAzasnbhuaI22LezPh4jA1s3TZb/uKNUjo1v7cA/4vBZmJE3coG7q2DFHSX5RhjVUfWtx98sW1+oztdwcYOo9chVo6tyI
cSAeHfD4III+EeiPxHkj6R3Q9k3jUKX0x/dn8rYeAqFjkg/pyJYgANl6AzQUCMyEKaSB8AWYToEZAoBwBmQwpc1PuFkfw3g5LyAZn5P2C5xfUNZl+mP21JcVwQOwZ8RM0dKtmbx1cZ4BCANIvovb+4m6eeSx4d2x7701Zr3ZFVn611uzeWvc9cuLmWcaJpx+49y1P7nn7ivy0Vt53/Pwnp9w29E+qs+HABEbTBA1dJHgHGYqT+pY8E/GmJ2rNKqi
VmzcjPpbj3thbSU6GtlO8D72mS7RfQBGAhwPARoJ9BgA6hPoVvGg7i9t2dOCXaeXp/Gdr7yve3/bwd8O9GfCLxnL7KTr0yKrySH0LeAHba92nhR/JcHWHC69h6/ZHglRJlW8AfIj7ezvAQ569KDd6GPpE5mnT9OMOmHHHbjxZm5Z3UeWHnHjvLSm+51OHD7oT4+/rcifn3jbV92XYSLO7FvAj99zTDBAQVkgddo2hoEgaQHdWfkfwW3EU/ReJHzd
es7FwA/HcJ2+LZalO0S7QflA4AygSY4w4Sec5mu/VBj0x5Jgse/9nBNZYxpQcB6Jl6DwrAy6QW7XmXzR/B2y9OUcuVjPAJVyq7VcauRgWrnV3q/bAGvhXYxiQBx8KPMfmHErqwu9ZL2fWQa31ud9OPdPnbLt1227fdse2EBntr29cRMOWnOkRWpId4VBySir7qa16Z9CTVNkfBXwgU4KHXZVrw9SQz6ZRRMCJBsibpRAxsXaatL/AYM0vANzoafd
d2bHr74/VSg/cRu/9DOnm1frIy3OBb8E8johIA9Juh5BWjxVudyAc9WtZtuXZ30Q9JPS3NoG23RDFaHBgc2HnKoLE6tEXqJvcQy+h5/s9LLdOL63dxaJXy982oDgS+A4pAiSE1qYcSTbEkn/zWBqaSLzAZi9NF4vMkz5El4pV25UvIKHSV4eQrGiDAposwcZKsFmTwplkpwTZPKAJ7dN+mwzcZtM3mbLN1m2zcWMylejCoSKd4Jd7KlHBWIwY6MM
VMOAitq4MBsiq+CTnJC5hTUxMZkIcFWSOpn3iQKsfWObHtjux/Y4ceOOnHQfPgpMOIqRA7nPbr4FyCyoASRDQxkR3phcBggkWvxrYu4LVK7EtTcAoLhMcQAHENSlGnUq2RZ4PQQ6OApAJSLgCQhh82Lq7kOY5t2kfA1p+cAERUWlYkhiaP7VIpTUSE78gtcQORASER2uQidBziy8c8hOnPQ3oDFUOG6ucEcx7v7u5+MYQlC3kJj+ur7Pc3Pz3mvp
tgt66ohvcHLbUL5XSRL9H7AEQg3gWPBHftaiS4GBjAZVQxdUXhrVuzifN4B7Y6p3VBVb/WxkhRB/ARYujGx/ix6hogdoxB5UeQf+6WNE3BPggFm5h7tqTLtJOnwIcnV2jovgbLnvGr1+q/Bn35UZ/+UmeZXYkcAHqkpAjV6/aEbrdADRAZBpuHpa4AwEIAIAKAZmyc679+lrB0kIgHeHGDQj6A9QuPZ930TP/Do8hV/w/2+7hMFfT/Pgx/06Kv8j
BivQ9j/+f5P+6QDf4j29rA/4X+V/iAHLma0MiKUc4AUAE3QwtlPbwB3/ukDmoz+i85TsgAagH6ABvJsox8G1iUCf+EAekB4Bg3Hx47+xAQgFxYHfl36UB2AVACX+wAWZIS+rUnFQoBjAVf79gwwsL4AGHAUwH6AA4s0DREHUKf7MA2AEyDag/zHFBPAGTgzTMUsOAobLQEgRyD4AfaANp/At6McCwuysn5jQEEAOyYGA3WiLAEAsyKsg7mHMLK7O
E/AVf41AoBoAQoWcAZKAkAFRusojyLgWhAc+sGH5YkA7YLDQCOQ2JoDBAg1j4F92aFpADMWD0PMDKAooAAAU8vNQCFUCEEkGJBAQicAAAlOqATIygOuDbw0QXEFEgdILwBRGxQUUFpBmQWtgcBUAQgDoBu3HSRWIJtggATI24J0jveQwlcrBBFfDP5TsRABz7F6kAENib+kroGCjIyTF0FCWrBqsSxWdTMwA6gQ2HAB+BJMNwEdBtHpSC0yjAM0B
sAHIMYHSWboGkC0yBmK0a+CYyPoDCBdyDR6DWd3gyB9A6wZmpbBcyjojz+k4hBLBAp4C7DXgQAA=
```
%%

517
Diagram/Diagrams CICD.md Normal file
View File

@ -0,0 +1,517 @@
---
excalidraw-plugin: parsed
tags: [excalidraw]
---
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠== You can decompress Drawing data with the command palette: 'Decompress current Excalidraw file'. For more info check in plugin settings under 'Saving'
# Excalidraw Data
## Text Elements
Phase ^o9262IQU
Role ^iEREG52m
Task ^OOykyAOr
Secret Management
(Drone Secrets) ^MpRlnZse
Build Backlog ^LqZ5xfXH
Setup Docker ^1eo7f7PB
Setup CI/CD ^rIDmcxbG
Test & Release - CD phase ^1otAOWKF
Tool ^pRRejkFL
FLOW ^rXlDuuiH
Arch Eng ^xoLC7ka1
.env.example ^P8KLk0CU
Setup pipeline (.yaml)
Lint ->SecScan->Test ->Build ^DrIaH0Kb
Init Repo ^XqIzxR1O
SEC ^dg27ao6a
DevOps ^rvZ20cAa
Create Repo ^mhGNCgND
Folder Structure ^NLSKeK0x
Security
SCA/SAST ^F2CzjdDy
Arch Eng ^syJ8EXCy
Support ^eBIOV9wE
Support ^MBLn0kSH
Setup Docker Composer
(for local) ^GlMfUYcL
Setup DockerFile Builder ^S0f4Jc5F
Build Template ^Ek5lYfOq
.gitignore ^p9GjLysf
Arch Eng ^VOdMdL3r
Leader ^S549IYU5
CI Server + Runner ^cqXPMjfy
Merge Code ^wQR5cJoG
Create FeatureList ^JIQZGL6d
Branch Stratery ^xrln2pRU
Create Document ^lfgbimdI
Foundation ^yNRYjKu0
Plan & Design ^fAqf4FEz
Create Feature Branch ^KlSK3IHe
Create UnitTest ^gVr7eNa1
Arch Eng ^SldOQWU2
Code Features ^OaHb97pk
Pull Request ^Tk7j7rv2
Develop & Integrate ^ai0FdAkS
Code Review ^gb9Dohrn
Code Review ^xaQE4G1h
Build with Pipeline ^NEF3fPEf
Tester ^oSStmmXe
CI On Server ^osdUnrG4
Dev Team ^ZptyTXm7
Make Release Version ^ub21PHbx
Production ^oR927Bhl
CI Server + Runner ^9OKCCr90
Staging ^V05ubVjs
Deploy ^TCGnvf6w
Notify ^wsvkcNpK
Build Image ^ES0qwtVg
Dev Team ^XzacjP5w
Thiết lập môi trường kỹ thuật và quy trình ban đầu. ^IW7wDWeE
Xác định sản phẩm, lên kế hoạch ^SWrvIGD9
Code Feature ^7tT6uXV5
Developer hiện thực hóa các tính năng ^rDBxdSYV
Commit Code ^4huvpOzb
Leader ^tpYV3lk4
Automated CI Pipeline ^3Ya0faAt
Approval ^SC30Hp63
Kiểm thử & Phát hành ^Hr0u0SeB
Deploy Staging ^jNqrS400
Unit Test ^sAy0Gwgm
Training Dev Team ^ZPXmLDwn
PR Code ^c0OjOrnA
Push Code FirstTime ^GDzSkATd
Smoke Test
E2E Test ^fHARAzDt
Đánh tag Version ^pmE2YXy8
register Image ^1PZiWEdK
%%
## Drawing
```compressed-json
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
FgIAA===
```
%%

16
Docs/Bộ Rule CICD.md Normal file
View File

@ -0,0 +1,16 @@
# Quy tắc Áp dụng CI/CD Dành cho Nhóm Phát Triển
| Quy tắc | Diễn giải / Hành động cụ thể |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Không làm việc trực tiếp trên nhánh chính (main/master/develop) | - Dev không push trực tiếp lên nhánh chính.<br/>- Git server cấu hình "Protected Branches", yêu cầu Pull Request. |
| Đặt tên nhánh theo quy tắc (feat/, fix/, chore/, ...) | - Tuân thủ naming convention khi tạo nhánh mới.<br/>- Có thể dùng pre-receive hook hoặc CI lint để kiểm tra tên nhánh. |
| Không hardcode biến, dùng `.env` cho local | - Không ghi trực tiếp token, URL... vào code.<br/>- Sử dụng secret management và `.env`. |
| Document rõ nếu template CI bị chỉnh sửa lớn | - Ghi chú lại những thay đổi cấu trúc template CI/CD để chia sẻ với team, không ảnh hưởng luồng hàng ngày. |
| Mọi thay đổi qua Pull Request (có review) | - Code được review trước khi merge.<br/>- PR trigger pipeline và cần pass + được review đầy đủ trước khi merge. |
| Test phải pass 100% (unit, integration, coverage) | - Nếu bất kỳ test nào fail → pipeline dừng.<br/>- Kiểm tra code coverage đủ ngưỡng tối thiểu. |
| Ưu tiên giữ pipeline luôn "Xanh" (Green) | - Khi có lỗi phải fix sớm.<br/>- Coi việc pipeline đỏ là blocker. |
| Tối ưu hóa thời gian chạy pipeline định kỳ | - Review log pipeline theo chu kỳ để giảm thời gian chờ build/test. |
| Cấu hình cảnh báo pipeline (Slack, Email, Teams...) | - Gửi notify khi lỗi hoặc deploy thành công. |
| Commit message ý nghĩa | - Viết commit rõ ràng.<br/>- Có thể dùng pre-commit hook hoặc CI lint commit message. |
| "Definition of Done" (DoD) | - Checklist kiểm tra các bước đã pass, QA/PO đã nghiệm thu trước khi đóng task. |
| Ai chịu trách nhiệm khi pipeline lỗi? | - Người vừa push hoặc cả team (tuỳ lỗi).<br/>- Có cơ chế phân công hoặc cảnh báo rõ người chịu trách nhiệm xử lý. |

4
Docs/FAQ.md Normal file
View File

@ -0,0 +1,4 @@
> 1. git merge vs git rebase cái nào tối ưu hơn?
> 1. Nếu làm **một mình**: **Dùng `rebase`**: giữ lịch sử gọn, dễ đọc, không tạo commit merge thừa.
> 2. Nếu làm **làm việc nhóm**: **Dùng `merge`**: an toàn, tránh rủi ro khi nhiều người đang dùng chung một nhánh. Lưu ý: Nếu rebase thì **chỉ rebase trước khi push**, không rebase lại nhánh đã được người khác dùng.

View File

@ -0,0 +1,7 @@
- Testing & Static Analysis: testing package, stretch/testify, golangci-lint
- SAST: securego/gosec
- Quét Secrets: gitleaks/gitleaks
- DevSecOps: aquasecurity/trivy
- ORM: gorm
- Web framework: gin-gogic
- Feature Flag: thomaspoignant/go-feature-flag

View File

@ -0,0 +1 @@
- Testing: facebook/jest, mochajs/mocha

View File

@ -0,0 +1,17 @@
### **1. Tích hợp Security vào Pipeline**
- **SAST (Static Application Security Testing):** SonarQube, ESLint.
- **DAST (Dynamic Application Security Testing):** OWASP ZAP.
- **Cấu hình trong DroneCI:**
```
- name: Run SonarQube
image: sonarsource/sonar-scanner-cli
commands:
- sonar-scanner -Dsonar.projectKey=my-project
```
### **2. Giám sát và Alerting**
- **Công cụ:** Prometheus (metrics) + Grafana (dashboard) + Alertmanager.
- **Metrics cần theo dõi:**
- Error rate, Latency, CPU/Memory usage.
- Số lần deploy thành công/thất bại.

View File

@ -0,0 +1,17 @@
#### **Developer (Người phát triển tính năng)**
**Tài liệu tham khảo:**
- Hướng dẫn dành cho người mới : Guideline Folder
- Các mẫu có sẵn: Sample Folder
- Template file cần thiết: Template Folder
**Trách nhiệm chính:**
- Tuân thủ Quy trình CI/CD [[Diagrams CICD]]
- Tuân thủ Rule [[Bộ Rule CICD]]
#### **Fresher/Thành viên mới**
**Tài liệu tham khảo:**
- Hướng dẫn dành cho người mới : Guideline Folder
- Các mẫu có sẵn: Sample Folder
- Template file cần thiết: Template Folder
**Trách nhiệm chính:**
- Tuân thủ Quy trình CI/CD [[Diagrams CICD]]
- Tuân thủ Rule [[Bộ Rule CICD]]
- Thử nghiệm trên cách nhánh & viết Unit Test

View File

@ -0,0 +1 @@
Soon

View File

@ -0,0 +1,92 @@
### 1. Đồng bộ Mã nguồn và Môi trường:
```
git checkout main
git pull origin main
=== Mục đích: Đảm bảo bạn có phiên bản code mới nhất từ nhánh chính trước khi bắt đầu công việc mới hoặc tiếp tục công việc cũ, tránh conflict.
git checkout feature/your-task-branch
git merge main // Xử lý Conflict nếu có
=== Cập nhật những thay đổi mới nhất từ `main` vào nhánh làm việc của bạn.
```
### 2. Tạo môi trường (lần đầu tiên)
Chạy các lệnh cần thiết để khởi động môi trường local (nếu chưa chạy):
- Tạo Các file cần thiết: .env
- Tạo các file mẫu: .gitignore , air.toml, Dockerfile, docker-compose.yml
- Cấu hình Global ban đầu
```
git config --global commit.template ~/.gitmessage.txt : Gắn Template commit template
- git config --global user.name "Tên của bạn"
- git config --global user.email "email@example.com"
```
- Sử dụng Makefile (nếu có): `make run-dev` hoặc lệnh tương tự. Tham khảo:
- Sử dụng Docker Compose: `docker-compose up -d`. Tham khảo:
- Sử dụng Air cho Golang (nếu có): Air sẽ tự động theo dõi thay đổi. Tham khảo:
### 3. Viết Code và Unit Test
- Triển khai tính năng hoặc sửa lỗi theo yêu cầu.
- Viết Unit Test sau mỗi unit code. Tham khảo [[Unit Test Rules]]
- Thường xuyên chạy Unit Test
- Tuân thủ Coding Convention của dự án. Tham khảo [[Code Convention]]
- Chú ý đến phi chức năng & bảo mật cơ bản
- Commit code thường xuyên với các thay đổi nhỏ, có ý nghĩa
- Sử dụng commit message : [[Git Template#Git Message]]
```
git add .
git commit
```
### 4. Testing & Pull Request
- Chạy tất cả các Testing như trong quy trình CI trên Server(Lint, Unit Test, Integration Test, Securtiy Scan): Tham khảo Makefile
- Cập nhật lại nhánh với những thay đổi mới nhất từ `main` trước khi Pull Request
```
git fetch origin
git merge origin/main
```
- Push Code
```
git status // kiểm tra trước khi push code
git push origin feature/task
```
- Tạo PR trên Git Server & Viết mô tả PR rõ ràng
- Link đến Task ID
- Mô tả những gì đã làm
- Hướng dẫn Test Manual cho người review (nếu có)
- Gán người Review
### 6. Theo dõi Pipeline CI/CD
- Sau khi tạo PR, Pipeline tự động kích hoạt
- Theo dõi pipeline: Tham khảo [[Diagrams CICD]] - [[Pipeline Template(Dev)]] - [[Pipeline Template(Main)]]
- Kiểm tra pipeline khi lỗi, sửa lỗi, commit và push lại. Tham khảo [[Bộ Rule CICD]]
### 7. Sau khi Merge Code
- Merge Code sẽ do Lead Approve vào nhánh main/master
- Clean Nhánh
```
git checkout main
git pull origin main # Cập nhật local main
git branch -d feature/TASK-ID # Xóa nhánh local
git push origin --delete feature/TASK-ID # Xóa nhánh remote (nếu có quyền và team quy định)
```
### 8. Xử lý việc cuối ngày
- Cập nhật trạng thái task & Ghi chú tiến độ cho ngày hôm sau( nếu chưa hoàn tất)
- Commit cuối ngày và push lên nhánh của mình đang thực hiện (feature/task-id)
```
git add .
git commit
git push origin
```
### Short CheatSheet (Go)
- go get --package_name-- : Cài đặt dependency
- go run /path/*.go : Chay Go
- go build /path/go : tạo thành file thực thi
- go mod tidy: Dọn dẹp dependencies
- go test -v ./... : Kiểm tra unit test
- golangci-lint run : Kiểm tra code style
- go test -cover ./... : Kiểm tra coverage của code
- go clean -cache|-testcache : Clean cache build / test
- go clean -i : xóa file biên dịch

View File

@ -0,0 +1,88 @@
### 1. Lập kế hoạch
- Tổng thể về dự án
- Xác định backlog
- Xác định các chức năng phi tuyến tính
- Xác định Tổng quan dự án: [[Tổng quan]]
### 2. First Design
- Phác thảo kiến trúc
- Quyết định cấu trúc thư mục (U-Hierarchy)
### 3. Kiểm tra lại các tiêu & Quy ước
- Review lại tron Docs Folder, Guideline Folder
- Quy trình CI/CD
- Coding Convention
- Commit Message
- Branching Strategy - [[Branch Strategy]]
### 4. Khởi tạo repo mới
- Khởi tạo repo & Protect Branches cho main
- Yêu cầu PR để được merge vào main
- ÍT nhất 1 lượt Approval
- Pass Pipeline
- Permission Push to main
- Xây dựng Starter Kit
- Xây dựng cấu trúc folder (như phần 1)
- File cấu hình cơ bản
- `.gitignore` - [[Git Template]]
- `.gitmessage` - [[Git Template]]
- Readme.md - Thông tin dự án
- .env - File môi trường
- Dockerfile - [[Docker Template]]
- docker-compose.yml - [[Docker Template]]
- Makefile - [[Makefile]]
- Khởi tạo dự án trong ngôn ngữ lập trình
- Golang: go mod init path/to/repo
- Nodejs: npm init
- Hot reload cho golang: Cấu hình với Air Tomb [[Air Tomb - Golang]] [[Cấu hình Air Tom]]
- Thiết lập pipeline cho CI/CD
- Tạo thư mục `.gitea/workflow`
- Tạo file yaml cho Dev & Main
- Trigger khi `feature/task-id`: [[Pipeline Template(Dev)]]
- Trigger khi `main` hoặc đánh tag `v*` : [[Pipeline Template(Main)]]
- Cấu hình cơ bản pipeline cần có
- Check out
- Setup ngôn ngữ
- Caching Dependencies
- Linting
- Unit Test & Coverage report
- Security Scan
- Build Artifact
- Upload Artifact (Main Branch)
- Push to Docker (Main Branch)
- Deploy to VPS(Staging) (Main Branch)
- Deploy to VPS(Production) by Tag or Release (Main Branch)
- Xây dựng danh sách các action và library phù hợp với phiên bản hiện tại
- actions/checkout@v4
- actions/setup-go@v5
- actions/cache@v3
- golangci/golangci-lint-action@v6
- golang/govulncheck-action@v1
- actions/upload-artifact@v3
- actions/download-artifact@v3
- docker/setup-buildx-action@v3
- docker/build-push-action@v5
- Tạo code mẫu
- Health API để check live
- Load & Read Config
- Connect to Database
- Cấu trúc thư mục & Module(U-Hierarchy)
- Unit test sample - Tham khảo [[Unit Test Rules]]
### 5. Push Starter Kit lên main
- Review lại toàn bộ file
- Tạo Branch init rồi PR vào main để chạy thử Pipeline
- Commit rõ ràng cho việc init: `chore: initial project setup and starter kit`
### 6. Checklist cho Team Lead khi Khởi tạo Repo/Service:
- [ ] Đã xác định mục tiêu, phạm vi repo/service.
- [ ] Đã có thiết kế high-level ban đầu.
- [ ] Repository trên Gitea đã được tạo và cấu hình "Protected Branch".
- [ ] File `.gitignore` đã được thêm và tùy chỉnh.
- [ ] File `README.md` cơ bản đã được cập nhật.
- [ ] File `.env.example` đã được tạo.
- [ ] `Dockerfile` đã được tạo và tùy chỉnh.
- [ ] `docker-compose.yml` (cho local) đã được tạo.
- [ ] `Makefile` với các target cơ bản đã được thiết lập.
- [ ] Go module / `package.json` đã được khởi tạo.
- [ ] (Nếu có) Cấu hình Air cho Golang đã hoàn tất.
- [ ] CI/CD pipeline cơ bản (Dev & Main) đã được tạo trong `.gitea/workflows/`.
- [ ] Code boilerplate (Hello World, unit test mẫu) đã được thêm.
- [ ] Starter kit đã được commit và push lên nhánh `init` và PR vào `main`.
- [ ] `README.md` đã được hoàn thiện với hướng dẫn cho Developer.

View File

@ -0,0 +1,13 @@
Trunk-Based Development là phương pháp quản lý nhánh trong Git, nơi tất cả thay đổi được tích hợp thường xuyên vào nhánh chính (`main`), còn gọi là "trunk".
- **Nhánh**
- Main
- Giữ trạng thái sẵn sàng deploy.
- Không commit trực tiếp; mọi thay đổi phải qua Pull Request (PR).
- Luôn phải qua CI (lint, test, build) xanh mới merge.
- **Tính năng**: `feature/<tên-tính-năng>`
- **Sửa lỗi**: `fix/<mô-tả-lỗi>`
- Công việc chung**: `chore/<mô-tả>`
- **Rule**
- Tồn tại < 2 ngày tích hợp liên tục
- Quy trình
- Tạo PR => Review Code => CI Pass => Merge

View File

@ -0,0 +1,38 @@
### **1. Git Commands**
**Command:**
- git checkout -b branch # Tạo nhánh.
- git pull origin branch # Kéo repo từ nhánh
- git add . | git add filename# Thêm file vào staging
- git commit -m "feat: content" # Commit thay đổi theo format scope + nội dung
- git push origin branch # Đẩy repo lên source code
- git merge branch # gộp tính năng vào
- git branch -d ten-nhanh # xóa local
- git push origin --delete ten-nhanh # xóa remote
**Commit Scope**
- **Dev Code**`feat`, `fix`
- **Dev Refactor → `refactor`, `perf`, `style`
- DevOps → `build`, `ci`, `chore`
- **Tester|BA**`docs`, `test`
- **Leader | Automation**`revert`
### 2. Docker Commands
**Command:**
- docker build -t image:tag : tạo docker image từ Dockerfile
- docker build --cache-from image:tag -t image:tag : Cache
- docker run --rm -it image:tag sh : Chạy container
- docker exec -it image:tag bash: Thực hiện lệnh trong Container
- docker compose down: tắt các docker đang chạy
- docker compose up -d : chạy lại các docker (background)
- docker ps -a: Xem danh sách docker đã khởi chạy
- docker container|image|volume prune -f : Xóa các entity không dùng
- docker network inspect network:name : Xem chi tiết network
### 3. Config Init
- git config --global commit.template ~/.gitmessage.txt : Gắn Template commit template
- git config --global user.name "Tên của bạn"
- git config --global user.email "email@example.com"

View File

@ -0,0 +1,26 @@
#### Definition of Done Checklist (For Small Team)
### 1. Functionality
- [ ] **Code passes all unit tests** and all tests pass.
- [ ] **Code does not break other functionalities** in the system.
### 2. Code Quality
- [ ] **No linting errors**: Code should follow basic formatting rules (e.g., indentation, naming conventions).
- [ ] **Code is readable and maintainable**: Avoid complex or unclear code.
### 3. Review Process
- [ ] **At least 1 person in the team has reviewed the code**.
- [ ] **No conflicts** with the main branch.
### 4. Documentation
- [ ] **Documentation updated if needed**: If there are changes that affect how the API or features are used, provide a description.
### 5. Manual Testing
- [ ] **Manual testing done** for the changed features (if required) to ensure no issues occur.
### 6. Environment and Performance
- [ ] **Code works stable on local environment**.
- [ ] **No performance degradation** in the system (if applicable).
### 7. Merge into Main Branch
- [ ] **No critical errors** during merge.

View File

@ -0,0 +1,134 @@
Dưới đây là phân tích chi tiết về 5 quy ước quan trọng nhất:
### 1. Bắt buộc Định dạng Mã bằng `gofmt`/`goimports`
- **Quy ước:** **Tất cả** mã nguồn Go trong dự án **phải** được định dạng bằng công cụ `gofmt`. Khuyến khích mạnh mẽ sử dụng `goimports` (bao gồm `gofmt` và tự động quản lý imports) thay thế.  
- **Giải thích:**
- `gofmt` là công cụ định dạng mã nguồn tiêu chuẩn của Go. Việc sử dụng nó đảm bảo một phong cách định dạng thống nhất (thụt lề bằng tab, cách dòng, sắp xếp, v.v.) trên toàn bộ codebase, loại bỏ hoàn toàn các cuộc tranh luận không cần thiết về định dạng.  
- `goimports` là một bản nâng cấp của `gofmt`, ngoài việc định dạng mã, nó còn tự động sắp xếp, thêm và xóa các khai báo `import` không cần thiết, giúp giữ cho phần import luôn gọn gàng và chính xác.  
- **Tại sao quan trọng cho đội ngũ:**
- **Tính nhất quán tuyệt đối:** Mọi người đọc và viết mã theo cùng một định dạng, giảm thiểu sự phân tâm và giúp tập trung vào logic nghiệp vụ.  
- **Giảm thời gian review:** Người review không cần phải bình luận về các lỗi định dạng cơ học.
- **Dễ đọc hơn:** Mã được định dạng chuẩn dễ đọc và dễ theo dõi hơn đáng kể.
- **Cách thực thi:**
- **Tích hợp vào IDE/Editor:** Cấu hình trình soạn thảo mã (VS Code, GoLand, v.v.) để tự động chạy `goimports` mỗi khi lưu file.  
- **Pre-commit Hooks:** Sử dụng các công cụ như `pre-commit` để tự động chạy `goimports` trước khi commit mã nguồn.
- **CI/CD Pipeline:** Đảm bảo có một bước kiểm tra định dạng bằng `gofmt` hoặc `goimports` trong quy trình tích hợp liên tục (CI).
### 2. Xử lý Lỗi Nhất quán và Rõ ràng
- **Quy ước:**
- **Luôn kiểm tra lỗi:** Nếu một hàm trả về giá trị kiểu `error`, **phải** kiểm tra giá trị đó. Không bao giờ bỏ qua lỗi bằng định danh trống (`_`) trừ khi có lý do cực kỳ chính đáng và được ghi chú rõ ràng.  
- **Thêm ngữ cảnh khi cần:** Khi trả về một lỗi từ tầng dưới, hãy sử dụng `fmt.Errorf` với động từ `%w` để "wrap" lỗi gốc và thêm ngữ cảnh mô tả thao tác đang thực hiện. Ví dụ: `return fmt.Errorf("opening config file %s: %w", filename, err)`.  
- **Xử lý lỗi một lần:** Một lỗi chỉ nên được xử lý (ví dụ: ghi log) tại một điểm duy nhất trong chuỗi gọi, thường là ở tầng cao nhất có đủ ngữ cảnh.  
- **Tránh `panic` cho lỗi thông thường:** Chỉ sử dụng `panic` cho các lỗi nghiêm trọng, không thể phục hồi (ví dụ: lỗi lập trình, điều kiện không thể xảy ra). Luôn ưu tiên trả về `error` cho các lỗi có thể dự đoán được.  
- **Chuỗi lỗi:** Chuỗi lỗi trả về (qua phương thức `Error()`) không nên viết hoa chữ cái đầu và không kết thúc bằng dấu chấm câu.  
- **Giải thích:**
- Go sử dụng kiểu `error` và trả về nhiều giá trị để xử lý lỗi một cách tường minh. Việc bỏ qua kiểm tra lỗi có thể dẫn đến các hành vi không mong muốn hoặc crash chương trình.  
- Wrapping lỗi bằng `%w` cho phép các tầng trên kiểm tra lỗi gốc bằng `errors.Is` hoặc `errors.As`, đồng thời cung cấp thông tin về đường dẫn lỗi xảy ra.  
- Xử lý lỗi nhiều lần (ví dụ: log ở nhiều tầng) gây ra nhiễu thông tin và khó theo dõi.
- **Tại sao quan trọng cho đội ngũ:**
- **Độ tin cậy:** Đảm bảo các trạng thái lỗi được xử lý đúng cách, giúp ứng dụng ổn định hơn.
- **Khả năng gỡ lỗi:** Lỗi được wrap với ngữ cảnh rõ ràng giúp xác định nguyên nhân gốc rễ nhanh hơn nhiều.
- **Tính nhất quán:** Một cách tiếp cận xử lý lỗi thống nhất giúp mã dễ hiểu và dễ bảo trì hơn.
- **Cách thực thi:**
- **Code Review:** Chú trọng kiểm tra việc xử lý lỗi trong quá trình review mã.
- **Linters:** Sử dụng các công cụ như `errcheck` (thường có trong `golangci-lint`) để tự động phát hiện các lỗi chưa được kiểm tra.  
### 3. Quy ước Đặt tên Rõ ràng và Nhất quán
- **Quy ước:**
- **`MixedCaps`:** Sử dụng `MixedCaps` hoặc `mixedCaps` (camelCase), không dùng dấu gạch dưới (`_`).  
- **Ngắn gọn nhưng Mô tả:** Độ dài tên tỷ lệ thuận với phạm vi của nó. Tên ngắn cho biến cục bộ, tên mô tả hơn cho các biến/hàm có phạm vi lớn hơn.  
- **Từ viết tắt (Initialisms):** Đối xử như một từ, viết hoa nhất quán (ví dụ: `userID`, `ServeHTTP`, `apiClient`, `URL`). Không dùng `UserId`, `ServeHttp`, `apiUrl`.  
- **Tên Package:** Ngắn gọn, một từ, chữ thường, không dấu gạch dưới, không lặp lại trong định danh của package (ví dụ: trong package `http`, dùng `Client` thay vì `HttpClient`). Tránh các tên chung chung như `util`, `common`.  
- **Tên Hàm/Phương thức:** Không tiền tố `Get` cho các hàm/phương thức chỉ trả về giá trị (ví dụ: `Counts()` thay vì `GetCounts()`).  
- **Tên Interface:** Thường có hậu tố `-er` cho interface một phương thức (ví dụ: `Reader`, `Writer`).  
- **Tên Receiver:** Ngắn (1-2 chữ cái), viết tắt của loại, nhất quán trong cùng một loại (ví dụ: `c` hoặc `cl` cho `*Client`).  
- **Giải thích:**
- Tên gọi nhất quán và có ý nghĩa giúp mã nguồn dễ đọc và dễ hiểu hơn rất nhiều.
- Quy tắc về từ viết tắt và việc không lặp lại tên package là những điểm đặc trưng của Go cần tuân thủ.
- **Tại sao quan trọng cho đội ngũ:**
- **Khả năng đọc:** Giảm thời gian cần thiết để hiểu mục đích của biến, hàm, package.
- **Khả năng bảo trì:** Dễ dàng tìm kiếm, thay đổi tên và hiểu tác động của thay đổi.
- **Giảm lỗi:** Tên rõ ràng giúp tránh nhầm lẫn và sử dụng sai.
- **Cách thực thi:**
- **Code Review:** Đây là cách chính để đảm bảo tuân thủ quy ước đặt tên.
- **Linters:** Một số linter (ví dụ: `revive`, `stylecheck` trong `golangci-lint`) có thể giúp kiểm tra một phần các quy ước đặt tên.
### 4. Quản lý Đồng thời Cẩn thận (Vòng đời Goroutine & `context.Context`)
- **Quy ước:**
- **Quản lý Vòng đời Goroutine:** Khi khởi tạo một goroutine bằng từ khóa `go`, phải đảm bảo có cách rõ ràng để nó kết thúc. Tránh goroutine bị rò rỉ (leak) do bị chặn vô thời hạn.  
- **Sử dụng `sync.WaitGroup`:** Dùng `WaitGroup` để chờ một nhóm các goroutine con hoàn thành trước khi goroutine cha tiếp tục.  
- **Truyền Biến Vòng lặp:** Khi tạo goroutine trong vòng lặp, luôn truyền biến vòng lặp làm tham số cho goroutine để tránh lỗi closure phổ biến (bắt giá trị cuối cùng).  
- **Sử dụng `context.Context`:**
- Truyền `context.Context` làm tham số **đầu tiên** (thường đặt tên là `ctx`) cho các hàm thực hiện I/O, gọi RPC, hoặc các tác vụ có thể bị hủy bỏ hoặc có deadline.  
- Các hàm nhận `ctx` nên lắng nghe kênh `ctx.Done()` (thường trong `select`) để dừng công việc sớm khi có tín hiệu hủy bỏ hoặc hết hạn.  
- **Không lưu trữ `Context` trong struct.** Truyền nó qua các tham số hàm/phương thức.  
- **Giải thích:**
- Goroutine rất nhẹ và dễ tạo, nhưng nếu không quản lý cẩn thận, chúng có thể bị leak, tiêu tốn tài nguyên và gây ra các lỗi khó gỡ.  
- `context.Context` là cơ chế tiêu chuẩn và thành ngữ của Go để xử lý việc hủy bỏ, timeout và truyền dữ liệu theo phạm vi yêu cầu một cách an toàn qua các tầng và goroutine.  
- **Tại sao quan trọng cho đội ngũ:**
- **Độ tin cậy:** Ngăn chặn rò rỉ tài nguyên và các lỗi liên quan đến đồng thời khó gỡ lỗi (race conditions, deadlocks).
- **Khả năng kiểm soát:** Cho phép hủy bỏ các tác vụ không cần thiết hoặc đã quá hạn, giải phóng tài nguyên hệ thống.
- **Khả năng mở rộng:** Các hệ thống xử lý nhiều yêu cầu đồng thời cần cơ chế quản lý hủy bỏ và deadline hiệu quả.
- **Cách thực thi:**
- **Code Review:** Đặc biệt chú ý đến việc khởi tạo goroutine và sử dụng `context`.
- **Race Detector:** Luôn chạy kiểm thử với cờ `-race` (`go test -race`) để phát hiện data races.  
- **Linters:** Một số linter có thể phát hiện các vấn đề liên quan đến `context` (ví dụ: `contextcheck`).
### 5. Thiết kế Package Hợp lý (Tránh `util`, Sử dụng `internal`)
- **Quy ước:**
- **Nhóm theo Chức năng:** Tổ chức mã vào các package dựa trên chức năng hoặc trách nhiệm nghiệp vụ, không phải theo loại (ví dụ: tránh các package `models`, `controllers`, `helpers`).  
- **Tránh Package Chung chung:** Không tạo các package có tên mơ hồ như `util`, `common`, `shared`, `helpers`, `base`. Nếu cần chia sẻ mã, hãy tìm một tên package cụ thể hơn, mô tả rõ trách nhiệm của nó.  
- **Sử dụng `internal`:** Đặt mã nguồn **không dành cho việc sử dụng bởi các module bên ngoài** vào thư mục `internal`. Trình biên dịch Go sẽ thực thi quy tắc này, ngăn chặn việc import mã từ `internal` bởi các dự án khác.  
- **Thư mục `pkg` (Thận trọng):** Chỉ đặt mã vào thư mục `pkg` ở gốc nếu bạn **chắc chắn** muốn cung cấp nó như một thư viện công khai, ổn định cho các dự án khác import. Việc đặt mã ở đây tạo ra một cam kết về API. Cân nhắc kỹ lưỡng, nhiều trường hợp đặt thư viện ở gốc hoặc trong `internal` là đủ.  
- **Bắt đầu Đơn giản:** Không cần áp dụng cấu trúc phức tạp ngay từ đầu. Bắt đầu với cấu trúc phẳng và chỉ thêm các thư mục như `internal` hay `cmd` khi dự án phát triển và thực sự cần thiết.  
- **Giải thích:**
- Thiết kế package tốt giúp mã dễ hiểu, dễ tìm kiếm và giảm thiểu sự phụ thuộc không cần thiết.
- Các package chung chung thường trở thành nơi chứa mã không liên quan, làm tăng sự phức tạp và khó bảo trì.  
- Thư mục `internal` là một công cụ mạnh mẽ của Go để thực thi đóng gói ở cấp độ module, giúp phân định rõ ràng API công khai và chi tiết triển khai nội bộ, cho phép tái cấu trúc an toàn hơn.  
- **Tại sao quan trọng cho đội ngũ:**
- **Khả năng bảo trì:** Mã được tổ chức tốt dễ hiểu và dễ sửa đổi hơn.
- **Khả năng tái sử dụng:** Các package được thiết kế tốt, tập trung vào chức năng cụ thể có khả năng tái sử dụng cao hơn.
- **Kiểm soát API:** Thư mục `internal` giúp kiểm soát chặt chẽ những gì được coi là API công khai, giảm rủi ro phá vỡ các dự án phụ thuộc khi thay đổi mã nội bộ.
- **Giảm xung đột:** Tên package cụ thể giúp tránh xung đột tên.
- **Cách thực thi:**
- **Thảo luận Thiết kế:** Thảo luận về cấu trúc package khi bắt đầu dự án hoặc các tính năng lớn.
- **Code Review:** Đảm bảo các package mới tuân thủ nguyên tắc nhóm theo chức năng và sử dụng `internal` đúng cách.

View File

@ -0,0 +1,40 @@
**Domain-Driven Design (DDD)** là một phương pháp thiết kế và phát triển phần mềm tập trung vào **nghiệp vụ (Domain)** của một lĩnh vực đặc thù.
----
#### **1. Domain (Lĩnh vực/Nghiệp vụ chính):**
- Là nghiệp vụ chính mà hệ thống phần mềm cần giải quyết.
- Đây chính là **trọng tâm** của hệ thống và là nơi tạo ra giá trị lớn nhất cho doanh nghiệp.
#### **2. Subdomain (Nghiệp vụ con):**
- Là các **thành phần nhỏ hơn** của Domain, hỗ trợ việc xử lý nghiệp vụ.
- **DDD** chia Subdomains thành 3 loại chính:
| **Loại Subdomain** | **Đặc điểm** |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Core Subdomain** | - Nghiệp vụ cốt lõi, quan trọng nhất của hệ thống. <br>- Tốn nhiều tài nguyên, thời gian và sáng tạo. <br>- Mang lại giá trị **độc nhất** (Unique Value) cho doanh nghiệp. |
| **Supporting Subdomain** | - Hỗ trợ Core Subdomain, nhưng không phải trung tâm. <br>- Có thể sử dụng giải pháp từ bên thứ ba hoặc thuê ngoài (outsourcing). |
| **Generic Subdomain** | - Là các nghiệp vụ chung mà bất kỳ công ty nào cũng cần. <br>- Quan trọng, nhưng không tạo ra lợi thế cạnh tranh đặc biệt. |
#### **3. Bounded Context (Ngữ cảnh giới hạn):**
- Là **ranh giới** rõ ràng cho từng Subdomain trong hệ thống.
- Mỗi Bounded Context tập trung vào một phần nghiệp vụ cụ thể và có mô hình riêng.
- Các Context giao tiếp với nhau thông qua **API** hoặc **sự kiện (event)**.
#### **4. Ubiquitous Language (Ngôn ngữ chung):**
- Là **ngôn ngữ chung** được cả đội ngũ kỹ thuật và chuyên gia nghiệp vụ sử dụng.
- Mục tiêu là để mọi người hiểu rõ ràng và nhất quán về nghiệp vụ và mô hình hệ thống.
----
### **Kết luận**
DDD là một phương pháp thiết kế mạnh mẽ, đặc biệt phù hợp với các hệ thống phức tạp.
Nó giúp:
- **Tập trung vào giá trị cốt lõi** của nghiệp vụ.
- **Tổ chức hệ thống rõ ràng** với các Bounded Context.
- Đảm bảo sự phối hợp chặt chẽ giữa đội ngũ **kỹ thuật****nghiệp vụ**.
#develoment #tech #work

View File

@ -0,0 +1,4 @@
- `origin`: Khi bạn clone một repo, Git mặc định gọi **remote gốc**`origin`.
- upstream: Tên remote (khi fork) | Nhánh đang tracking
- Fork: Tạo bản sao độc lập với Repo có thể Pull Request trực tiếp vào repo và trở thành Contributor
- Clone: Tạo bản sao về Local. cả fork và clone đều có thể sync thông qua gắn upstream vào repo gốc.

View File

@ -0,0 +1,23 @@
- Tuân thủ nguyên tắc First(Fast, Independent, Repeatable, Self-Validating, Timely)
- Tên test rõ ràng có ý nghĩa
- Structure Test
- Arrange: Khởi tạo input
- Act: Thực thi hàm | Logic
- Assert: Kiểm tra output
- Assert: Tiếp tục test (testify/assert)
- Error: Dừng ngay lập tức
- Test tất cả giá trị
- Normal: các dữ liệu bình thường (a/b - b/a)
- Biên của hàm: các giới hạn trong hàm(0/a - 0/b)
- Lỗi: dữ liệu lỗi (a/0 - b/0)
- Tránh logic phức tạp
- Test không nên chứa vòng lặp hoặc `if` trừ khi thật sự cần
- Mỗi test nên kiểm tra một logic đơn lẻ và rõ ràng
- Mock External Dependencies
- Dùng mock: DB,API,File,Email (gomock,testify/mock)
- Test song song không phụ thuộc
- Tối thiểu hóa side effect
- Không test ghi file, database, hoặc gọi API thật trong unit test.
- Nếu cần test integration, viết riêng ở layer khác (Integration Test).
- Kiểm tra Coverage
- Sử dụng t.Run cho subtests

View File

View File

@ -0,0 +1,103 @@
File ```.air.toml``` là file cấu hình cho công cụ Air - một công cụ hot-reload dành cho ứng dụng Go. Air giúp các lập trình viên Go phát triển ứng dụng nhanh hơn bằng cách theo dõi các thay đổi trong mã nguồn và tự động biên dịch lại, khởi động lại ứng dụng khi có thay đổi.
```
# -----------------------------------------------------
# Air Template Configuration - Cấu hình mẫu Air
# Công cụ Hot-reload cho ứng dụng Go
# -----------------------------------------------------
air.toml
# Thư mục gốc của dự án, mặc định là thư mục hiện tại
root = "."
# Thư mục chứa dữ liệu test
testdata_dir = "testdata"
# Thư mục tạm để lưu các file biên dịch
tmp_dir = "tmp"
# Cấu hình quá trình build
[build]
# Các tham số dòng lệnh được truyền vào file thực thi
args_bin = []
# Đường dẫn đến file thực thi sau khi biên dịch
bin = "./tmp/main.exe"
# Lệnh biên dịch ứng dụng
cmd = "go build -o ./tmp/main.exe ./cmd/server/main.go"
# Độ trễ (millisecond) trước khi khởi động lại sau khi phát hiện thay đổi
delay = 1000
# Các thư mục bị loại trừ khỏi việc theo dõi
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules", ".git"]
# Các file cụ thể bị loại trừ khỏi việc theo dõi
exclude_file = [".gitignore", ".air.toml", "README.md"]
# Loại trừ các file theo biểu thức chính quy
exclude_regex = ["_test.go", "\\.DS_Store"]
# Có bỏ qua theo dõi các file không thay đổi hay không
exclude_unchanged = false
# Có theo dõi symbolic link hay không
follow_symlink = false
# Đường dẫn đầy đủ đến file thực thi (nếu cần các tham số đặc biệt)
full_bin = ""
# Các thư mục cụ thể cần theo dõi
include_dir = []
# Chỉ theo dõi các file có phần mở rộng trong danh sách này
include_ext = ["go", "tpl", "tmpl", "html", "css", "js"]
# Độ trễ trước khi kết thúc tiến trình cũ sau khi tái khởi động
kill_delay = "0s"
# File log lưu các lỗi build
log = "build-errors.log"
# Có gửi tín hiệu ngắt đến ứng dụng trước khi kill hay không
send_interrupt = false
# Có dừng theo dõi khi gặp lỗi build hay không
stop_on_error = true
# Cấu hình màu sắc cho đầu ra
[color]
# Màu cho thông tin ứng dụng
app = "green"
# Màu cho thông tin build
build = "yellow"
# Màu cho thông tin chung
main = "magenta"
# Màu cho thông tin runner
runner = "cyan"
# Màu cho thông tin watcher
watcher = "blue"
# Cấu hình cho log
[log]
# Thời gian (ms) giữa các lần update của file log
time = false
# Có hiển thị màu trong log hay không
main_only = false
# Cấu hình cho screen
[screen]
# Có xóa màn hình mỗi khi tái khởi động hay không
clear_on_rebuild = true
# Có giữ cuộn màn hình hay không
keep_scroll = true
```

View File

@ -0,0 +1,99 @@
```
docker-compose.yml
services:
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./migrations:/docker-entrypoint-initdb.d
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 5s
      timeout: 5s
      retries: 5
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
  adminer:
    image: adminer
    restart: always
    ports:
      - "8081:8080"
    depends_on:
      db:
        condition: service_healthy
  app:
    build: .
    environment:
      DB_HOST: db
      DB_USER: ${DB_USER}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_NAME: ${DB_NAME}
      DB_PORT: "5432"
      LOG_LEVEL: "debug"
    ports:
      - "8080:8080"
    depends_on:
      db:
        condition: service_healthy
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G
volumes:
  db_data:
  pgdata_dev:
networks:
  default:
    name: matching_network
    driver: bridge
```
```
Dockerfile
# Build stage
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o matching-app cmd/server/main.go
# Final image
FROM alpine:3.18
WORKDIR /app
# Add non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Copy binary and resources
COPY --from=builder --chown=appuser:appgroup /app/matching-app .
COPY --from=builder --chown=appuser:appgroup /app/migrations ./migrations
COPY --from=builder --chown=appuser:appgroup /app/configs ./configs
# Environment variables
ENV APP_PORT=8080
ENV APP_ENV=production
# Install wget for healthcheck
RUN apk --no-cache add wget
# Healthcheck
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget --no-verbose --tries=1 --spider http://localhost:${APP_PORT}/health || exit 1
EXPOSE ${APP_PORT}
USER appuser
ENTRYPOINT ["/app/matching-app"]
CMD []
```

31
Templates/Env.md Normal file
View File

@ -0,0 +1,31 @@
`.env` phù hợp **trong giai đoạn dev/local**, đơn giản và dễ triển khai.
```
.env
# Database configuration
DB_USER=
DB_PASSWORD=
DB_NAME=
# App configuration
APP_PORT=8080
APP_ENV=development
LOG_LEVEL=debug
# Email settings (SMTP)
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PSSWORD=
# AWS S3 Configuration
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_S3_BUCKET=
# Telegram Notification
TELEGRAM_TOKEN=
TELEGRAM_CHAT_ID=
```

94
Templates/Git Template.md Normal file
View File

@ -0,0 +1,94 @@
```
.gitignore
# Các file và thư mục tạm thời của Go
/tmp/
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
/vendor/
# File log
*.log
build-errors.log
# Thư mục template và các file mẫu
/template/
template-*
*-template*
example-*
*.example.*
# Thư mục tạm thời của Air
.air.conf
.air.toml.backup
# Các file cấu hình và IDE
.idea/
.vscode/
*.swp
*.swo
.DS_Store
Thumbs.db
# Các file binary được tạo ra
/bin/
/build/
# Các file môi trường và cấu hình cụ thể cho môi trường cục bộ
.env
.env.local
.env.*.local
*.local.yaml
*.local.yml
*.local.toml
*.local.json
# Các thư mục cache
.cache/
__pycache__/
node_modules/
.npm/
# Các file và thư mục khác không cần thiết
coverage/
coverage.txt
profile.out
.coverage
# Các file backup
*~
*.bak
*.backup
*.old
*.orig
```
## Git Message
```
.gitmessage
# type: feat | fix | docs | style | refactor | perf | test | chore
# scope: phần của project bị ảnh hưởng (auth, api, db...)
# summary: mô tả ngắn gọn (không viết hoa, không chấm câu)
# body: mô tả thêm (có thể bỏ qua)
# footer: liên kết issue hoặc cảnh báo BREAKING CHANGE
# ~/.gitmessage.txt
<type>(<scope>): <summary>
[Body - mô tả chi tiết]
[Footer - issue liên quan, breaking change,...]
```
**Commit Scope**
- **Dev Code**`feat`, `fix`
- **Dev Refactor → `refactor`, `perf`, `style`
- DevOps → `build`, `ci`, `chore`
- **Tester|BA**`docs`, `test`
- **Leader | Automation**`revert`

65
Templates/Makefile.md Normal file
View File

@ -0,0 +1,65 @@
```
Makefile
# --- Gitea & Runner Management ---
# Định nghĩa các target không phải là file
.PHONY: gitea-up gitea-down gitea-force-up gitea-force-down \
        gitea-runner-up gitea-runner-down gitea-runner-force-up gitea-runner-force-down
# Đường dẫn đến file docker-compose.yaml
GITEA_COMPOSE_FILE := ./docker-compose.yaml
# --- Gitea Management ---
gitea-up: ## Khởi động toàn bộ dịch vụ Gitea (DB, server và runner)
    @echo ">>> Khởi động dịch vụ Gitea..."
    docker-compose -f $(GITEA_COMPOSE_FILE) up -d
    @echo ">>> Đã khởi động dịch vụ Gitea."
gitea-down: ## Dừng toàn bộ dịch vụ Gitea (DB, server và runner)
    @echo ">>> Dừng dịch vụ Gitea..."
    docker-compose -f $(GITEA_COMPOSE_FILE) down
    @echo ">>> Đã dừng dịch vụ Gitea."
gitea-force-up: ## Khởi động lại và buộc xây dựng lại các dịch vụ Gitea
    @echo ">>> Force khởi động lại dịch vụ Gitea..."
    docker-compose -f $(GITEA_COMPOSE_FILE) up -d --force-recreate --build
    @echo ">>> Đã force khởi động lại dịch vụ Gitea."
gitea-force-down: ## Dừng và xóa các container, network và image của Gitea
    @echo ">>> Force dừng và xóa dịch vụ Gitea..."
    docker-compose -f $(GITEA_COMPOSE_FILE) down -v --rmi local
    @echo ">>> Đã force dừng và xóa dịch vụ Gitea."
# --- Runner Management ---
gitea-runner-up: ## Chỉ khởi động runner cho Gitea
    @echo ">>> Khởi động Gitea runner..."
    docker-compose -f $(GITEA_COMPOSE_FILE) up -d runner
    @echo ">>> Đã khởi động Gitea runner."
gitea-runner-down: ## Chỉ dừng runner của Gitea
    @echo ">>> Dừng Gitea runner..."
    docker-compose -f $(GITEA_COMPOSE_FILE) stop runner
    @echo ">>> Đã dừng Gitea runner."
gitea-runner-force-up: ## Force khởi động lại runner cho Gitea
    @echo ">>> Force khởi động lại Gitea runner..."
    docker-compose up -d --force-recreate --build runner
    @echo ">>> Đã force khởi động lại Gitea runner."
gitea-runner-force-down: ## Force dừng và xóa runner của Gitea
    @echo ">>> Force dừng và xóa Gitea runner..."
    docker-compose rm -fsv runner
    @echo ">>> Đã force dừng và xóa Gitea runner."
# --- Help ---
help: ## Hiển thị hướng dẫn sử dụng các lệnh
    @echo "----------------------------------------"
    @echo "   GITEA & RUNNER MANAGEMENT COMMANDS   "
    @echo "----------------------------------------"
    @echo "Usage: make [target]"
    @echo ""
    @echo "Targets:"
    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'
```

View File

@ -0,0 +1,70 @@
Template cho dev dùng CI
Build - Unit Test - Lint Test - Deploy Local
```
for golang:
name: Go CI for Feature Branch
on:
push:
branches:
- "feature/**"
jobs:
build-test:
name: Build & Test
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.21 # Hoặc phiên bản Go bạn dùng
- name: Install dependencies
run: go mod tidy
- name: Build
run: go build ./...
- name: Run unit tests
run: go test -v ./...
- name: Check formatting
run: go fmt ./...
```
```
for Nodejs
name: Feature Branch CI
on:
push:
branches:
- 'feature/**'
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Test
run: npm run test
```

View File

@ -0,0 +1,393 @@
Build - Test - Security (SCA/SAST) - Staging - Deploy
Example
```
# File: .gitea/workflows/ci.yml (Phiên bản cải thiện)
name: Go CI Pipeline
# Step 1: Thêm trigger pull_request
on:
  push:
    tags:
      - 'v*'
jobs:
  # ---- Job: Lint Code ----
  lint:
    name: Lint Code
    runs-on: ubuntu-latest
    steps:
      # Step 2: Cập nhật action versions
      - name: Checkout code
        uses: actions/checkout@v4
      # Step 2: Cập nhật action versions
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23' # Đặt phiên bản Go của bạn
          cache-dependency-path: go.sum # Bật cache cho Go modules
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@v6
        with:
          version: latest # Hoặc phiên bản cụ thể
          args: --timeout=5m # Giữ timeout
          # Gợi ý: Tạo file .golangci.yml trong repo để cấu hình chi tiết,
          # bao gồm bật các linter bảo mật như 'gosec' để có SAST cơ bản.
          # cache: true # Cân nhắc bật cache của golangci-lint nếu cần
  # ---- Job: Run Tests ----
  test:
    name: Run Tests
    runs-on: ubuntu-latest
    steps:
      # Step 2: Cập nhật action versions
      - name: Checkout code
        uses: actions/checkout@v4
      # Step 2: Cập nhật action versions
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache-dependency-path: go.sum
      # Step 7: Cài đặt tool tạo report JUnit
      - name: Install go-junit-report
        run: go install github.com/jstemmer/go-junit-report@latest
      # Step 7: Chạy test, tạo coverage
      - name: Run Go Test, Coverage
        run: |
          # Chạy test với -v để go-junit-report có input, lưu output vào file log
          go test -v -race -coverprofile=coverage.out ./... | tee test-output.log
          # Tạo report coverage dạng text (tùy chọn)
          go tool cover -func=coverage.out
  # ---- Job: Security Scan (SCA - govulncheck) ----
  sca_scan:
    name: Security Scan (SCA - govulncheck)
    runs-on: ubuntu-latest
    steps:
      # Step 2: Cập nhật action versions
      - name: Checkout code
        uses: actions/checkout@v4
      # Step 2: Cập nhật action versions
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache-dependency-path: go.sum
      # Step 5: Thay Trivy bằng govulncheck action
      - name: Run Go Vulnerability Check (govulncheck)
        uses: golang/govulncheck-action@v1
        # govulncheck sẽ tự động fail job nếu tìm thấy lỗ hổng có thể bị ảnh hưởng
  # ---- Job: Build ----
  build:
    name: Build Application
    runs-on: ubuntu-latest
    # Quan trọng: needs phải bao gồm tất cả các job kiểm tra trước đó
    steps:
      # Step 2: Cập nhật action versions
      - name: Checkout code
        uses: actions/checkout@v4
      # Step 2: Cập nhật action versions
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache-dependency-path: go.sum
      # Step 6: Build với các cờ tối ưu và version info
      - name: Build Go Application
        run: |
          # Lấy thông tin version (ví dụ: tên tag hoặc tên nhánh + SHA ngắn)
          # Lưu ý: Biến context của Gitea có thể là gitea.* thay vì github.*
          APP_VERSION="${{ gitea.ref_name }}-${{ format('{0}', gitea.sha) }}"
          # Thay main.version bằng đường dẫn thực tế đến biến version trong code của bạn
          go build -v -ldflags="-s -w -X main.version=${APP_VERSION}" -o ./bin/server ./cmd/server
      # Step 6: Upload artifact binary
      # Step 2: Cập nhật action versions
      - name: Upload build artifact
        uses: actions/upload-artifact@v3
        with:
          name: server-binary # Tên artifact rõ ràng hơn
          path: ./bin/server # Đường dẫn tới file binary
  docker-build-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest
    needs: [build]
    if: gitea.ref_name == 'master' || startsWith(gitea.ref_name, 'v')
    steps:
      - name: Checkout code # Cần checkout để lấy Dockerfile.prod
        uses: actions/checkout@v4
      - name: Download build artifact # Tải artifact binary từ job 'build'
        uses: actions/download-artifact@v3 # Dùng v3 cho Gitea
        with:
          name: server-binary # Tên artifact đã upload ở job build
          path: ./bin # Giải nén vào thư mục ./bin
      - name: Cài Docker CLI
        run: |
          apt-get update
          apt-get install -y docker.io
          docker version
      - name: Set up Docker Buildx # Công cụ build image nâng cao
        uses: docker/setup-buildx-action@v3
      - name: Login to Gitea Container Registry # Đăng nhập vào registry
        uses: docker/login-action@v3
        with:
          registry: ${{ gitea.server_url }} # Biến context chứa URL Gitea (vd: gitea.tuvanwebsite.com) - Kiểm tra lại biến đúng
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASSWORD }}
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: . # Build context là thư mục gốc
          file: ./Dockerfile # Chỉ định Dockerfile cho production
          push: true # Đẩy image lên registry
          tags: | # Đặt tên và tag cho image
            ${{ secrets.REGISTRY_URL }}/${{ gitea.repository }}:${{ gitea.ref_name }}
            ${{ secrets.REGISTRY_URL }}/${{ gitea.repository }}:latest
          # cache-from: type=gha # Bật cache build layer (tùy chọn)
          # cache-to: type=gha,mode=max
  # ---- Job: Deploy to VPS ----
  deploy:
    name: Deploy to VPS
    runs-on: ubuntu-latest
    if: gitea.ref_name == 'master' || startsWith(gitea.ref_name, 'v')
    steps:
      - name: Set image name
        run: echo "IMAGE_NAME=${{ secrets.REGISTRY_URL }}/${{ gitea.repository }}:${{ gitea.ref_name }}" >> $GITEA_ENV
      - name: Cài Docker CLI
        run: |
          apt-get update
          apt-get install -y docker.io
          apt-get install -y curl
          docker version
      - name: Deploy using Docker commands
        run: |
          curl -v https://${{ secrets.REGISTRY_URL }} || echo "Curl failed"
          echo "Deploying image: ${{ env.IMAGE_NAME }}"
          # Kéo image mới nhất về VPS host (thông qua runner)
          docker pull ${{ env.IMAGE_NAME }}
          # Dừng container cũ nếu đang chạy (bỏ qua lỗi nếu chưa có)
          docker stop my-go-app-container || true
          # Xóa container cũ nếu tồn tại (bỏ qua lỗi nếu chưa có)
          docker rm my-go-app-container || true
          # Chạy container mới từ image vừa kéo
          # Quan trọng: Thêm các biến môi trường cần thiết cho ứng dụng (-e)
          # và đảm bảo nó kết nối đúng network để thấy DB (-network)
          docker run -d \
            --name my-go-app-container \
            --network gitea_gitea_network \
            --restart always \
            -p 8080:8080 \
            -e DB_HOST=db \
            -e DB_USER=gitea \
            -e DB_PASSWORD=gitea \
            -e DB_NAME=gitea \
            ${{ env.IMAGE_NAME }} # Sử dụng image vừa build/push
```

159
Templates/Workflow.md Normal file
View File

@ -0,0 +1,159 @@
```
# File: .gitea/workflows/ci.yml (Phiên bản cải thiện)
name: Go CI Pipeline
# Step 1: Thêm trigger pull_request
on:
  push:
    tags:
      - 'v*'
jobs:
  # ---- Job: Lint Code ----
  lint:
    name: Lint Code
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23' # Đặt phiên bản Go của bạn
          cache-dependency-path: go.sum # Bật cache cho Go modules
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@v6
        with:
          version: latest # Hoặc phiên bản cụ thể
          args: --timeout=5m # Giữ timeout
  # ---- Job: Run Tests ----
  test:
    name: Run Tests
    runs-on: ubuntu-latest
    steps:
      # Step 2: Cập nhật action versions
      - name: Checkout code
        uses: actions/checkout@v4
      # Step 2: Cập nhật action versions
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache-dependency-path: go.sum
      # Step 7: Cài đặt tool tạo report JUnit
      - name: Install go-junit-report
        run: go install github.com/jstemmer/go-junit-report@latest
      # Step 7: Chạy test, tạo coverage
      - name: Run Go Test, Coverage
        run: |
          go test -race -coverprofile=coverage.out ./... | tee test-output.log
  # ---- Job: Security Scan (SCA - govulncheck) ----
  sca_scan:
    name: Security Scan (SCA - govulncheck)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache-dependency-path: go.sum
      - name: Run Go Vulnerability Check (govulncheck)
        uses: golang/govulncheck-action@v1
  # ---- Job: Build ----
  build:
    name: Build Application
    runs-on: ubuntu-latest
    needs: [lint,test]
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache-dependency-path: go.sum
      - name: Build Go Application
        run: |
          APP_VERSION="${{ gitea.ref_name }}-${{ format('{0}', gitea.sha) }}"
          go build -v -ldflags="-s -w -X main.version=${APP_VERSION}" -o ./bin/server ./cmd/server
      - name: Upload build artifact
        uses: actions/upload-artifact@v3
        with:
          name: server-binary # Tên artifact rõ ràng hơn
          path: ./bin/server # Đường dẫn tới file binary
  docker-build-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest
    needs: [build]
    if: gitea.ref_name == 'master' || startsWith(gitea.ref_name, 'v')
    steps:
      - name: Checkout code # Cần checkout để lấy Dockerfile.prod
        uses: actions/checkout@v4
      - name: Download build artifact # Tải artifact binary từ job 'build'
        uses: actions/download-artifact@v3 # Dùng v3 cho Gitea
        with:
          name: server-binary # Tên artifact đã upload ở job build
          path: ./bin # Giải nén vào thư mục ./bin
      - name: Cài Docker CLI
        run: |
          apt-get update
          apt-get install -y docker.io
      - name: Set up Docker Buildx # Công cụ build image nâng cao
        uses: docker/setup-buildx-action@v3
      - name: Login to Gitea Container Registry # Đăng nhập vào registry
        uses: docker/login-action@v3
        with:
          registry: ${{ gitea.server_url }} # Biến context chứa URL Gitea (vd: gitea.tuvanwebsite.com) - Kiểm tra lại biến đúng
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASSWORD }}
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: . # Build context là thư mục gốc
          file: ./Dockerfile # Chỉ định Dockerfile cho production
          push: true # Đẩy image lên registry
          tags: | # Đặt tên và tag cho image
            ${{ secrets.REGISTRY_URL }}/${{ gitea.repository }}:${{ gitea.ref_name }}
            ${{ secrets.REGISTRY_URL }}/${{ gitea.repository }}:latest
          # cache-from: type=gha # Bật cache build layer (tùy chọn)
          # cache-to: type=gha,mode=max
  # ---- Job: Deploy to VPS ----
  deploy:
    name: Deploy to VPS
    runs-on: ubuntu-latest
    if: gitea.ref_name == 'master' || startsWith(gitea.ref_name, 'v')
    steps:
      - name: Set image name
        run: echo "IMAGE_NAME=${{ secrets.REGISTRY_URL }}/${{ gitea.repository }}:${{ gitea.ref_name }}" >> $GITEA_ENV
      - name: Cài Docker CLI
        run: |
          apt-get update
          apt-get install -y docker.io
          docker version
      - name: Deploy using Docker commands
        run: |
          echo "Deploying image: ${{ env.IMAGE_NAME }}"
          # Kéo image mới nhất về VPS host (thông qua runner)
          docker pull ${{ env.IMAGE_NAME }}
          # Dừng container cũ nếu đang chạy (bỏ qua lỗi nếu chưa có)
          docker stop my-go-app-container || true
          # Xóa container cũ nếu tồn tại (bỏ qua lỗi nếu chưa có)
          docker rm my-go-app-container || true
          docker run -d \
            --name my-go-app-container \
            --network gitea_gitea_network \
            --restart always \
            -p 8080:8080 \
            -e DB_HOST=db \
            -e DB_USER=gitea \
            -e DB_PASSWORD=gitea \
            -e DB_NAME=gitea \
            ${{ env.IMAGE_NAME }} # Sử dụng image vừa build/push
```

58
Tổng quan.md Normal file
View File

@ -0,0 +1,58 @@
### Tổng quan về dự án
- Giới thiệu tổng quan về dự án: [Zee]
- Knowledge Base: Knowledge Base Folder
- Tài liệu theo quy trình [[Tài liệu theo Workflow]]
- Tài liệu theo Vai trò [[Tài liệu theo Role]]
- Hướng dẫn cho người mới : Guidelines Folder, Sample Folder
- Mẫu cấu trúc: Template Folder
- Diagram: [[Diagrams CICD]], [[Diagram Image]]
### Tổng quan về kiến trúc
- Sử dụng Mô hình DDD (Domain Driven Development) - Customize
- `Resource`: Các Aggregate DDD
- `Transaction`: Các Saga điều phối luồng nghiệp vụ phức tạp
- `Adapter`: Xử lý giao tiếp với các hệ thống bên ngoài
- `Helper`: Các thư viện, tiện ích dùng chung
- `UIUX`: Lớp giao diện người dùng
- Thành phần kiến trúc chi tiết (U-Hierarchy)
- `ubit`: Đơn vị logic nhỏ nhất (hàm, type, hằng số)
- `ubrick`: Tập hợp các `ubit` liên quan
- `ublock`: Thành phần hoạt động độc lập tương đối
- `ubundle`: Tính năng hoàn chỉnh cho người dùng
### Techstack
- Frontend: Thiết kế giao diện theo Framework
- Framework: Vue (Nuxtjs), Flutter (Mobile)
- Css Framework: TailwindCss
- Helper Color generation: UL Color Schema
- CMS Framework: .....
- Database: Postreql, Mongodb, ....
- CI/CD Workflow:
- Git Server: Gitea
- Runner: Gitea Runner
- Workflow Action: Gitea Action
- Server: VPS, Cloud Service(AWS, GCP, Azure)
- Artifact Management: Gitea Packages, Nexus, Docker
- Secret Management: Gitea Secret
- Containerization: Kubernetes, Docker
- Feature Flag: Go Feature Flag, Unleash Selfhosted
- *Logging: Loki + Grafana (Soon)*
- *Monitoring: Grafana(Soon)*
- *Alerting: Telegram(Soon)*
- *Infra as Code: Ansible, OpenTofu (Soon)*
- Backend:
- Ngôn ngữ: Golang, Nodejs
- ORM: https://gorm.io/
- Web Framework: https://gin-gonic.com/
- API Document: https://swagger.io/
### Thư viện ngôn ngữ
- Library Golang [[Thư viện cho Golang]]
- Library Nodejs [[Thư viện cho Nodejs]]
### Thông tin liên hệ & Contact
- Kênh chính: Google Docs
- Kênh Chat: Telegram | Discord
- Lưu trữ dữ liệu: Obsidiant, Google Drive
- Meeting: Discord