diff --git a/.env b/.env new file mode 100644 index 00000000..6dd3db3d --- /dev/null +++ b/.env @@ -0,0 +1,12 @@ +DB_USER=test +DB_PASS=secret +DB_NAME=nuts +DB_SSL_MODE=disable +API_HOST=localhost +API_PORT=3080 +API_REQUEST_LOG=false +CORS_ALLOWED_ORIGINS=http://localhost:3000 +AUTH_SIGNINGKEY=secret +AUTH_REFRESHKEY=secret +API_URL=http://localhost:3080/api +DATA_PATH=/tmp/nuts diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 00000000..35d3cbf7 --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1,2 @@ +github: Fantasy-Programming +buy_me_a_coffee: fantasypg diff --git a/.gitignore b/.gitignore index d85b98a0..4f34a8a7 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ node_modules dist dist-ssr *.local +.yaak # Editor directories and files .vscode/* @@ -47,3 +48,4 @@ Todo.md # server certs +server/api diff --git a/.yaak/yaak.fl_36p4pDsXza.yaml b/.yaak/yaak.fl_36p4pDsXza.yaml new file mode 100644 index 00000000..6e189101 --- /dev/null +++ b/.yaak/yaak.fl_36p4pDsXza.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_36p4pDsXza +createdAt: 2025-06-17T15:13:38.218343410 +updatedAt: 2025-06-17T15:13:38.218345531 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Oauth +sortPriority: -1750173200000.0 diff --git a/.yaak/yaak.fl_3aEd5zTo7v.yaml b/.yaak/yaak.fl_3aEd5zTo7v.yaml new file mode 100644 index 00000000..8b9b3d86 --- /dev/null +++ b/.yaak/yaak.fl_3aEd5zTo7v.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_3aEd5zTo7v +createdAt: 2025-06-17T15:12:41.949638837 +updatedAt: 2025-06-17T15:13:14.418600986 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Sessions +sortPriority: 1000.0 diff --git a/.yaak/yaak.fl_6GD26Nrb5d.yaml b/.yaak/yaak.fl_6GD26Nrb5d.yaml new file mode 100644 index 00000000..62c4ca86 --- /dev/null +++ b/.yaak/yaak.fl_6GD26Nrb5d.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_6GD26Nrb5d +createdAt: 2025-06-17T02:21:15.203469152 +updatedAt: 2025-06-17T02:22:45.809028202 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Webhooks +sortPriority: 8000.0 diff --git a/.yaak/yaak.fl_6nMaX2pXyX.yaml b/.yaak/yaak.fl_6nMaX2pXyX.yaml new file mode 100644 index 00000000..2c72e2c0 --- /dev/null +++ b/.yaak/yaak.fl_6nMaX2pXyX.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_6nMaX2pXyX +createdAt: 2025-06-17T02:20:39.887654787 +updatedAt: 2025-06-17T02:22:45.788186357 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Planning +sortPriority: 2000.0 diff --git a/.yaak/yaak.fl_7PuxfgR4L6.yaml b/.yaak/yaak.fl_7PuxfgR4L6.yaml new file mode 100644 index 00000000..2db51cfb --- /dev/null +++ b/.yaak/yaak.fl_7PuxfgR4L6.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_7PuxfgR4L6 +createdAt: 2025-06-17T02:17:57.392501002 +updatedAt: 2025-06-17T02:22:45.826964231 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Categories +sortPriority: 14000.0 diff --git a/.yaak/yaak.fl_BeKgF8BWyu.yaml b/.yaak/yaak.fl_BeKgF8BWyu.yaml new file mode 100644 index 00000000..3dc98da2 --- /dev/null +++ b/.yaak/yaak.fl_BeKgF8BWyu.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_BeKgF8BWyu +createdAt: 2025-06-17T02:20:15.826247683 +updatedAt: 2025-06-17T02:22:45.847906297 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Meta +sortPriority: 20000.0 diff --git a/.yaak/yaak.fl_F9uyRErzPD.yaml b/.yaak/yaak.fl_F9uyRErzPD.yaml new file mode 100644 index 00000000..251f59db --- /dev/null +++ b/.yaak/yaak.fl_F9uyRErzPD.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_F9uyRErzPD +createdAt: 2025-06-17T02:16:59.882471805 +updatedAt: 2025-06-17T02:22:45.823387279 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Budgets +sortPriority: 13000.0 diff --git a/.yaak/yaak.fl_HFsTvP2UvL.yaml b/.yaak/yaak.fl_HFsTvP2UvL.yaml new file mode 100644 index 00000000..71470bef --- /dev/null +++ b/.yaak/yaak.fl_HFsTvP2UvL.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_HFsTvP2UvL +createdAt: 2025-05-24T19:21:18.453228535 +updatedAt: 2025-06-17T02:22:56.201056564 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Transactions +sortPriority: 375.0 diff --git a/.yaak/yaak.fl_HouTUfaVmB.yaml b/.yaak/yaak.fl_HouTUfaVmB.yaml new file mode 100644 index 00000000..6e3d91e7 --- /dev/null +++ b/.yaak/yaak.fl_HouTUfaVmB.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_HouTUfaVmB +createdAt: 2025-06-17T02:20:00.069593648 +updatedAt: 2025-06-17T02:22:45.844585148 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Investments +sortPriority: 19000.0 diff --git a/.yaak/yaak.fl_KoofDQJrth.yaml b/.yaak/yaak.fl_KoofDQJrth.yaml new file mode 100644 index 00000000..f2187c0e --- /dev/null +++ b/.yaak/yaak.fl_KoofDQJrth.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_KoofDQJrth +createdAt: 2025-06-17T16:10:40.552872476 +updatedAt: 2025-06-17T19:27:51.005407078 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Open Finance +sortPriority: 0.0 diff --git a/.yaak/yaak.fl_NyMncqjBuk.yaml b/.yaak/yaak.fl_NyMncqjBuk.yaml new file mode 100644 index 00000000..be004448 --- /dev/null +++ b/.yaak/yaak.fl_NyMncqjBuk.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_NyMncqjBuk +createdAt: 2025-06-17T02:19:20.554988357 +updatedAt: 2025-06-17T02:22:45.834250039 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Data +sortPriority: 16000.0 diff --git a/.yaak/yaak.fl_NzhsYbCAJZ.yaml b/.yaak/yaak.fl_NzhsYbCAJZ.yaml new file mode 100644 index 00000000..9097b7f0 --- /dev/null +++ b/.yaak/yaak.fl_NzhsYbCAJZ.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_NzhsYbCAJZ +createdAt: 2025-06-17T02:21:07.465180037 +updatedAt: 2025-06-17T02:22:45.805438443 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Tags +sortPriority: 7000.0 diff --git a/.yaak/yaak.fl_PddkaG4pEq.yaml b/.yaak/yaak.fl_PddkaG4pEq.yaml new file mode 100644 index 00000000..e78d6664 --- /dev/null +++ b/.yaak/yaak.fl_PddkaG4pEq.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_PddkaG4pEq +createdAt: 2025-06-17T02:19:37.635663351 +updatedAt: 2025-06-17T02:22:45.838761902 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Feedback +sortPriority: 17000.0 diff --git a/.yaak/yaak.fl_Vx2bBPuqxS.yaml b/.yaak/yaak.fl_Vx2bBPuqxS.yaml new file mode 100644 index 00000000..924123e3 --- /dev/null +++ b/.yaak/yaak.fl_Vx2bBPuqxS.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_Vx2bBPuqxS +createdAt: 2025-05-24T18:38:28.497899944 +updatedAt: 2025-06-17T02:22:45.782346723 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Auth +sortPriority: 0.0 diff --git a/.yaak/yaak.fl_XonaU3qFKA.yaml b/.yaak/yaak.fl_XonaU3qFKA.yaml new file mode 100644 index 00000000..34749782 --- /dev/null +++ b/.yaak/yaak.fl_XonaU3qFKA.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_XonaU3qFKA +createdAt: 2025-06-17T02:20:58.338946937 +updatedAt: 2025-06-17T02:22:45.799362412 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Reports +sortPriority: 5000.0 diff --git a/.yaak/yaak.fl_Y9aoxepReK.yaml b/.yaak/yaak.fl_Y9aoxepReK.yaml new file mode 100644 index 00000000..ee890757 --- /dev/null +++ b/.yaak/yaak.fl_Y9aoxepReK.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_Y9aoxepReK +createdAt: 2025-06-17T02:20:46.300058160 +updatedAt: 2025-06-17T02:22:45.793461948 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Plugins +sortPriority: 3000.0 diff --git a/.yaak/yaak.fl_agD4HZ42DT.yaml b/.yaak/yaak.fl_agD4HZ42DT.yaml new file mode 100644 index 00000000..507a4894 --- /dev/null +++ b/.yaak/yaak.fl_agD4HZ42DT.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_agD4HZ42DT +createdAt: 2025-06-17T02:19:46.608483565 +updatedAt: 2025-06-17T02:22:45.841624690 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: File +sortPriority: 18000.0 diff --git a/.yaak/yaak.fl_dTjhdPdJVv.yaml b/.yaak/yaak.fl_dTjhdPdJVv.yaml new file mode 100644 index 00000000..4e56f2c7 --- /dev/null +++ b/.yaak/yaak.fl_dTjhdPdJVv.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_dTjhdPdJVv +createdAt: 2025-06-17T02:20:30.672511599 +updatedAt: 2025-06-17T02:22:45.785642542 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Notifications +sortPriority: 1000.0 diff --git a/.yaak/yaak.fl_fEMk8ujqjR.yaml b/.yaak/yaak.fl_fEMk8ujqjR.yaml new file mode 100644 index 00000000..9ed436e1 --- /dev/null +++ b/.yaak/yaak.fl_fEMk8ujqjR.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_fEMk8ujqjR +createdAt: 2025-06-17T14:48:54.154297759 +updatedAt: 2025-06-17T15:13:14.423862911 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +description: '' +headers: [] +name: MFA +sortPriority: 2000.0 diff --git a/.yaak/yaak.fl_jGKe38JHW5.yaml b/.yaak/yaak.fl_jGKe38JHW5.yaml new file mode 100644 index 00000000..0d0dc8c2 --- /dev/null +++ b/.yaak/yaak.fl_jGKe38JHW5.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_jGKe38JHW5 +createdAt: 2025-06-17T02:16:46.158133061 +updatedAt: 2025-06-17T02:22:45.830298078 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Alerts +sortPriority: 15000.0 diff --git a/.yaak/yaak.fl_mpZkn9SeUm.yaml b/.yaak/yaak.fl_mpZkn9SeUm.yaml new file mode 100644 index 00000000..0433896d --- /dev/null +++ b/.yaak/yaak.fl_mpZkn9SeUm.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_mpZkn9SeUm +createdAt: 2025-06-17T02:21:02.644100824 +updatedAt: 2025-06-17T02:22:45.802806878 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Shared +sortPriority: 6000.0 diff --git a/.yaak/yaak.fl_s5dckXYTe7.yaml b/.yaak/yaak.fl_s5dckXYTe7.yaml new file mode 100644 index 00000000..9522a952 --- /dev/null +++ b/.yaak/yaak.fl_s5dckXYTe7.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_s5dckXYTe7 +createdAt: 2025-06-17T02:20:52.563014545 +updatedAt: 2025-06-17T02:22:45.796749409 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Preferences +sortPriority: 4000.0 diff --git a/.yaak/yaak.fl_tGkTJbhPVY.yaml b/.yaak/yaak.fl_tGkTJbhPVY.yaml new file mode 100644 index 00000000..e583d5d0 --- /dev/null +++ b/.yaak/yaak.fl_tGkTJbhPVY.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_tGkTJbhPVY +createdAt: 2025-06-17T02:17:24.453419556 +updatedAt: 2025-06-17T02:22:45.820898216 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Categories +sortPriority: 12000.0 diff --git a/.yaak/yaak.fl_vWgxAmkhHJ.yaml b/.yaak/yaak.fl_vWgxAmkhHJ.yaml new file mode 100644 index 00000000..70e0f66f --- /dev/null +++ b/.yaak/yaak.fl_vWgxAmkhHJ.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_vWgxAmkhHJ +createdAt: 2025-05-24T19:21:48.212678419 +updatedAt: 2025-06-17T02:22:48.753144247 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Users +sortPriority: 500.0 diff --git a/.yaak/yaak.fl_var8RMD9gd.yaml b/.yaak/yaak.fl_var8RMD9gd.yaml new file mode 100644 index 00000000..cdd6cbeb --- /dev/null +++ b/.yaak/yaak.fl_var8RMD9gd.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_var8RMD9gd +createdAt: 2025-06-17T02:21:35.235412504 +updatedAt: 2025-06-17T02:22:45.852667523 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: AI Service +sortPriority: 21000.0 diff --git a/.yaak/yaak.fl_zwpwhxYdvP.yaml b/.yaak/yaak.fl_zwpwhxYdvP.yaml new file mode 100644 index 00000000..ea88299d --- /dev/null +++ b/.yaak/yaak.fl_zwpwhxYdvP.yaml @@ -0,0 +1,13 @@ +type: folder +model: folder +id: fl_zwpwhxYdvP +createdAt: 2025-05-24T00:56:01.149585257 +updatedAt: 2025-06-17T02:22:52.947297718 +workspaceId: wk_BbcoeNtmFM +folderId: null +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Accounts +sortPriority: 250.0 diff --git a/.yaak/yaak.rq_CEt6CQprp8.yaml b/.yaak/yaak.rq_CEt6CQprp8.yaml new file mode 100644 index 00000000..b05eec62 --- /dev/null +++ b/.yaak/yaak.rq_CEt6CQprp8.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_CEt6CQprp8 +createdAt: 2025-05-24T18:55:17.686907415 +updatedAt: 2025-06-17T19:27:51.023056036 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Get Account Balance timeline +sortPriority: 5000.0 +url: ${[ BASE_URL ]}/accounts/timeline +urlParameters: [] diff --git a/.yaak/yaak.rq_DUqCofbNTZ.yaml b/.yaak/yaak.rq_DUqCofbNTZ.yaml new file mode 100644 index 00000000..07832611 --- /dev/null +++ b/.yaak/yaak.rq_DUqCofbNTZ.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_DUqCofbNTZ +createdAt: 2025-06-17T16:11:11.867673808 +updatedAt: 2025-06-17T16:11:19.822082682 +workspaceId: wk_BbcoeNtmFM +folderId: fl_KoofDQJrth +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Link a Plaid Account +sortPriority: 999.9999 +url: '' +urlParameters: [] diff --git a/.yaak/yaak.rq_EqQjBEiqX8.yaml b/.yaak/yaak.rq_EqQjBEiqX8.yaml new file mode 100644 index 00000000..b75c569d --- /dev/null +++ b/.yaak/yaak.rq_EqQjBEiqX8.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_EqQjBEiqX8 +createdAt: 2025-06-17T15:14:03.433001843 +updatedAt: 2025-06-17T15:15:51.480704178 +workspaceId: wk_BbcoeNtmFM +folderId: fl_3aEd5zTo7v +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Get Sessions +sortPriority: -0.0001 +url: ${[ BASE_URL ]}/auth/sessions +urlParameters: [] diff --git a/.yaak/yaak.rq_JznusLFdxt.yaml b/.yaak/yaak.rq_JznusLFdxt.yaml new file mode 100644 index 00000000..348aec74 --- /dev/null +++ b/.yaak/yaak.rq_JznusLFdxt.yaml @@ -0,0 +1,30 @@ +type: http_request +model: http_request +id: rq_JznusLFdxt +createdAt: 2025-05-24T18:58:29.442542891 +updatedAt: 2025-06-30T15:04:53.249078320 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Get Accounts With Trends +sortPriority: 4000.0 +url: ${[ BASE_URL ]}/accounts/trends +urlParameters: +- enabled: true + name: start + value: '' + id: wxNJQqHsyI +- enabled: true + name: end + value: '' + id: SKYIduWXfM +- enabled: true + name: '' + value: '' + id: G4scAbaVsf diff --git a/.yaak/yaak.rq_MosRdi9CAw.yaml b/.yaak/yaak.rq_MosRdi9CAw.yaml new file mode 100644 index 00000000..4f9b4d7e --- /dev/null +++ b/.yaak/yaak.rq_MosRdi9CAw.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_MosRdi9CAw +createdAt: 2025-06-17T14:40:04.330803445 +updatedAt: 2025-06-17T19:24:49.222385677 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: POST +name: Refresh +sortPriority: 7000.0 +url: ${[ BASE_URL ]}/auth/refresh +urlParameters: [] diff --git a/.yaak/yaak.rq_NEp9gdQbCV.yaml b/.yaak/yaak.rq_NEp9gdQbCV.yaml new file mode 100644 index 00000000..1ee12730 --- /dev/null +++ b/.yaak/yaak.rq_NEp9gdQbCV.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_NEp9gdQbCV +createdAt: 2025-06-17T14:43:42.244742284 +updatedAt: 2025-06-17T15:17:53.512520936 +workspaceId: wk_BbcoeNtmFM +folderId: fl_fEMk8ujqjR +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: POST +name: MFA - Enable +sortPriority: 1000.0 +url: ${[ BASE_URL ]}/auth/mfa/enable +urlParameters: [] diff --git a/.yaak/yaak.rq_SoXyNFNN66.yaml b/.yaak/yaak.rq_SoXyNFNN66.yaml new file mode 100644 index 00000000..b958621c --- /dev/null +++ b/.yaak/yaak.rq_SoXyNFNN66.yaml @@ -0,0 +1,27 @@ +type: http_request +model: http_request +id: rq_SoXyNFNN66 +createdAt: 2025-05-24T18:38:35.002002467 +updatedAt: 2025-06-17T19:23:50.064882909 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +body: + text: |- + { + "email": "rocket_1@tutanota.com", + "password": "tuestfou92AZ@" + } +bodyType: application/json +description: '' +headers: +- enabled: true + name: Content-Type + value: application/json + id: 4SBZPUs74f +method: POST +name: Login +sortPriority: 3000.0 +url: ${[ BASE_URL ]}/auth/login +urlParameters: [] diff --git a/.yaak/yaak.rq_Sv5fX4HaWE.yaml b/.yaak/yaak.rq_Sv5fX4HaWE.yaml new file mode 100644 index 00000000..924d6a57 --- /dev/null +++ b/.yaak/yaak.rq_Sv5fX4HaWE.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_Sv5fX4HaWE +createdAt: 2025-06-17T14:47:53.808614435 +updatedAt: 2025-06-18T12:26:43.910135505 +workspaceId: wk_BbcoeNtmFM +folderId: fl_3aEd5zTo7v +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: POST +name: Delete Session +sortPriority: 0.0 +url: ${[ BASE_URL ]}/auth/sessions/:id/logout +urlParameters: [] diff --git a/.yaak/yaak.rq_WsNenhTZsZ.yaml b/.yaak/yaak.rq_WsNenhTZsZ.yaml new file mode 100644 index 00000000..493f12ca --- /dev/null +++ b/.yaak/yaak.rq_WsNenhTZsZ.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_WsNenhTZsZ +createdAt: 2025-06-17T16:09:41.483865927 +updatedAt: 2025-06-17T16:10:47.118995290 +workspaceId: wk_BbcoeNtmFM +folderId: fl_KoofDQJrth +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Link a Teller account +sortPriority: 1000.0 +url: '' +urlParameters: [] diff --git a/.yaak/yaak.rq_XjrGMVXhkM.yaml b/.yaak/yaak.rq_XjrGMVXhkM.yaml new file mode 100644 index 00000000..2b5ae25c --- /dev/null +++ b/.yaak/yaak.rq_XjrGMVXhkM.yaml @@ -0,0 +1,26 @@ +type: http_request +model: http_request +id: rq_XjrGMVXhkM +createdAt: 2025-06-17T14:43:03.047563854 +updatedAt: 2025-06-17T19:25:37.058148270 +workspaceId: wk_BbcoeNtmFM +folderId: fl_36p4pDsXza +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Oauth Login Callback +sortPriority: 1000.0 +url: ${[ BASE_URL ]}/auth/oauth/:provider/callback +urlParameters: +- enabled: true + name: :provider + value: google + id: QncBabe4Bm +- enabled: true + name: '' + value: '' + id: q6CZ7JUmGh diff --git a/.yaak/yaak.rq_XpQpih8UEE.yaml b/.yaak/yaak.rq_XpQpih8UEE.yaml new file mode 100644 index 00000000..a014eef9 --- /dev/null +++ b/.yaak/yaak.rq_XpQpih8UEE.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_XpQpih8UEE +createdAt: 2025-05-24T18:52:21.986238455 +updatedAt: 2025-06-17T19:27:51.027485631 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: DELETE +name: Delete An Account +sortPriority: 7000.0 +url: ${[ BASE_URL ]}/accounts/:id +urlParameters: [] diff --git a/.yaak/yaak.rq_XrWZquyY8D.yaml b/.yaak/yaak.rq_XrWZquyY8D.yaml new file mode 100644 index 00000000..583f0f30 --- /dev/null +++ b/.yaak/yaak.rq_XrWZquyY8D.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_XrWZquyY8D +createdAt: 2025-06-18T15:09:38.484833966 +updatedAt: 2025-06-18T15:09:38.484835917 +workspaceId: wk_BbcoeNtmFM +folderId: fl_var8RMD9gd +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: '' +sortPriority: 2999.9999 +url: '' +urlParameters: [] diff --git a/.yaak/yaak.rq_aad6UVSaht.yaml b/.yaak/yaak.rq_aad6UVSaht.yaml new file mode 100644 index 00000000..15a6f0fd --- /dev/null +++ b/.yaak/yaak.rq_aad6UVSaht.yaml @@ -0,0 +1,27 @@ +type: http_request +model: http_request +id: rq_aad6UVSaht +createdAt: 2025-05-24T18:38:43.816675861 +updatedAt: 2025-06-17T15:13:14.436558513 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +body: + text: |- + { + "email": "rocket_1@tutanota.com", + "password": "tuestfou92AZ@" + }` +bodyType: application/json +description: '' +headers: +- enabled: true + name: Content-Type + value: application/json + id: yCmJvAmz6p +method: POST +name: Signup +sortPriority: 4000.0 +url: ${[ BASE_URL ]}/auth/signup +urlParameters: [] diff --git a/.yaak/yaak.rq_ddugsB8Ynm.yaml b/.yaak/yaak.rq_ddugsB8Ynm.yaml new file mode 100644 index 00000000..6ae9fd16 --- /dev/null +++ b/.yaak/yaak.rq_ddugsB8Ynm.yaml @@ -0,0 +1,26 @@ +type: http_request +model: http_request +id: rq_ddugsB8Ynm +createdAt: 2025-05-24T18:44:06.080712163 +updatedAt: 2025-06-17T19:27:51.013495148 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Get An Account +sortPriority: 2000.0 +url: ${[ BASE_URL ]}/accounts/:id +urlParameters: +- enabled: true + name: :id + value: 87eb1b57-20a6-4027-9f41-de677e175f32 + id: cQmxps5HVe +- enabled: true + name: '' + value: '' + id: DiKC3Myq36 diff --git a/.yaak/yaak.rq_gHQhA7vyun.yaml b/.yaak/yaak.rq_gHQhA7vyun.yaml new file mode 100644 index 00000000..312910a2 --- /dev/null +++ b/.yaak/yaak.rq_gHQhA7vyun.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_gHQhA7vyun +createdAt: 2025-06-17T14:44:24.394309596 +updatedAt: 2025-06-17T15:17:57.807185301 +workspaceId: wk_BbcoeNtmFM +folderId: fl_fEMk8ujqjR +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: DELETE +name: MFA - Disable +sortPriority: 2000.0 +url: ${[ BASE_URL ]}/auth/mfa/disable +urlParameters: [] diff --git a/.yaak/yaak.rq_gaCHLVYTMm.yaml b/.yaak/yaak.rq_gaCHLVYTMm.yaml new file mode 100644 index 00000000..e8da5b19 --- /dev/null +++ b/.yaak/yaak.rq_gaCHLVYTMm.yaml @@ -0,0 +1,26 @@ +type: http_request +model: http_request +id: rq_gaCHLVYTMm +createdAt: 2025-06-17T14:40:37.201884883 +updatedAt: 2025-06-17T19:25:13.004831559 +workspaceId: wk_BbcoeNtmFM +folderId: fl_36p4pDsXza +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Oauth Login +sortPriority: 0.0 +url: ${[ BASE_URL ]}/auth/oauth/:provider +urlParameters: +- enabled: true + name: :provider + value: google + id: muS4G6cQ8k +- enabled: true + name: '' + value: '' + id: ZniSRDj8jz diff --git a/.yaak/yaak.rq_giE77RS6Y8.yaml b/.yaak/yaak.rq_giE77RS6Y8.yaml new file mode 100644 index 00000000..18ce0eaa --- /dev/null +++ b/.yaak/yaak.rq_giE77RS6Y8.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_giE77RS6Y8 +createdAt: 2025-05-24T00:55:54.607855963 +updatedAt: 2025-06-17T19:27:51.010313782 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Get All Accounts +sortPriority: 1000.0 +url: ${[ BASE_URL ]}/accounts +urlParameters: [] diff --git a/.yaak/yaak.rq_mg85djdzdz.yaml b/.yaak/yaak.rq_mg85djdzdz.yaml new file mode 100644 index 00000000..5521f02b --- /dev/null +++ b/.yaak/yaak.rq_mg85djdzdz.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_mg85djdzdz +createdAt: 2025-05-24T18:38:55.022709729 +updatedAt: 2025-06-17T15:13:33.300587953 +workspaceId: wk_BbcoeNtmFM +folderId: fl_Vx2bBPuqxS +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: POST +name: Logout +sortPriority: 4500.0 +url: ${[ BASE_URL ]}/auth/logout +urlParameters: [] diff --git a/.yaak/yaak.rq_oxucGNHWwg.yaml b/.yaak/yaak.rq_oxucGNHWwg.yaml new file mode 100644 index 00000000..3a68a958 --- /dev/null +++ b/.yaak/yaak.rq_oxucGNHWwg.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_oxucGNHWwg +createdAt: 2025-06-17T14:43:48.029510696 +updatedAt: 2025-06-17T15:17:49.057331514 +workspaceId: wk_BbcoeNtmFM +folderId: fl_fEMk8ujqjR +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: POST +name: MFA - Generate +sortPriority: 0.0 +url: ${[ BASE_URL ]}/auth/mfa/generate +urlParameters: [] diff --git a/.yaak/yaak.rq_srJdKYrDBR.yaml b/.yaak/yaak.rq_srJdKYrDBR.yaml new file mode 100644 index 00000000..8e46b1f4 --- /dev/null +++ b/.yaak/yaak.rq_srJdKYrDBR.yaml @@ -0,0 +1,22 @@ +type: http_request +model: http_request +id: rq_srJdKYrDBR +createdAt: 2025-05-24T18:45:21.704371724 +updatedAt: 2025-06-18T12:28:11.962224438 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: application/json +description: '' +headers: +- enabled: true + name: Content-Type + value: application/json + id: 3wHwG6Jtu7 +method: POST +name: Create an Account +sortPriority: 3000.0 +url: ${[ BASE_URL ]}/accounts +urlParameters: [] diff --git a/.yaak/yaak.rq_wvQSMAoHwN.yaml b/.yaak/yaak.rq_wvQSMAoHwN.yaml new file mode 100644 index 00000000..f51d9021 --- /dev/null +++ b/.yaak/yaak.rq_wvQSMAoHwN.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_wvQSMAoHwN +createdAt: 2025-06-17T16:09:45.521979053 +updatedAt: 2025-06-17T16:10:47.109039926 +workspaceId: wk_BbcoeNtmFM +folderId: fl_KoofDQJrth +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: GET +name: Link a Mono Account +sortPriority: 0.0 +url: '' +urlParameters: [] diff --git a/.yaak/yaak.rq_yuSU9QEQtn.yaml b/.yaak/yaak.rq_yuSU9QEQtn.yaml new file mode 100644 index 00000000..1d6ce19c --- /dev/null +++ b/.yaak/yaak.rq_yuSU9QEQtn.yaml @@ -0,0 +1,18 @@ +type: http_request +model: http_request +id: rq_yuSU9QEQtn +createdAt: 2025-05-24T18:45:48.021105151 +updatedAt: 2025-06-17T19:27:51.025207622 +workspaceId: wk_BbcoeNtmFM +folderId: fl_zwpwhxYdvP +authentication: {} +authenticationType: null +body: {} +bodyType: null +description: '' +headers: [] +method: PUT +name: Update an Account +sortPriority: 6000.0 +url: ${[ BASE_URL ]}/accounts/:id +urlParameters: [] diff --git a/.yaak/yaak.wk_BbcoeNtmFM.yaml b/.yaak/yaak.wk_BbcoeNtmFM.yaml new file mode 100644 index 00000000..0dc7a264 --- /dev/null +++ b/.yaak/yaak.wk_BbcoeNtmFM.yaml @@ -0,0 +1,14 @@ +type: workspace +model: workspace +id: wk_BbcoeNtmFM +createdAt: 2025-05-24T00:53:44.550811719 +updatedAt: 2025-08-30T16:58:21.020018236 +authentication: {} +authenticationType: null +description: '' +headers: [] +name: Nuts +encryptionKeyChallenge: eUE0azNuQwFaVG6qbszgXWeEitsBh5aNdvTH+7UCmtl1ISg9FSj80PW96xtGTiBCbzaChYl/1zLTBQ+k1e2aMuUNFUEnmmoYJH5qFlJ9OoVG8IKDISnZj+Y2jpjHlI2Kc9U= +settingValidateCertificates: true +settingFollowRedirects: true +settingRequestTimeout: 0 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..f46ef2b8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,59 @@ +# Agent Development Guide + +## Build & Test Commands + +### Client (TypeScript/React) +- Build: `cd apps/client && pnpm build` +- Lint: `cd apps/client && pnpm lint` (fix: `pnpm lint:fix`) +- Type check: `cd apps/client && pnpm type-check` +- Test: `cd apps/client && pnpm test` +- Dev: `cd apps/client && pnpm dev` + +### Server (Go) +- Build: `cd server && task build` (runs all checks + build) +- Lint: `cd server && task lint` +- Format: `cd server && task fmt` +- Test all: `cd server && task test` or `ENVIRONMENT=test go test ./...` +- Test single: `cd server && go test ./path/to/package -run TestName` +- Test integration: `cd server && task test:integration` +- Dev: `cd server && task dev` (hot reload with air) + +### Mobile (React Native/Expo) +- Lint: `cd apps/mobile && pnpm lint` +- Type check: `cd apps/mobile && pnpm type-check` +- Test: `cd apps/mobile && pnpm test` +- Check all: `cd apps/mobile && pnpm check-all` + +### AI Service (Python) +- Test: `cd services/ai && python -m pytest` +- Format: `cd services/ai && black .` + +## Code Style + +### TypeScript/React (Client & Mobile) +- Use **functional components** with hooks (React 19) +- Import order: external → internal → relative → types +- Formatting: **Prettier** with 160 char line length, 2 spaces, double quotes, semicolons +- Naming: kebab-case for files (`account.balance-chart.tsx`), PascalCase for components +- State: Tanstack Query for server state, Zustand for client state +- Types: Always type function params and returns; use Zod for runtime validation +- Error handling: Use react-error-boundary for component errors + +### Go (Server) +- Follow `gofmt` and `golangci-lint` standards +- Package structure: `internal/domain//{models,requests,errors,service}.go` +- Use **SQLC** for type-safe DB queries +- Error handling: Return custom domain errors (e.g., `ErrAccountNotFound`) +- Naming: Exported vars/funcs PascalCase, private camelCase +- Testing: Unit tests in `*_test.go`, integration tests with `Integration` prefix + +### Python (AI Service) +- Follow PEP 8, use Black for formatting +- Include type hints and docstrings +- Use Pydantic for data validation + +### General +- **NO COMMENTS** unless explicitly requested +- Keep functions small and focused +- Write self-documenting code with clear variable names +- Follow existing patterns in the codebase diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..036bbaa9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,437 @@ +# Contributing to Nuts + +Thank you for your interest in contributing to Nuts! This document provides guidelines and information for contributors. + +## 🤝 Ways to Contribute + +### 🐛 Bug Reports +Help us improve by reporting bugs you encounter: +- Check [existing issues](https://github.com/Fantasy-Programming/nuts/issues) first +- Use the bug report template +- Include clear reproduction steps +- Provide environment details (OS, browser, version) + +### 💡 Feature Requests +Suggest new features or improvements: +- Describe the problem you're trying to solve +- Explain your proposed solution +- Consider the impact on existing users +- Check if similar requests exist + +### 📝 Documentation +Improve our documentation: +- Fix typos and grammatical errors +- Add missing information +- Improve code examples +- Translate content to other languages + +### 🔧 Code Contributions +Submit code improvements: +- Bug fixes +- New features +- Performance improvements +- Refactoring and code quality + +### 🌍 Translations +Help make Nuts accessible globally: +- Translate UI text +- Localize email templates +- Add currency and date format support + +## 🚀 Getting Started + +### Prerequisites +- **Git**: Version control +- **Go 1.23+**: Backend development +- **Node.js 18+**: Frontend and services +- **Python 3.9+**: AI service +- **Docker**: Containerization +- **pnpm**: Package manager (preferred) +- **nix + devenv.nix**: What i use for local dev (good but not required) + +### Development Setup + +1. **Fork and Clone** + ```bash + # Fork the repository on GitHub + git clone https://github.com/your-username/nuts.git + cd nuts + ``` + +2. **Install Development Tools** + ```bash + # Using devenv (recommended) + direnv allow + + # Or install manually + go install github.com/air-verse/air@latest + npm install -g pnpm + pip install -r services/ai/requirements.txt + ``` + +3. **Setup Environment** + ```bash + # Copy environment files + cp .env.example .env + cp server/.env.example server/.env + cp client/.env.example client/.env + ``` + +4. **Start Development Services** + ```bash + # Start database and dependencies + docker-compose up -d postgres minio + + # Start backend (in separate terminal) + cd server && air + + # Start frontend (in separate terminal) + cd client && pnpm dev + + # Start AI service (optional, in separate terminal) + cd services/ai && uvicorn app.main:app --reload + + # Start mail service (optional, in separate terminal) + cd services/mail-generator && npm run dev + ``` + +5. **Verify Setup** + - Backend: http://localhost:8080/health + - Frontend: http://localhost:5173 + - AI Service: http://localhost:8000/health + - Mail Service: http://localhost:3001/health + +## 📋 Development Guidelines + +### Code Style + +#### Go (Backend) +- Follow `gofmt` formatting +- Use `golangci-lint` for linting +- Write clear, self-documenting code +- Include unit tests for new functionality + +```bash +# Format and lint Go code +cd server +go fmt ./... +golangci-lint run +go test ./... +``` + +#### TypeScript/JavaScript (Frontend & Services) +- Use ESLint and Prettier configuration +- Follow functional programming patterns +- Include JSDoc comments for complex functions +- Write tests for new components + +```bash +# Format and lint TypeScript +cd client +pnpm lint +pnpm format +pnpm test +``` + +#### Python (AI Service) +- Follow PEP 8 standards +- Use Black for formatting +- Include type hints +- Add docstrings for functions + +```bash +# Format and lint Python +cd services/ai +black . +flake8 . +python -m pytest +``` + +### Commit Guidelines + +We try to follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +(): + +[optional body] + +[optional footer(s)] +``` + +**Types:** +- `feat`: New feature +- `fix`: Bug fix +- `docs`: Documentation changes +- `style`: Code style changes (formatting, etc.) +- `refactor`: Code refactoring +- `test`: Adding or updating tests +- `chore`: Maintenance tasks + +**Examples:** +``` +feat(api): add neural transaction parsing endpoint +fix(client): resolve memory leak in transaction list +docs: update getting started guide +refactor(server): simplify authentication middleware +``` + +### Branch Naming + +Use descriptive branch names: +- `feature/transaction-rules` +- `fix/email-template-rendering` +- `docs/api-documentation` +- `refactor/database-queries` + +## 🧪 Testing + +### Running Tests + +```bash +# Backend tests +cd server && go test ./... + +# Frontend tests +cd client && pnpm test + +# AI service tests +cd services/ai && python -m pytest + +# Integration tests +./scripts/test-integration.sh + +# E2E tests (if available) +cd mobile && pnpm test:e2e +``` + +### Writing Tests + +#### Go Tests +```go +func TestTransactionCreation(t *testing.T) { + // Setup test data + tx := &Transaction{ + Amount: decimal.NewFromFloat(-25.50), + Description: "Test transaction", + } + + // Test the function + result, err := CreateTransaction(tx) + + // Assertions + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, tx.Amount, result.Amount) +} +``` + +#### React Component Tests +```typescript +import { render, screen } from '@testing-library/react'; +import { TransactionList } from './TransactionList'; + +test('renders transaction list', () => { + const transactions = [ + { id: '1', amount: -25.50, description: 'Test' } + ]; + + render(); + + expect(screen.getByText('Test')).toBeInTheDocument(); + expect(screen.getByText('-$25.50')).toBeInTheDocument(); +}); +``` + +## 📖 Documentation Standards + +### Code Documentation +- Add JSDoc/GoDoc comments for public functions +- Include usage examples in documentation +- Document complex algorithms and business logic +- Keep comments up-to-date with code changes + +### API Documentation +- Use OpenAPI/Swagger specs for REST APIs +- Include request/response examples +- Document error codes and messages +- Provide authentication details + +### User Documentation +- Write clear, step-by-step instructions +- Include screenshots for UI changes +- Test all documented procedures +- Consider different user skill levels + +## 🔍 Code Review Process + +### Submitting Pull Requests + +1. **Create Feature Branch** + ```bash + git checkout -b feature/your-feature-name + git push -u origin feature/your-feature-name + ``` + +2. **Make Changes** + - Follow coding standards + - Include tests + - Update documentation + - Keep commits focused and atomic + +3. **Pre-submission Checklist** + - [ ] Code follows style guidelines + - [ ] Tests pass locally + - [ ] Documentation updated + - [ ] No merge conflicts + - [ ] Conventional commit messages + +4. **Submit PR** + - Use the PR template + - Reference related issues + - Add screenshots for UI changes + - Request review from relevant maintainers + +### Review Criteria + +Reviewers will check for: +- **Functionality**: Does it work as intended? +- **Code Quality**: Is it readable and maintainable? +- **Performance**: Any negative performance impact? +- **Security**: Are there security implications? +- **Tests**: Adequate test coverage? +- **Documentation**: Is it properly documented? + +## 🏗️ Architecture Guidelines + +### Backend (Go) +- Follow clean architecture principles +- Use dependency injection +- Implement proper error handling +- Include comprehensive logging + +### Frontend (React) +- Use functional components with hooks +- Implement proper state management +- Follow accessibility guidelines +- Optimize for performance + +### Database +- Use migrations for schema changes +- Include both up and down migrations +- Test migrations on sample data +- Consider performance implications + +### APIs +- Follow RESTful conventions +- Use proper HTTP status codes +- Implement consistent error responses +- Include rate limiting + +## 🔐 Security Guidelines + +### General Security +- Never commit secrets or credentials +- Use environment variables for configuration +- Implement proper input validation +- Follow OWASP security guidelines + +### Authentication & Authorization +- Use secure session management +- Implement proper RBAC +- Validate all user inputs +- Log security-relevant events + +### Data Protection +- Encrypt sensitive data at rest +- Use HTTPS for all communications +- Implement proper data deletion +- Follow privacy regulations (GDPR, etc.) + +## 🚀 Release Process + +### Version Numbering +We follow [Semantic Versioning](https://semver.org/): +- **MAJOR**: Breaking changes +- **MINOR**: New features (backward compatible) +- **PATCH**: Bug fixes (backward compatible) + +### Release Steps +1. Update version numbers +2. Update CHANGELOG.md +3. Create release branch +4. Run full test suite +5. Create release PR +6. Tag release after merge +7. Deploy to production + +## 🌟 Recognition + +### Contributors +All contributors are recognized in: +- CONTRIBUTORS.md file +- GitHub contributors page +- Release notes (for significant contributions) +- Annual contributor highlights + +### Rewards +Active contributors may receive: +- Early access to new features +- Special contributor status +- Nuts swag and merchandise +- Invitation to contributor events + +## 📞 Getting Help + +### Development Questions +- **Discord**: [Join our community](https://discord.gg/nuts) +- **GitHub Discussions**: [Ask questions](https://github.com/Fantasy-Programming/nuts/discussions) +- **Email**: dev@nuts.app + +### Mentorship +New contributors can request mentorship: +- Pair programming sessions +- Code review guidance +- Architecture discussions +- Career advice + +## 📋 Issue Labels + +We use these labels to organize issues: + +**Type:** +- `bug`: Something isn't working +- `feature`: New feature request +- `enhancement`: Improvement to existing feature +- `documentation`: Documentation improvements + +**Priority:** +- `critical`: Urgent fix needed +- `high`: Important but not urgent +- `medium`: Moderate importance +- `low`: Nice to have + +**Status:** +- `needs-triage`: Needs initial review +- `ready`: Ready for development +- `in-progress`: Being worked on +- `blocked`: Waiting for dependencies + +**Area:** +- `backend`: Go server issues +- `frontend`: React app issues +- `mobile`: Mobile app issues +- `ai`: AI service issues +- `docs`: Documentation issues + +## 📜 Code of Conduct + +We are committed to fostering a welcoming community. Please read our [Code of Conduct](CODE_OF_CONDUCT.md) for details on our standards and enforcement procedures. + +## 📄 License + +By contributing to Nuts, you agree that your contributions will be licensed under the same AGPL-3.0 license that covers the project. + +--- + +Thank you for contributing to Nuts! Together, we're building the future of personal finance management. 🌰 diff --git a/README.md b/README.md index 14c4e31e..2942b1aa 100644 --- a/README.md +++ b/README.md @@ -14,48 +14,459 @@ ## About Nuts +Nuts is a comprehensive personal finance management platform designed to be your complete financial operating system. -## Features +Whether you're managing personal finances, tracking business expenses, or analyzing spending patterns, Nuts provides the tools and intelligence you need to make informed financial decisions. +## ✨ Features -## Get started +- Fully offline-first + Sync - Once loaded you can use the app without internet and your changes are synched to other devices once back online +- AI-Powered Transaction Processing: (Convert natural language like "bought coffee for $4.50" into structured transaction data) +- Advanced Rules Engine: Automatically categorize and organize transactions with custom rules +- Bank Connectivity: Connect banks worldwide through multiple providers + - **North America**: Plaid, Teller + - **Europe**: GoCardless + - **Asia**: Brankas + - **Africa**: Mono, Okra +- **Secure Connections**: Industry-standard security for all bank integrations +- Multi-Platform Support (Web, mobile) +- Financial Intelligence + - **Daily Insights**: Automated daily financial summaries and insights + - **Spending Analysis**: Advanced analytics and spending pattern recognition + - **Financial Forecasting**: AI-powered predictions and recommendations +- **Budget Tracking**: Intelligent budget management and alerts +## Get Started -## App Architecture +### Quick Start with Docker -- Monorepo -- Golang -- Python -- Kotlin -- React -- TypeScript -- Vite -- Postgres -- Minio -- TailwindCSS -- And more ... +The fastest way to get Nuts running locally: -### Hosting +```bash +# Clone the repository +git clone https://github.com/Fantasy-Programming/nuts.git +cd nuts -- -- +# Start all services +docker-compose up -d +``` -### Services +### Manual Setup -- Github Actions (CI/CD) -- Plaid (Bank connection in Canada and US) -- Teller (Bank connection in the US) -- GoCardLess (Bank connection EU) -- Brankas (Bank connection East asia) -- Mono / okra (Bank connection africa) -- Paystack (Payment processing) -- Resend (Email & Marketing) +For development or custom deployments: -- PostHog (analytics) +#### Prerequisites +- **Go 1.23+** (for backend server) +- **Node.js 18+** (for frontend and services) +- **PostgreSQL 17+** (for database) +- **Docker** (optional, for containerized services) +#### 1. Database Setup +```bash +# Start PostgreSQL (or use your existing instance) +docker run -d \ + --name nuts-postgres \ + -e POSTGRES_USER=nuts \ + -e POSTGRES_PASSWORD=nuts \ + -e POSTGRES_DB=nuts \ + -p 5432:5432 \ + postgres:17-alpine +``` -## License +#### 2. Backend Server +```bash +cd server + +# Copy environment configuration +cp .env.example .env + +# Install dependencies and run +go mod tidy +go run cmd/api/main.go +``` + +#### 3. Frontend Application +```bash +cd client + +# Install dependencies +npm install + +# Start development server +npm run dev +``` + +#### 4. AI Service (Optional) +```bash +cd services/ai + +# Create virtual environment +python -m venv venv +source venv/bin/activate + +# Install dependencies +pip install -r requirements.txt + +# Train initial model +python training/training_pipeline.py + +# Start service +uvicorn app.main:app --host 0.0.0.0 --port 8000 +``` + +#### 5. Mail Generator Service (Optional) +```bash +cd services/mail-generator + +# Install dependencies +npm install + +# Start service +npm start +``` + +### Environment Configuration + +Create `.env` files in the appropriate directories with your configuration: + +```bash +# Database +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=nuts +DB_USER=nuts +DB_PASS=nuts + +# Email (Optional) +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=your-email@gmail.com +SMTP_PASSWORD=your-app-password + +# Bank Connections (Optional) +PLAID_CLIENT_ID=your_plaid_client_id +PLAID_SECRET=your_plaid_secret +TELLER_APPLICATION_ID=your_teller_app_id + +# AI/LLM Configuration (Optional) +LLM_PROVIDER=local +LLM_LOCAL_MODEL=gemma2:2b +``` + +## 📋 Documentation + +### Getting Started +- **[Getting Started Guide](./docs/GETTING_STARTED.md)**: Comprehensive setup and first steps +- **[Project Structure](./docs/PROJECT_STRUCTURE.md)**: Understanding the codebase architecture + +### Features & Configuration +- **[Transaction Rules](./docs/transaction-rules.md)**: Configure automatic transaction processing +- **[Email System](./docs/MAIL_SYSTEM.md)**: Set up and customize the email system +- **[AI/LLM Features](./server/pkg/llm/README.md)**: Neural transaction parsing documentation + +### API & Development +- **[API Documentation](./docs/API.md)**: Complete API reference and examples +- **[Service Documentation](./services/)**: Individual service documentation + - [AI Service](./services/ai/README.md) + - [Mail Generator](./services/mail-generator/README.md) + +## 🏗️ Project Structure + +``` +nuts/ +├── client/ # React web application +├── mobile/ # React Native mobile app +├── server/ # Go backend API +├── services/ +│ ├── ai/ # Python AI/ML service +│ └── mail-generator/ # Node.js email service +├── marketing/ # Astro marketing website +├── docs/ # Documentation +└── scripts/ # Utility scripts +``` + + + +## 🏗️ Architecture + +Nuts follows a modern microservices architecture designed for scalability, maintainability, and developer experience. + +### Core Technologies + +**Frontend Stack:** +- **React 19** - Modern web interface with hooks and suspense +- **TypeScript** - Type-safe development +- **Vite** - Fast build tool and development server +- **TailwindCSS** - Utility-first CSS framework +- **Tanstack Router** - Type-safe routing +- **Tanstack Query** - Server state management + +**Mobile Stack:** +- **React Native** - Cross-platform mobile development +- **Expo** - Development platform and tools +- **TypeScript** - Type-safe mobile development +- **NativeWind** - TailwindCSS for React Native + +**Backend Stack:** +- **Go 1.23+** - High-performance REST API +- **Chi Router** - Lightweight HTTP router +- **PostgreSQL 17** - Primary database +- **SQLC** - Type-safe SQL code generation +- **River** - Background job processing + +**AI/ML Stack:** +- **Python FastAPI** - AI service for transaction categorization +- **Scikit-learn** - Machine learning models +- **Ollama** - Local LLM inference +- **OpenAI/Gemini** - Remote LLM providers + +**Infrastructure:** +- **Docker** - Containerization +- **MinIO** - S3-compatible object storage +- **Redis** - Caching and sessions +- **GitHub Actions** - CI/CD pipeline + +### Service Architecture + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Web Client │ │ Mobile App │ │ Marketing Site │ +│ (React/TS) │ │ (React Native) │ │ (Astro) │ +└─────────┬───────┘ └─────────┬───────┘ └─────────────────┘ + │ │ + └──────────┬───────────┘ + │ + ┌─────────────────┐ + │ API Gateway │ + │ (Go/Chi) │ + └─────────┬───────┘ + │ + ┌───────────────┼───────────────┐ + │ │ │ +┌───▼────┐ ┌─────▼─────┐ ┌───▼────┐ +│ AI │ │ Mail │ │ Core │ +│Service │ │Generator │ │ API │ +│(Python)│ │ (Node.js) │ │ (Go) │ +└────────┘ └───────────┘ └───┬────┘ + │ + ┌─────────▼─────────┐ + │ PostgreSQL │ + │ MinIO Storage │ + └───────────────────┘ +``` + +### External Integrations + +**Banking Providers:** +- **Plaid** - North American banks (US, Canada) +- **Teller** - US banking with modern API +- **GoCardless** - European Open Banking +- **Brankas** - Southeast Asian banks +- **Mono/Okra** - African banking infrastructure + +**Third-Party Services:** +- **Resend** - Transactional email delivery +- **PostHog** - Product analytics and feature flags +- **GitHub Actions** - Continuous integration and deployment +- **Paystack** - Payment processing (where applicable) + +### Data Flow + +1. **Transaction Import**: Bank connections automatically sync transactions +2. **AI Processing**: Neural parsing converts natural language to structured data +3. **Rule Engine**: Automatic categorization and organization +4. **Real-time Updates**: WebSocket connections for live updates +5. **Email Notifications**: Automated alerts and daily summaries +6. **Analytics**: Background processing for insights and forecasting + +### Security & Privacy + +- **End-to-End Encryption** for sensitive financial data +- **OAuth 2.0** authentication with bank providers +- **JWT** tokens for API authentication +- **Rate Limiting** on all API endpoints +- **Data Anonymization** for AI training +- **GDPR Compliance** with data export/deletion + +## 🛠️ Development + +### Prerequisites +- **Go 1.23+** +- **Node.js 18+** +- **Python 3.9+** +- **PostgreSQL 17+** +- **Docker & Docker Compose** + +### Development Workflow + +1. **Fork and Clone** + ```bash + git clone https://github.com/your-username/nuts.git + cd nuts + ``` + +2. **Setup Development Environment** + ```bash + # Install development tools (if using devenv) + direnv allow + + # Or install manually + go install github.com/air-verse/air@latest + npm install -g pnpm + ``` + +3. **Start Development Services** + ```bash + # Start database and dependencies + docker-compose up -d postgres redis minio + + # Start backend with hot reload + cd server && air + + # Start frontend with hot reload + cd client && pnpm dev + + # Start mobile development + cd mobile && pnpm start + ``` + +4. **Running Tests** + ```bash + # Backend tests + cd server && go test ./... + + # Frontend tests + cd client && pnpm test + + # AI service tests + cd services/ai && python -m pytest + ``` + +### Code Standards +- **Go**: Follow `gofmt` and `golangci-lint` standards +- **TypeScript**: ESLint + Prettier configuration +- **Python**: Black formatting + flake8 linting +- **Commit Messages**: Conventional commits format + +### API Development +- Use `sqlc` for type-safe database queries +- Follow RESTful API conventions +- Document endpoints with OpenAPI/Swagger +- Add proper error handling and validation + +## 🚀 Deployment + +### Docker Deployment (Recommended) + +```bash +# Production build +docker-compose -f compose.yml -f compose.prod.yml up -d + +# Or use provided scripts +./scripts/deploy.sh production +``` + +### Manual Deployment + +1. **Build Applications** + ```bash + # Build server + cd server && go build -o bin/server cmd/api/main.go + + # Build client + cd client && pnpm build + + # Build AI service + cd services/ai && pip install -r requirements.txt + ``` + +2. **Configure Environment** + ```bash + # Copy and configure production environment + cp .env.example .env.production + # Edit .env.production with your production values + ``` + +3. **Database Migration** + ```bash + # Run database migrations + cd server && ./bin/server migrate + ``` + +### Cloud Deployment + +Nuts can be deployed on various cloud platforms: + +- **AWS**: ECS/EKS with RDS PostgreSQL +- **Google Cloud**: Cloud Run with Cloud SQL +- **Azure**: Container Instances with Azure Database +- **DigitalOcean**: App Platform with Managed Database +- **Railway**: One-click deployment (coming soon) + +### Environment Variables + +Critical environment variables for production: + +```bash +# Database +DATABASE_URL=postgresql://user:pass@host:5432/nuts + +# Security +JWT_SECRET=your-super-secret-key +ENCRYPTION_KEY=32-byte-encryption-key + +# External Services +PLAID_CLIENT_ID=your_plaid_client_id +PLAID_SECRET=your_plaid_secret +PLAID_ENV=production + +# Email +SMTP_HOST=smtp.sendgrid.net +SMTP_USERNAME=apikey +SMTP_PASSWORD=your_sendgrid_api_key + +# Storage +S3_BUCKET=your-bucket-name +S3_REGION=us-east-1 +S3_ACCESS_KEY=your_access_key +S3_SECRET_KEY=your_secret_key +``` + +## 🤝 Contributing + +We welcome contributions! Here's how you can help: + +### Ways to Contribute +- 🐛 **Bug Reports**: Submit detailed bug reports with reproduction steps +- 💡 **Feature Requests**: Suggest new features or improvements +- 📝 **Documentation**: Improve docs, add examples, fix typos +- 🔧 **Code**: Submit pull requests for bug fixes or features +- 🌍 **Translations**: Help translate the app to other languages + +### Quick Start for Contributors +1. Fork the repository and clone your fork +2. Set up the development environment (see [Getting Started](./docs/GETTING_STARTED.md#manual-development-setup)) +3. Create a feature branch for your changes +4. Make your changes following our [coding standards](./CONTRIBUTING.md#code-style) +5. Add tests for new functionality +6. Submit a pull request with a clear description + +### Development Guidelines +- **Write Tests**: All new features should include tests +- **Documentation**: Update docs for API changes +- **Performance**: Consider performance impact of changes +- **Security**: Never commit secrets or sensitive data +- **Accessibility**: Ensure UI changes are accessible + +For detailed contribution guidelines, development setup, and coding standards, see our **[Contributing Guide](./CONTRIBUTING.md)**. + +### Community +- **Discord**: [Join our community](https://discord.gg/nuts) for discussions +- **GitHub Discussions**: [Ask questions and share ideas](https://github.com/Fantasy-Programming/nuts/discussions) +- **Issues**: [Report bugs and request features](https://github.com/Fantasy-Programming/nuts/issues) + +## 📄 License This project is licensed under the **[AGPL-3.0](https://opensource.org/licenses/AGPL-3.0)** for non-commercial use. @@ -64,3 +475,9 @@ This project is licensed under the **[AGPL-3.0](https://opensource.org/licenses/ For commercial use or deployments requiring a setup fee, please contact us for a commercial license at [engineer@nuts.com](mailto:rich@nuts.com). By using this software, you agree to the terms of the license. + +--- + +

+ Built with ❤️ by the Nuts team +

diff --git a/android/.gitignore b/android/.gitignore deleted file mode 100644 index aa724b77..00000000 --- a/android/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml -.DS_Store -/build -/captures -.externalNativeBuild -.cxx -local.properties diff --git a/android/app/.gitignore b/android/app/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/android/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts deleted file mode 100644 index 5ac6c99d..00000000 --- a/android/app/build.gradle.kts +++ /dev/null @@ -1,82 +0,0 @@ -plugins { - alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.kotlin.compose) -} - -android { - namespace = "com.fantasy.nuts" - compileSdk = 34 - - defaultConfig { - applicationId = "com.fantasy.nuts" - minSdk = 31 - targetSdk = 34 - versionCode = 1 - versionName = "1.0" - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - isMinifyEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" - ) - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = "17" - } - buildFeatures { - compose = true - } -} - -dependencies { - - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.lifecycle.runtime.ktx) - implementation(libs.androidx.activity.compose) - implementation(platform(libs.androidx.compose.bom)) - implementation(libs.androidx.ui) - implementation(libs.androidx.ui.graphics) - implementation(libs.androidx.ui.tooling.preview) - implementation(libs.androidx.material3) - implementation(libs.androidx.activity.ktx) - implementation(libs.androidx.room.compiler) - implementation(libs.androidx.room.ktx) - implementation(libs.androidx.room.runtime) - implementation(libs.retrofit) - implementation(libs.converter.gson) - implementation(libs.logging.interceptor) - implementation(libs.accompanist.systemuicontroller) - implementation(libs.accompanist.permissions) - implementation(libs.accompanist.navigation.animation) - implementation(libs.mpandroidchart) - implementation(libs.ycharts) - implementation(libs.coil.compose) - implementation(libs.androidx.datastore.preferences) - implementation(libs.androidx.work.runtime.ktx) - implementation(libs.hilt.android) - implementation(libs.hilt.android.compiler) - implementation(libs.androidx.hilt.navigation.compose) - implementation(libs.kotlinx.coroutines.android) - implementation(libs.kotlinx.coroutines.core) - implementation(libs.androidx.lifecycle.viewmodel.compose) - implementation(libs.androidx.lifecycle.runtime.compose) - implementation(libs.androidx.navigation.compose) - testImplementation(libs.junit) - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) - androidTestImplementation(platform(libs.androidx.compose.bom)) - androidTestImplementation(libs.androidx.ui.test.junit4) - debugImplementation(libs.androidx.ui.tooling) - debugImplementation(libs.androidx.ui.test.manifest) -} \ No newline at end of file diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/android/app/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/fantasy/nuts/ExampleInstrumentedTest.kt b/android/app/src/androidTest/java/com/fantasy/nuts/ExampleInstrumentedTest.kt deleted file mode 100644 index d51017ed..00000000 --- a/android/app/src/androidTest/java/com/fantasy/nuts/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.fantasy.nuts - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.fantasy.nuts", appContext.packageName) - } -} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index c3085851..00000000 --- a/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/app/src/main/java/com/fantasy/nuts/MainActivity.kt b/android/app/src/main/java/com/fantasy/nuts/MainActivity.kt deleted file mode 100644 index 35f05cc2..00000000 --- a/android/app/src/main/java/com/fantasy/nuts/MainActivity.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.fantasy.nuts - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import com.fantasy.nuts.ui.theme.NutsTheme - -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enableEdgeToEdge() - setContent { - NutsTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Greeting( - name = "Android", - modifier = Modifier.padding(innerPadding) - ) - } - } - } - } -} - -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - NutsTheme { - Greeting("Android") - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/fantasy/nuts/ui/theme/Color.kt b/android/app/src/main/java/com/fantasy/nuts/ui/theme/Color.kt deleted file mode 100644 index 78de989c..00000000 --- a/android/app/src/main/java/com/fantasy/nuts/ui/theme/Color.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.fantasy.nuts.ui.theme - -import androidx.compose.ui.graphics.Color - -val Purple80 = Color(0xFFD0BCFF) -val PurpleGrey80 = Color(0xFFCCC2DC) -val Pink80 = Color(0xFFEFB8C8) - -val Purple40 = Color(0xFF6650a4) -val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/android/app/src/main/java/com/fantasy/nuts/ui/theme/Theme.kt b/android/app/src/main/java/com/fantasy/nuts/ui/theme/Theme.kt deleted file mode 100644 index b19ca9dd..00000000 --- a/android/app/src/main/java/com/fantasy/nuts/ui/theme/Theme.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.fantasy.nuts.ui.theme - -import android.app.Activity -import android.os.Build -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext - -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 -) - -private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ -) - -@Composable -fun NutsTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, - content: @Composable () -> Unit -) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - - darkTheme -> DarkColorScheme - else -> LightColorScheme - } - - MaterialTheme( - colorScheme = colorScheme, - typography = Typography, - content = content - ) -} \ No newline at end of file diff --git a/android/app/src/main/java/com/fantasy/nuts/ui/theme/Type.kt b/android/app/src/main/java/com/fantasy/nuts/ui/theme/Type.kt deleted file mode 100644 index c8ad9b1d..00000000 --- a/android/app/src/main/java/com/fantasy/nuts/ui/theme/Type.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.fantasy.nuts.ui.theme - -import androidx.compose.material3.Typography -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp - -// Set of Material typography styles to start with -val Typography = Typography( - bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) - /* Other default text styles to override - titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, - fontSize = 11.sp, - lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9c..00000000 --- a/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d11..00000000 --- a/android/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml deleted file mode 100644 index 6f3b755b..00000000 --- a/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml deleted file mode 100644 index 6f3b755b..00000000 --- a/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78e..00000000 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp deleted file mode 100644 index b2dfe3d1..00000000 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d64..00000000 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp deleted file mode 100644 index 62b611da..00000000 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp deleted file mode 100644 index 948a3070..00000000 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 1b9a6956..00000000 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp deleted file mode 100644 index 28d4b77f..00000000 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9287f508..00000000 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index aa7d6427..00000000 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9126ae37..00000000 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml deleted file mode 100644 index f8c6127d..00000000 --- a/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml deleted file mode 100644 index b73c4b8d..00000000 --- a/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - Nuts - \ No newline at end of file diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml deleted file mode 100644 index 1612142c..00000000 --- a/android/app/src/main/res/values/themes.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - + {selectedPages.map((id) => { + const page = mockPages.find((p) => p.id === id); + if (!page) return null; + return ( + onRemovePage(id)} + /> + ); + })} + {selectedUsers.map((id) => { + const user = mockUsers.find((u) => u.id === id); + if (!user) return null; + return ( + onRemoveUser(id)} + /> + ); + })} + + + {hasSelectedContext && ( +
+ {selectedPages.map((id) => { + const page = mockPages.find((p) => p.id === id); + if (!page) return null; + return ( + onRemovePage(id)} + /> + ); + })} + {selectedUsers.map((id) => { + const user = mockUsers.find((u) => u.id === id); + if (!user) return null; + return ( + onRemoveUser(id)} + /> + ); + })} +
+ )} + + ); +} + +interface ModelSelectProps { + value: string; + onValueChange: (value: string) => void; +} + +function ModelSelect({ value, onValueChange }: ModelSelectProps) { + return ( + + ); +} + +interface AgentModeSelectProps { + value: string; + onValueChange: (value: string) => void; +} + +function AgentModeSelect({ value, onValueChange }: AgentModeSelectProps) { + return ( + + ); +} + +interface LeftActionButtonsProps { + webSearchEnabled: boolean; + thinkingEnabled: boolean; + onWebSearchToggle: (enabled: boolean) => void; + onThinkingToggle: (enabled: boolean) => void; +} + +function LeftActionButtons({ + webSearchEnabled, + thinkingEnabled, + onWebSearchToggle, + onThinkingToggle, +}: LeftActionButtonsProps) { + return ( + <> +
+ + + + + Attach file + + + + + + + + + + {thinkingEnabled ? "Disable Thinking" : "Enable Thinking"} + + + + + + + + + + + Search + + + + + {webSearchEnabled ? "Disable web search" : "Enable web search"} + + +
+ + + + + + + { }}> + + Attach file + + + onThinkingToggle(!thinkingEnabled)}> + + Thinking + {thinkingEnabled && } + + onWebSearchToggle(!webSearchEnabled)} + > + + Web search + {webSearchEnabled && } + + + + + ); +} + +interface RightActionButtonsProps { + input: string; +} + +function RightActionButtons({ input }: RightActionButtonsProps) { + const hasInput = input.trim().length > 0; + + return ( + + + + + + {hasInput ? "Send message" : "Start voice input"} + + + ); +} + +export default function AIPromptInput() { + const [input, setInput] = useState(""); + const [model, setModel] = useState("gpt-3.5-turbo"); + const [agentMode, setAgentMode] = useState("auto"); + const [contextOptions, setContextOptions] = useState([]); + const [webSearchEnabled, setWebSearchEnabled] = useState(false); + const [thinkingEnabled, setThinkingEnabled] = useState(false); + const [selectedUsers, setSelectedUsers] = useState([]); + const [selectedPages, setSelectedPages] = useState([]); + + const handleUserToggle = (userId: string) => { + setSelectedUsers((prev) => + prev.includes(userId) + ? prev.filter((id) => id !== userId) + : [...prev, userId] + ); + if (!contextOptions.includes("users")) { + setContextOptions((prev) => [...prev, "users"]); + } + }; + + const handlePageToggle = (pageId: string) => { + setSelectedPages((prev) => + prev.includes(pageId) + ? prev.filter((id) => id !== pageId) + : [...prev, pageId] + ); + if (!contextOptions.includes("pages")) { + setContextOptions((prev) => [...prev, "pages"]); + } + }; + + const handleRemoveUser = (userId: string) => { + setSelectedUsers((prev) => prev.filter((id) => id !== userId)); + }; + + const handleRemovePage = (pageId: string) => { + setSelectedPages((prev) => prev.filter((id) => id !== pageId)); + }; + + const handleSubmit = useCallback( + (e?: React.FormEvent) => { + e?.preventDefault(); + if (!input.trim()) return; + console.log("Submitted:", { + input, + model, + agentMode, + contextOptions, + webSearchEnabled, + thinkingEnabled, + selectedUsers, + selectedPages, + }); + setInput(""); + }, + [ + input, + model, + agentMode, + contextOptions, + webSearchEnabled, + thinkingEnabled, + selectedUsers, + selectedPages, + ] + ); + + return ( + +
+ + +
+
+ +
+ +