Compare commits
618 commits
pragmatism
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9989ce8df9 | |||
| f5a2c391b3 | |||
| 3fa534e464 | |||
| 107ea4449d | |||
| fb06e94ff3 | |||
| b318a1c376 | |||
| b246405845 | |||
| f7cf33d9df | |||
| 71bb6c059d | |||
| 45ebddb586 | |||
| 3b8ad3fb95 | |||
| 5103eec5ac | |||
| 0bebb0c1f2 | |||
| 2c66e30e66 | |||
| 5230b7d889 | |||
| cb40c8edab | |||
| bccd7a24cf | |||
| a413cbd37e | |||
| 54e1069ce0 | |||
| 72e64ce7b4 | |||
| 3f5e8eee1c | |||
| 45cb0c6371 | |||
| c4d9644e15 | |||
| 20b244b1e8 | |||
| 4042763344 | |||
| 511e198229 | |||
| 27c19def7d | |||
| cf921bd28a | |||
| 9aa42524d2 | |||
| dbd36c4250 | |||
| 41d6d02af7 | |||
| 0907346d3d | |||
| 527660fd3b | |||
| 28445fdb7e | |||
| ce4c676501 | |||
| 468a4fdbb7 | |||
| f62d1f4664 | |||
| 8fbcec2b1e | |||
| 53f63866d2 | |||
| 23081e63e6 | |||
| 45e3088a54 | |||
| 402c5edc3d | |||
| 156b7550c1 | |||
| f39bee2b19 | |||
| 645f43be9d | |||
| 1f5b06ffd0 | |||
| 70869a360e | |||
| 73644e4ede | |||
| 0b1876461e | |||
| 3da2574a00 | |||
| 51bb163462 | |||
| d34e24a5fc | |||
| b45ac25faa | |||
| 8eac754e04 | |||
| be0adbd46e | |||
| e32a8fb604 | |||
| f992c26026 | |||
| 6a84e8b4c4 | |||
| a23e763913 | |||
| 2ff5c43531 | |||
| ea36abbea3 | |||
| 1e1225e2d8 | |||
| 8974c91a17 | |||
| 57c0407806 | |||
| 3295ffe832 | |||
| c5c72648b6 | |||
| aacaa866da | |||
| 8f30ebfa22 | |||
| 7146c4b2ee | |||
| 4bcf3c461b | |||
| 71fe5995b5 | |||
| 947000893e | |||
| fc25f3b0fc | |||
| 4582c90f2b | |||
| 4a99ec7f4e | |||
| c51e9e1533 | |||
| e8c158427a | |||
| de4b9d9b0d | |||
| d19c5a1dff | |||
| bb08ad812e | |||
| 88a444b0f4 | |||
| 3e313b2f86 | |||
| 428595f7ec | |||
| 08d1a56732 | |||
| a21ee09c97 | |||
| d95c7d597c | |||
| af9b6a923b | |||
| 8992b7491d | |||
| 04b923cda1 | |||
| 585f49a2d3 | |||
| 236d7e7ce2 | |||
| 59030bc6fb | |||
| 588fbc3c5e | |||
| 4b692abc5f | |||
| 65e4d41970 | |||
| 1169655267 | |||
| 10c004f95f | |||
| 50baf12650 | |||
| 9977ca85b8 | |||
| 7977246712 | |||
| 1f43cd8c4a | |||
| 9545be05d8 | |||
| 1567717d21 | |||
| dc452c8602 | |||
| a87b3e0b22 | |||
| 5d9c74ed3c | |||
| 7d32b949c3 | |||
| bc9f8cae39 | |||
| 387db0caf5 | |||
| 21d05286ad | |||
| 953e96012e | |||
| 852f2969dc | |||
| 3c5145196a | |||
| 55966f329b | |||
| 7dcab89e06 | |||
| f98e5ebd06 | |||
| 7b144bd1f9 | |||
| 5abb7c2e2e | |||
| 40cc22f1fd | |||
| a305060619 | |||
| 08c05eb894 | |||
| 30ceb24903 | |||
| 6f0d9a1b91 | |||
| 875eaf4ee7 | |||
| f7597aa646 | |||
| 09f3c1f9d7 | |||
| ac02f7a4c8 | |||
| f5542eb834 | |||
| 5b13f104b2 | |||
| 45484aa6fc | |||
| 7b70341735 | |||
| 8aab947a14 | |||
| bcc042c7fa | |||
| 47b3c23b9d | |||
| ff1834ffeb | |||
| f1b3c4258e | |||
| cbb79a5311 | |||
| 338f3dd248 | |||
| 7e019145c5 | |||
| 1efcb4d1be | |||
| 541f31b2db | |||
| 46588a7ea6 | |||
| 475bcde522 | |||
| 205d0fe1a9 | |||
| 6d7df4d62f | |||
| 304505a29e | |||
| 1565b68243 | |||
| 0aa90a3a24 | |||
| 5687aeb322 | |||
| 7fc77b1d0c | |||
| bd34c9a984 | |||
| a97e35ae82 | |||
| ffd0aabede | |||
| 39f6d7904d | |||
| 7fc051446e | |||
| 6afdb0404a | |||
| 5a295b19f0 | |||
| 54a82c1322 | |||
| d6c36fdfba | |||
| bead4a3520 | |||
| 4b039b2fab | |||
| 05a8b2bc13 | |||
| cd34722dcc | |||
| 93b6058449 | |||
| 0ac8ee7989 | |||
| f51ba0afbc | |||
| 35852cb76f | |||
| 357cb4c0e7 | |||
| dd40eaae57 | |||
| 81096be802 | |||
| c82e9e360b | |||
| 5009c46634 | |||
| b293fc966e | |||
| 8c9c90181e | |||
| 588e23fb4f | |||
| 94d0923acb | |||
| d561af0981 | |||
| c6d73e73bd | |||
| 3963b72147 | |||
| 5b47759263 | |||
| a8842408f7 | |||
| 12d33d5c7c | |||
| 3bf10e44ca | |||
| 1357a5b174 | |||
| 87bbc31887 | |||
| e39f92d6fa | |||
| 1f838a33db | |||
| 03bdd539f2 | |||
| cf4946dde9 | |||
| f4fae5672f | |||
| 49f3ea066e | |||
| 1aa2e6dfd9 | |||
| e1bf241f58 | |||
| 88add80f16 | |||
| 8d6368ada1 | |||
| 586da4dbd4 | |||
| 3ec393c3ba | |||
| 5157d8ba8b | |||
| ab5147e077 | |||
| 51c8fb594a | |||
| ccd15e8df4 | |||
| 7280ebc4da | |||
| 594e1492f2 | |||
| 2741f0ff7d | |||
| 91826f3c70 | |||
| 9b90a8bce8 | |||
| 6b0d7d449d | |||
| 5477f20493 | |||
| a6dfb450d1 | |||
| f1cdc524d4 | |||
| 5c69a8eed0 | |||
| 992fd38863 | |||
| 273034faf2 | |||
| a5b747e5a8 | |||
| ffb0683292 | |||
| bff10302eb | |||
| b6cbe6d346 | |||
| 770b1b0eaa | |||
| e295d5291c | |||
| 23eaf3c9b4 | |||
| 9a63f33ac1 | |||
| 081675ac9f | |||
| 286e40c9fd | |||
| b7d5a7c934 | |||
| fb91aae7f9 | |||
| 116f914490 | |||
| c86c8ad84e | |||
| 60b6aa8cf4 | |||
| 9e649e580a | |||
| 0629ccedec | |||
| 8638eb3567 | |||
| b41061f9a2 | |||
| 78a6113b64 | |||
| 24262f4596 | |||
| a088fb9fc8 | |||
| 7e21552ae4 | |||
| b75624a412 | |||
| b00e2e0135 | |||
| 36501ae20d | |||
| 68f2e3e637 | |||
| 8f8f9fc51a | |||
| 202fb1756d | |||
| f9adf00cad | |||
| f684b5738b | |||
| 577fa28400 | |||
| 28eb4cc2cd | |||
| b6bfc782d5 | |||
| 9a28cff96e | |||
| 122332dbf3 | |||
| 5c7dc816ee | |||
| f29597987d | |||
| 2117ea20aa | |||
| cc6b6050fe | |||
| f49d8e3330 | |||
| e7fbaa52ce | |||
| 5f1b770640 | |||
| 3a5b6e4f63 | |||
| 289ebc2377 | |||
| 09e19c50b9 | |||
| 5ec97b4894 | |||
| feabd5c391 | |||
| bf2cd42336 | |||
| eba06a1616 | |||
| 1ef62eb275 | |||
| 83af75e028 | |||
| f3d571ad49 | |||
| a966c3dd35 | |||
| 2054d9bfab | |||
| 76c68d35b2 | |||
| e3949600f6 | |||
| c07d6a9af4 | |||
| 2c0988ee97 | |||
| 305732a908 | |||
| e9fe0fa701 | |||
| 7c8ac65784 | |||
| 487e1b342b | |||
| 2be7dc8ce3 | |||
| fb13f5911c | |||
| 3e8214e008 | |||
| 7c5028bfd6 | |||
| 65ec28f77a | |||
| 659570821d | |||
| fcc9d8e36c | |||
| ab2aaa3994 | |||
| d970a96417 | |||
| 45a77e936f | |||
| dc3e5cd117 | |||
| b633a38f40 | |||
| 877a151822 | |||
| e7c6eab486 | |||
| 96cdaede5f | |||
| 5d9ce3d851 | |||
| 34427b9903 | |||
| 7b1391cbd5 | |||
| 24ae18af3a | |||
| 0e0e09917a | |||
| 8c9443a0c4 | |||
| 245f34ad3c | |||
| 795c65ce6f | |||
| 4f0f7818b9 | |||
| e33d6f4a0e | |||
| 0f7efaa28e | |||
| 3c99e6de08 | |||
| 175490cbc5 | |||
| bd04fa1b40 | |||
| 1093108716 | |||
| 68ba373383 | |||
| 7bcf60c193 | |||
| e2d6eb8c24 | |||
| 5aefc9a21c | |||
| 84415097c0 | |||
| fe2987f1dd | |||
| 3f042a6e71 | |||
| da8bb150d1 | |||
| 6ecab3c616 | |||
| f9ce3fb419 | |||
| bbea646325 | |||
| 1c7f19e92b | |||
| 5384c3825e | |||
| 40a38a1dbb | |||
| 8f0fa31856 | |||
| 6e7a0d5505 | |||
| 56762b1dec | |||
| 7595ba40be | |||
| 73e763197d | |||
| db4613b322 | |||
| 0f38e9f08f | |||
| 491e7441c0 | |||
| 226337a12e | |||
| e3858db952 | |||
| 9fcf933cf4 | |||
| 44e374ce97 | |||
| e6ea794f91 | |||
| 44df9c79a9 | |||
| 788ac4d87d | |||
| 30a51697bf | |||
| 62aa619211 | |||
| 1a6d6299d5 | |||
| 17161624da | |||
| 14e41f1bfc | |||
| c59418061a | |||
| d3abe80c1c | |||
| f333d68cd6 | |||
| ae38a8705e | |||
| d6419b57d5 | |||
| c92da26f17 | |||
| 104f0e21e7 | |||
| a3c3276c06 | |||
| 33dab80fe3 | |||
| 3f13f41fce | |||
| 17f6c61db9 | |||
| 7eb61b3f47 | |||
| a5cc841915 | |||
| 35433964e8 | |||
| 0f4c1d0ecd | |||
| 7265a9ebef | |||
| f9734978de | |||
| bb5b39b137 | |||
| b6686fe00d | |||
| 48c70f9dac | |||
| 9171352a31 | |||
| 1d2aa0cabb | |||
| 3b10e6a284 | |||
| 4e99594303 | |||
| c550c4291d | |||
| 57d8bd9975 | |||
| bf8db24d64 | |||
| 04470b533b | |||
| 4fc772e4b1 | |||
| 15ffb51d1b | |||
| 45db3d0f89 | |||
| a0296ba7aa | |||
| 9ecacb02fa | |||
| cf14ab4009 | |||
| 7233603814 | |||
| 78fd9e9617 | |||
| 2b4f116787 | |||
| a1d04c1e39 | |||
| 4cf4c646fa | |||
| 58e81908bd | |||
| 726d7364ed | |||
| c0b4bd3e34 | |||
| 6bb180fd65 | |||
| 3fb682c500 | |||
| aae3b15718 | |||
| f82cf82a52 | |||
| e76a693375 | |||
| c6a86bac12 | |||
| 8f14164094 | |||
| c005667f8c | |||
| 9202963ace | |||
| f66b4c4b29 | |||
| 455232a290 | |||
| 34c2f0e3f2 | |||
| 1f4259d526 | |||
| 6bbfcbe183 | |||
| 4755a80550 | |||
| 145957dcd3 | |||
| 5845efbc57 | |||
| 2a47fd6c65 | |||
| afccd1f719 | |||
| 4882324c8a | |||
| 192df5d523 | |||
| 4b197aff16 | |||
| ef2a4cf065 | |||
| e81be659a6 | |||
| c98e03ed4a | |||
| 4657a6f40b | |||
| 69fc248904 | |||
| e80e5baf8c | |||
| d3a6522f53 | |||
| 5e326b8b43 | |||
| 9d0099c3a1 | |||
| 0a3ecf6f9f | |||
| b830fb8678 | |||
| a0b8d5a61b | |||
| 175458d355 | |||
| 20d91f00d3 | |||
| 07ba6cb000 | |||
| 15f16fa387 | |||
| a22977406b | |||
| 5b259a2c5a | |||
| f514cb795a | |||
| aa82f2feee | |||
| 2938fe15da | |||
| 54a9ec1b52 | |||
| db5d393d50 | |||
| 7d3a60535e | |||
| 3f30e27da9 | |||
| 1d7b8b4e8b | |||
| 690e739e51 | |||
| 0cc5ce7400 | |||
| fdc330fb29 | |||
| d2e695d6b0 | |||
| f91c799012 | |||
| 51f7fc0947 | |||
| 7ae3a7181d | |||
| 298e5097ad | |||
| 1012d63314 | |||
| 137e71f819 | |||
| 478363d562 | |||
|
|
7e71bf3e15 | ||
|
|
96c69dc08b | ||
|
|
0a02759a89 | ||
|
|
3d5a9d7fab | ||
|
|
9c1a2eae34 | ||
| 4504108799 | |||
| 7d8c60b4b9 | |||
| 121eb4b5f2 | |||
| 310318e879 | |||
| 5abd8282d0 | |||
| fce6c76f07 | |||
| f3dc4c989c | |||
| 5fa88d49e0 | |||
| 4167906c00 | |||
| 78609fe3c7 | |||
| dbede36f10 | |||
| 44982757f5 | |||
| 2539161d71 | |||
| 83272e946c | |||
| 16f776f9b5 | |||
| 11465ab7eb | |||
| 78f6eea275 | |||
| 7ee2816f10 | |||
| dcdc237bfa | |||
| 38307a9710 | |||
| f99ba5a911 | |||
| 9861f1cefc | |||
| 153cb41918 | |||
| 176f07b345 | |||
| 254a760f7b | |||
| 79521d1659 | |||
| ca0ca5f72c | |||
| 54e50d94a3 | |||
| beb9e19c8c | |||
| ca7ed157e1 | |||
| 39190da88e | |||
| 94f73b1f66 | |||
| ea6a154d5d | |||
| 0993b8a712 | |||
| b610d2f1b9 | |||
| 903f48cd14 | |||
| 530456ea7f | |||
| dc27c7f082 | |||
| db96fd6efe | |||
| 83ce8b70ee | |||
| cea656ea17 | |||
| fb2129eead | |||
| 313e3dfc78 | |||
| d41fbdb5eb | |||
| 5275cbaa31 | |||
| 665a4a107a | |||
| b8aa71e206 | |||
| cad04a41bf | |||
| 50ee73e275 | |||
| 3aeb941638 | |||
| 6fd3c019ba | |||
| efce147586 | |||
| e706eb9fbb | |||
| 1fdacca368 | |||
| fd0ad0f785 | |||
| 219e01a9f3 | |||
| 3660a86afc | |||
| c05c218891 | |||
| cf3f9d806c | |||
| 25eac616fb | |||
| 542763983d | |||
| 116c5885f6 | |||
| c939c4f1dd | |||
| abc73de918 | |||
| 06c0768fe8 | |||
| 94dcbdda66 | |||
| 40b0b2d12c | |||
| d68c257b66 | |||
| 1e1e71d920 | |||
| 7b4735dd71 | |||
| 007cde436b | |||
| 511de99cef | |||
| 65039a255f | |||
| b9f7725886 | |||
| f4b303e23c | |||
| 18c1398758 | |||
| c4779fe55e | |||
| 059489b501 | |||
| eba68bb8ee | |||
| 1f1cdd8d22 | |||
| 573f5b4f7b | |||
| aa22617b97 | |||
| 1dc5ee9512 | |||
| 6c2a551a8e | |||
| 65cb081a2b | |||
| edda3464c6 | |||
| cd76b543e9 | |||
| 682f0e7fa3 | |||
| 9dbc16aef6 | |||
| f8a8cc97b0 | |||
| 98fb4c9713 | |||
| a440589bad | |||
| 39773cc7a9 | |||
| 076447086d | |||
| 95719cbe4c | |||
| a4ff41f13c | |||
| 7800c2d149 | |||
| 2a4cdedb8b | |||
| 7b07f3b6ab | |||
| 98d9c61af9 | |||
| eb3b30ef1c | |||
| 89643ae926 | |||
| 54f5019b6b | |||
| 9820144a6e | |||
| fccf542748 | |||
| 75113b15a8 | |||
| 454a8c92f4 | |||
| 1c6c48cfc9 | |||
| 808b0b1109 | |||
| 2a29f45781 | |||
| 131918ba09 | |||
| 47ac1cdc29 | |||
| 104812ec65 | |||
| 301325f925 | |||
| 74bc8556cc | |||
| c2cacf9c5e | |||
| 539935a730 | |||
| 6a6776eb3c | |||
| 6d5c93797a | |||
| 26535ba803 | |||
| b0da676a10 | |||
| d778dcb17b | |||
| 98783fc83d | |||
| 5ed5b21ad1 | |||
| 9c65220965 | |||
| ee4cec0013 | |||
| 068f011907 | |||
| df257e990e | |||
| 03a03c3a3f | |||
| 974e1e688a | |||
| b5896c2493 | |||
| 5221bc9ec5 | |||
| 65f1c762c1 | |||
| 5c3d772010 | |||
| 164a0972a4 | |||
| 1ccd1f9cc9 | |||
| e194dcf9e6 | |||
| 3c5c01f4ea | |||
| e50bcee8c7 | |||
| 198bcf8edb | |||
| 613a14ecfb | |||
| cd2dd0f6f6 | |||
| a13e3f7c51 | |||
| c9eabb0f0d | |||
| edb40ea8e0 | |||
| 416d0c7de6 | |||
| 24e0f3c3a6 | |||
| 22d7bdc16e | |||
| f67e25fcd3 | |||
| 93e46dfdaa | |||
| 0b591e663e | |||
| b3c35feff7 | |||
| 0ac7c4ed03 | |||
| cb9c94223d | |||
| 1f5c25ce79 | |||
| 2a45c5d7c4 | |||
| b6a0faf879 | |||
| f34e760697 | |||
| b6f69951f4 | |||
| 92f2c012f0 | |||
| 14d95994b9 | |||
| 4f7f0fff0e | |||
| d48791290a | |||
| 8831c56c90 | |||
| b9d6816644 | |||
| c258a61ad5 | |||
| 3326e07234 | |||
| 7bd5375d1a | |||
| 3dbadbafcb | |||
| b431ae6602 | |||
| 7e89d183ff | |||
| b2f143f664 |
52 changed files with 16174 additions and 1339 deletions
|
|
@ -1,5 +1,5 @@
|
|||
[build]
|
||||
rustc-wrapper = "sccache"
|
||||
# rustc-wrapper = "sccache"
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
|
|
|
|||
8
.env.example
Normal file
8
.env.example
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# General Bots Environment Configuration
|
||||
# Copy this file to .env and fill in values
|
||||
# NEVER commit .env to version control
|
||||
|
||||
# Vault connection
|
||||
VAULT_ADDR=https://127.0.0.1:8200
|
||||
VAULT_TOKEN=<your-vault-token-here>
|
||||
VAULT_CACERT=./botserver-stack/vault/certs/ca.crt
|
||||
16
.forgejo/workflows/botapp.yaml
Normal file
16
.forgejo/workflows/botapp.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: Botapp CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botapp/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botapp
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
16
.forgejo/workflows/botbook.yaml
Normal file
16
.forgejo/workflows/botbook.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: Botbook CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botbook/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botbook
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
16
.forgejo/workflows/botdevice.yaml
Normal file
16
.forgejo/workflows/botdevice.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: Botdevice CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botdevice/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botdevice
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
16
.forgejo/workflows/botmodels.yaml
Normal file
16
.forgejo/workflows/botmodels.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: Botmodels CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botmodels/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botmodels
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
16
.forgejo/workflows/botplugin.yaml
Normal file
16
.forgejo/workflows/botplugin.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: Botplugin CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botplugin/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botplugin
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
29
.forgejo/workflows/botserver.yaml
Normal file
29
.forgejo/workflows/botserver.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
name: BotServer CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botserver/**'
|
||||
- 'botlib/**'
|
||||
- 'Cargo.lock'
|
||||
- '.forgejo/workflows/botserver.yaml'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botserver
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
git submodule update --init --recursive botlib botserver
|
||||
cargo build -p botserver
|
||||
- name: Deploy
|
||||
run: |
|
||||
sudo incus exec system -- systemctl stop botserver || true
|
||||
sudo incus exec system -- pkill -x botserver || true
|
||||
sleep 1
|
||||
sudo incus file push /opt/gbo/work/botserver/target/debug/botserver system:/opt/gbo/bin/botserver --mode=0755
|
||||
sudo incus exec system -- systemctl start botserver
|
||||
sleep 2
|
||||
sudo incus exec system -- pgrep -x botserver && echo "✅ BotServer Deployed" || echo "❌ Failed"
|
||||
16
.forgejo/workflows/bottest.yaml
Normal file
16
.forgejo/workflows/bottest.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: Bottest CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'bottest/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/bottest
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
20
.forgejo/workflows/botui.yaml
Normal file
20
.forgejo/workflows/botui.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
name: BotUI CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'botui/**'
|
||||
- 'botlib/**'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
steps:
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/gbo/work/botui
|
||||
git reset --hard HEAD && git clean -fd
|
||||
git pull
|
||||
cargo build
|
||||
- name: Deploy
|
||||
run: |
|
||||
echo "BotUI deployed"
|
||||
56
.gitignore
vendored
56
.gitignore
vendored
|
|
@ -2,15 +2,23 @@
|
|||
target/
|
||||
*.out
|
||||
bin/
|
||||
|
||||
*.png
|
||||
*.jpg
|
||||
# Logs
|
||||
*.log
|
||||
*logfile*
|
||||
*-log*
|
||||
.vscode
|
||||
.zed
|
||||
.gemini
|
||||
.claude
|
||||
|
||||
|
||||
# Temporary files
|
||||
.tmp*
|
||||
.tmp/*
|
||||
.tmp
|
||||
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
|
|
@ -24,19 +32,24 @@ work/
|
|||
|
||||
# Documentation build
|
||||
docs/book
|
||||
|
||||
.ruff_cache
|
||||
.goutputstream*
|
||||
# Installers (keep gitkeep)
|
||||
botserver-installers/*
|
||||
!botserver-installers/.gitkeep
|
||||
botserver-stack
|
||||
TODO*
|
||||
work
|
||||
.swp
|
||||
|
||||
# Lock file (regenerated from Cargo.toml)
|
||||
Cargo.lock
|
||||
# Lock file
|
||||
# Cargo.lock (should be tracked)
|
||||
.kiro
|
||||
config
|
||||
|
||||
# Data directory (contains bot configs and API keys)
|
||||
data/
|
||||
|
||||
# Playwright
|
||||
node_modules/
|
||||
/test-results/
|
||||
|
|
@ -44,3 +57,38 @@ node_modules/
|
|||
/blob-report/
|
||||
/playwright/.cache/
|
||||
/playwright/.auth/
|
||||
.playwright*
|
||||
.ruff_cache
|
||||
.opencode
|
||||
config/directory_config.json
|
||||
# CI cache bust: Fri Feb 13 22:33:51 UTC 2026
|
||||
|
||||
# Secrets - NEVER commit these files
|
||||
vault-unseal-keys
|
||||
start-and-unseal.sh
|
||||
vault-token-*
|
||||
init.json
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
*.cert
|
||||
$null
|
||||
AppData/
|
||||
build_errors*.txt
|
||||
build_errors_utf8.txt
|
||||
check.json
|
||||
clippy*.txt
|
||||
errors.txt
|
||||
errors_utf8.txt
|
||||
|
||||
vault-unseal-keysdefault-vault.tar
|
||||
prompts/sec-bots.md
|
||||
AGENTS-PROD.md
|
||||
|
||||
# Backup files
|
||||
*.head
|
||||
*.bad2
|
||||
*.bad
|
||||
*.check
|
||||
*.fix
|
||||
*.bak
|
||||
|
|
|
|||
23
.gitmodules
vendored
23
.gitmodules
vendored
|
|
@ -1,42 +1,43 @@
|
|||
[submodule "botapp"]
|
||||
path = botapp
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botapp.git
|
||||
url = ../botapp.git
|
||||
|
||||
[submodule "botserver"]
|
||||
path = botserver
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botserver.git
|
||||
url = ../BotServer.git
|
||||
|
||||
[submodule "botlib"]
|
||||
path = botlib
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botlib.git
|
||||
url = ../botlib.git
|
||||
|
||||
[submodule "botui"]
|
||||
path = botui
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botui.git
|
||||
url = ../botui.git
|
||||
|
||||
[submodule "botbook"]
|
||||
path = botbook
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botbook.git
|
||||
url = ../botbook.git
|
||||
|
||||
[submodule "bottest"]
|
||||
path = bottest
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/bottest.git
|
||||
url = ../bottest.git
|
||||
|
||||
[submodule "botdevice"]
|
||||
path = botdevice
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botdevice.git
|
||||
url = ../botdevice.git
|
||||
|
||||
[submodule "botmodels"]
|
||||
path = botmodels
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botmodels.git
|
||||
url = ../botmodels.git
|
||||
|
||||
[submodule "botplugin"]
|
||||
path = botplugin
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/botplugin.git
|
||||
url = ../botplugin.git
|
||||
|
||||
[submodule "bottemplates"]
|
||||
path = bottemplates
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/bottemplates.git
|
||||
url = ../bottemplates.git
|
||||
|
||||
[submodule ".github"]
|
||||
path = .github
|
||||
url = https://alm.pragmatismo.com.br/GeneralBots/.github.git
|
||||
url = ../.github.git
|
||||
|
|
|
|||
9
.idea/gb.iml
generated
9
.idea/gb.iml
generated
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
10
.idea/libraries/botserver_installers.xml
generated
10
.idea/libraries/botserver_installers.xml
generated
|
|
@ -1,10 +0,0 @@
|
|||
<component name="libraryTable">
|
||||
<library name="botserver-installers">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/botserver/botserver-installers/llama-b7345-bin-ubuntu-x64.zip!/" />
|
||||
<root url="jar://$PROJECT_DIR$/botserver/botserver-installers/vault_1.15.4_linux_amd64.zip!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/gb.iml" filepath="$PROJECT_DIR$/.idea/gb.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
52
.idea/workspace.xml
generated
52
.idea/workspace.xml
generated
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="32fd08b0-7933-467d-9a46-1a53fd2da15c" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/botserver" beforeDir="false" afterPath="$PROJECT_DIR$/botserver" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo"><![CDATA[{
|
||||
"associatedIndex": 1
|
||||
}]]></component>
|
||||
<component name="ProjectId" id="38qdWTFkX8Nem4LzgigXpAycSN7" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"git-widget-placeholder": "main",
|
||||
"last_opened_file_path": "/home/rodriguez/src/gb",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-jdk-30f59d01ecdd-2fc7cc6b9a17-intellij.indexing.shared.core-IU-253.30387.90" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="32fd08b0-7933-467d-9a46-1a53fd2da15c" name="Changes" comment="" />
|
||||
<created>1769531070022</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1769531070022</updated>
|
||||
<workItem from="1769531115917" duration="176000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
{
|
||||
"languages": {
|
||||
"typescript": {
|
||||
"name": "typescript-language-server",
|
||||
"command": "typescript-language-server",
|
||||
"args": [
|
||||
"--stdio"
|
||||
],
|
||||
"file_extensions": [
|
||||
"ts",
|
||||
"js",
|
||||
"tsx",
|
||||
"jsx"
|
||||
],
|
||||
"project_patterns": [
|
||||
"package.json",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/node_modules/**",
|
||||
"**/dist/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {
|
||||
"preferences": {
|
||||
"disableSuggestions": false
|
||||
}
|
||||
},
|
||||
"request_timeout_secs": 60
|
||||
},
|
||||
"python": {
|
||||
"name": "pyright",
|
||||
"command": "pyright-langserver",
|
||||
"args": [
|
||||
"--stdio"
|
||||
],
|
||||
"file_extensions": [
|
||||
"py"
|
||||
],
|
||||
"project_patterns": [
|
||||
"pyproject.toml",
|
||||
"setup.py",
|
||||
"requirements.txt",
|
||||
"pyrightconfig.json"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/__pycache__/**",
|
||||
"**/venv/**",
|
||||
"**/.venv/**",
|
||||
"**/.pytest_cache/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {},
|
||||
"request_timeout_secs": 60
|
||||
},
|
||||
"rust": {
|
||||
"name": "rust-analyzer",
|
||||
"command": "rust-analyzer",
|
||||
"args": [],
|
||||
"file_extensions": [
|
||||
"rs"
|
||||
],
|
||||
"project_patterns": [
|
||||
"Cargo.toml"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/target/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {
|
||||
"cargo": {
|
||||
"buildScripts": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"enable": true,
|
||||
"enableExperimental": true
|
||||
},
|
||||
"workspace": {
|
||||
"symbol": {
|
||||
"search": {
|
||||
"scope": "workspace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request_timeout_secs": 60
|
||||
},
|
||||
"java": {
|
||||
"name": "jdtls",
|
||||
"command": "jdtls",
|
||||
"args": [],
|
||||
"file_extensions": [
|
||||
"java"
|
||||
],
|
||||
"project_patterns": [
|
||||
"pom.xml",
|
||||
"build.gradle",
|
||||
"build.gradle.kts",
|
||||
".project"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/target/**",
|
||||
"**/build/**",
|
||||
"**/.gradle/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {
|
||||
"settings": {
|
||||
"java": {
|
||||
"compile": {
|
||||
"nullAnalysis": {
|
||||
"mode": "automatic"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"annotationProcessing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request_timeout_secs": 60
|
||||
},
|
||||
"ruby": {
|
||||
"name": "solargraph",
|
||||
"command": "solargraph",
|
||||
"args": [
|
||||
"stdio"
|
||||
],
|
||||
"file_extensions": [
|
||||
"rb"
|
||||
],
|
||||
"project_patterns": [
|
||||
"Gemfile",
|
||||
"Rakefile"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/vendor/**",
|
||||
"**/tmp/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {},
|
||||
"request_timeout_secs": 60
|
||||
},
|
||||
"go": {
|
||||
"name": "gopls",
|
||||
"command": "gopls",
|
||||
"args": [],
|
||||
"file_extensions": [
|
||||
"go"
|
||||
],
|
||||
"project_patterns": [
|
||||
"go.mod",
|
||||
"go.sum"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/vendor/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {
|
||||
"usePlaceholders": true,
|
||||
"completeUnimported": true
|
||||
},
|
||||
"request_timeout_secs": 60
|
||||
},
|
||||
"cpp": {
|
||||
"name": "clangd",
|
||||
"command": "clangd",
|
||||
"args": [
|
||||
"--background-index"
|
||||
],
|
||||
"file_extensions": [
|
||||
"cpp",
|
||||
"cc",
|
||||
"cxx",
|
||||
"c",
|
||||
"h",
|
||||
"hpp",
|
||||
"hxx"
|
||||
],
|
||||
"project_patterns": [
|
||||
"CMakeLists.txt",
|
||||
"compile_commands.json",
|
||||
"Makefile"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"**/build/**",
|
||||
"**/cmake-build-**/**"
|
||||
],
|
||||
"multi_workspace": false,
|
||||
"initialization_options": {},
|
||||
"request_timeout_secs": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'botserver'",
|
||||
"cargo": {
|
||||
"args": ["run", "--bin=botserver", "--package=botserver", "--manifest-path=${workspaceFolder}/botserver/Cargo.toml"],
|
||||
"filter": {
|
||||
"name": "botserver",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"env": {
|
||||
"RUST_LOG": "trace,aws_sigv4=off,aws_smithy_checksums=off,mio=off,reqwest=off,aws_runtime=off,aws_smithy_http_client=off,rustls=off,hyper_util=off,aws_smithy_runtime=off,aws_smithy_runtime_api=off,tracing=off,aws_sdk_s3=off"
|
||||
|
||||
},
|
||||
"cwd": "${workspaceFolder}/botserver"
|
||||
},
|
||||
]
|
||||
}
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"git.ignoreLimitWarning": true,
|
||||
"Codegeex.SidebarUI.LanguagePreference": "English",
|
||||
"Codegeex.RepoIndex": true
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"languages": {
|
||||
"Rust": {
|
||||
"enable_language_server": false,
|
||||
},
|
||||
},
|
||||
}
|
||||
11680
Cargo.lock
generated
Normal file
11680
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,7 @@ members = [
|
|||
"bottest",
|
||||
"botui",
|
||||
]
|
||||
exclude = ["backup-to-s3"]
|
||||
|
||||
[workspace.lints.rust]
|
||||
|
||||
|
|
@ -109,6 +110,7 @@ url = "2.5"
|
|||
dirs = "5.0"
|
||||
tempfile = "3"
|
||||
walkdir = "2.5.0"
|
||||
notify = "8.0"
|
||||
|
||||
# ─── COMPRESSION / ARCHIVES ───
|
||||
flate2 = "1.0"
|
||||
|
|
@ -174,7 +176,7 @@ indicatif = "0.18.0"
|
|||
|
||||
# ─── MEMORY ALLOCATOR ───
|
||||
tikv-jemallocator = "0.6"
|
||||
tikv-jemalloc-ctl = { version = "0.6", default-features = false }
|
||||
tikv-jemalloc-ctl = { version = "0.6", default-features = false, features = ["stats"] }
|
||||
|
||||
# ─── SECRETS / VAULT ───
|
||||
vaultrs = "0.7"
|
||||
|
|
@ -196,7 +198,7 @@ csv = "1.3"
|
|||
tonic = { version = "0.14.2", default-features = false }
|
||||
|
||||
# ─── STATIC FILES ───
|
||||
rust-embed = "8.5"
|
||||
rust-embed = { version = "8.5", features = ["interpolate-folder-path"] }
|
||||
mime_guess = "2.0"
|
||||
|
||||
# ─── TAURI (Desktop/Mobile) ───
|
||||
|
|
|
|||
|
|
@ -1,204 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# DEPENDENCIES-DEV.sh - Development Dependencies for General Bots
|
||||
#
|
||||
# This script installs additional packages needed for BUILDING botserver from source.
|
||||
# Only install these if you plan to compile the code yourself.
|
||||
#
|
||||
# Usage: sudo ./DEPENDENCIES-DEV.sh
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN} General Bots Development Dependencies${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
|
||||
# Check root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}Error: Run as root (use sudo)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect OS
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
OS=$ID
|
||||
else
|
||||
echo -e "${RED}Error: Cannot detect OS${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}OS: $OS${NC}"
|
||||
|
||||
install_debian_ubuntu() {
|
||||
apt-get update
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
gcc \
|
||||
g++ \
|
||||
clang \
|
||||
llvm-dev \
|
||||
libclang-dev \
|
||||
cmake \
|
||||
make \
|
||||
git \
|
||||
pkg-config \
|
||||
libssl-dev \
|
||||
libpq-dev \
|
||||
liblzma-dev \
|
||||
zlib1g-dev \
|
||||
libabseil-dev \
|
||||
protobuf-compiler \
|
||||
libprotobuf-dev \
|
||||
automake \
|
||||
bison \
|
||||
flex \
|
||||
gperf \
|
||||
libtool \
|
||||
m4 \
|
||||
nasm \
|
||||
python3 \
|
||||
python3-pip \
|
||||
nodejs \
|
||||
npm
|
||||
|
||||
# Cross-compilation toolchains
|
||||
apt-get install -y \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
gcc-x86-64-linux-gnu || true
|
||||
}
|
||||
|
||||
install_fedora_rhel() {
|
||||
dnf groupinstall -y "Development Tools"
|
||||
dnf install -y \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
clang \
|
||||
llvm-devel \
|
||||
clang-devel \
|
||||
cmake \
|
||||
make \
|
||||
git \
|
||||
pkgconf-devel \
|
||||
openssl-devel \
|
||||
libpq-devel \
|
||||
xz-devel \
|
||||
zlib-devel \
|
||||
abseil-cpp-devel \
|
||||
protobuf-compiler \
|
||||
protobuf-devel \
|
||||
automake \
|
||||
bison \
|
||||
flex \
|
||||
gperf \
|
||||
libtool \
|
||||
m4 \
|
||||
nasm \
|
||||
python3 \
|
||||
python3-pip \
|
||||
nodejs \
|
||||
npm
|
||||
}
|
||||
|
||||
install_arch() {
|
||||
pacman -Sy --noconfirm \
|
||||
base-devel \
|
||||
gcc \
|
||||
clang \
|
||||
llvm \
|
||||
cmake \
|
||||
make \
|
||||
git \
|
||||
pkgconf \
|
||||
openssl \
|
||||
postgresql-libs \
|
||||
xz \
|
||||
zlib \
|
||||
abseil-cpp \
|
||||
protobuf \
|
||||
automake \
|
||||
bison \
|
||||
flex \
|
||||
gperf \
|
||||
libtool \
|
||||
m4 \
|
||||
nasm \
|
||||
python \
|
||||
python-pip \
|
||||
nodejs \
|
||||
npm
|
||||
}
|
||||
|
||||
install_alpine() {
|
||||
apk add --no-cache \
|
||||
build-base \
|
||||
gcc \
|
||||
g++ \
|
||||
clang \
|
||||
llvm-dev \
|
||||
clang-dev \
|
||||
cmake \
|
||||
make \
|
||||
git \
|
||||
pkgconf-dev \
|
||||
openssl-dev \
|
||||
postgresql-dev \
|
||||
xz-dev \
|
||||
zlib-dev \
|
||||
abseil-cpp-dev \
|
||||
protobuf-dev \
|
||||
protoc \
|
||||
automake \
|
||||
bison \
|
||||
flex \
|
||||
gperf \
|
||||
libtool \
|
||||
m4 \
|
||||
nasm \
|
||||
python3 \
|
||||
py3-pip \
|
||||
nodejs \
|
||||
npm
|
||||
}
|
||||
|
||||
case $OS in
|
||||
ubuntu|debian|linuxmint|pop)
|
||||
install_debian_ubuntu
|
||||
;;
|
||||
fedora|rhel|centos|rocky|almalinux)
|
||||
install_fedora_rhel
|
||||
;;
|
||||
arch|manjaro)
|
||||
install_arch
|
||||
;;
|
||||
alpine)
|
||||
install_alpine
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unsupported OS: $OS${NC}"
|
||||
echo "Required development packages:"
|
||||
echo " - build-essential/base-devel"
|
||||
echo " - gcc, g++, clang"
|
||||
echo " - cmake, make, git"
|
||||
echo " - Development headers for:"
|
||||
echo " - OpenSSL, PostgreSQL, XZ, zlib"
|
||||
echo " - Abseil, Protobuf, LLVM"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo -e "${GREEN}Development dependencies installed!${NC}"
|
||||
echo ""
|
||||
echo "Install Rust if not already installed:"
|
||||
echo " curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
|
||||
echo ""
|
||||
echo "Then build with:"
|
||||
echo " cargo build --release"
|
||||
77
DEPENDENCIES.ps1
Normal file
77
DEPENDENCIES.ps1
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Installs runtime dependencies for General Bots on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
This script downloads and configures the system libraries required to build
|
||||
and run BotServer on Windows. It downloads PostgreSQL binaries (for libpq)
|
||||
and sets the PQ_LIB_DIR environment variable permanently.
|
||||
|
||||
.EXAMPLE
|
||||
PS> .\DEPENDENCIES.ps1
|
||||
#>
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ─── COLORS ───
|
||||
function Write-Step { param($msg) Write-Host " * $msg" -ForegroundColor Green }
|
||||
function Write-Warn { param($msg) Write-Host " ! $msg" -ForegroundColor Yellow }
|
||||
function Write-Err { param($msg) Write-Host " x $msg" -ForegroundColor Red }
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host " General Bots Runtime Dependencies" -ForegroundColor Green
|
||||
Write-Host " (Windows)" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# ─── PostgreSQL binaries (libpq.lib for Diesel ORM) ───
|
||||
$PgsqlDir = "C:\pgsql\pgsql"
|
||||
$PgsqlLib = "$PgsqlDir\lib\libpq.lib"
|
||||
$PgsqlZipUrl = "https://get.enterprisedb.com/postgresql/postgresql-17.4-1-windows-x64-binaries.zip"
|
||||
$PgsqlZip = "$env:TEMP\pgsql.zip"
|
||||
|
||||
if (Test-Path $PgsqlLib) {
|
||||
Write-Step "PostgreSQL binaries already present at $PgsqlDir"
|
||||
} else {
|
||||
Write-Host "`nDownloading PostgreSQL binaries..." -ForegroundColor Cyan
|
||||
Write-Host " URL: $PgsqlZipUrl"
|
||||
Write-Host " This may take a few minutes (~300MB)...`n"
|
||||
|
||||
Invoke-WebRequest -Uri $PgsqlZipUrl -OutFile $PgsqlZip -UseBasicParsing
|
||||
|
||||
Write-Host "Extracting to C:\pgsql ..."
|
||||
if (Test-Path "C:\pgsql") { Remove-Item "C:\pgsql" -Recurse -Force }
|
||||
Expand-Archive -Path $PgsqlZip -DestinationPath "C:\pgsql" -Force
|
||||
Remove-Item $PgsqlZip -Force -ErrorAction SilentlyContinue
|
||||
|
||||
if (Test-Path $PgsqlLib) {
|
||||
Write-Step "PostgreSQL binaries installed successfully."
|
||||
} else {
|
||||
Write-Err "Failed to find libpq.lib after extraction!"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Set PQ_LIB_DIR permanently for the current user
|
||||
$CurrentPqDir = [System.Environment]::GetEnvironmentVariable("PQ_LIB_DIR", "User")
|
||||
if ($CurrentPqDir -ne "$PgsqlDir\lib") {
|
||||
[System.Environment]::SetEnvironmentVariable("PQ_LIB_DIR", "$PgsqlDir\lib", "User")
|
||||
$env:PQ_LIB_DIR = "$PgsqlDir\lib"
|
||||
Write-Step "PQ_LIB_DIR set to '$PgsqlDir\lib' (User environment variable)"
|
||||
} else {
|
||||
Write-Step "PQ_LIB_DIR already configured."
|
||||
}
|
||||
|
||||
# ─── Summary ───
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host " Dependencies installed!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "You can now build and run:" -ForegroundColor Cyan
|
||||
Write-Host " cargo build -p botserver"
|
||||
Write-Host " cargo build -p botui"
|
||||
Write-Host " .\restart.ps1"
|
||||
Write-Host ""
|
||||
Write-Host "NOTE: If this is the first time, restart your terminal" -ForegroundColor Yellow
|
||||
Write-Host " so PQ_LIB_DIR takes effect." -ForegroundColor Yellow
|
||||
967
PROD.md
Normal file
967
PROD.md
Normal file
|
|
@ -0,0 +1,967 @@
|
|||
# Production Environment Guide
|
||||
|
||||
## CRITICAL RULES — READ FIRST
|
||||
|
||||
NEVER INCLUDE HERE CREDENTIALS OR COMPANY INFORMATION, THIS IS COMPANY AGNOSTIC.
|
||||
|
||||
Always manage services with `systemctl` inside the `system` Incus container. Never run `/opt/gbo/bin/botserver` or `/opt/gbo/bin/botui` directly — they will fail because they won't load the `.env` file containing Vault credentials and paths. The correct commands are `sudo incus exec system -- systemctl start|stop|restart|status botserver` and the same for `ui`. Systemctl handles environment loading, auto-restart, logging, and dependencies.
|
||||
|
||||
Never push secrets (API keys, passwords, tokens) to git. Never commit `init.json` (it contains Vault unseal keys). All secrets must come from Vault — only `VAULT_*` variables are allowed in `.env`. Never deploy manually via scp or ssh; always use CI/CD. Always push all submodules (botserver, botui, botlib) before or alongside the main repo. Always ask before pushing to ALM.
|
||||
|
||||
---
|
||||
|
||||
## Infrastructure Overview
|
||||
|
||||
The host machine is accessed via `ssh user@<hostname>`, running Incus (an LXD fork) as hypervisor. All services run inside named Incus containers. You enter containers with `sudo incus exec <container> -- <command>` and list them with `sudo incus list`.
|
||||
|
||||
### Container Architecture
|
||||
|
||||
| Container | Service | Technology | Binary Path | Logs Path | Data Path | Notes |
|
||||
|-----------|---------|------------|-------------|-----------|-----------|-------|
|
||||
| **system** | BotServer + BotUI | Rust/Axum | `/opt/gbo/bin/botserver`<br>`/opt/gbo/bin/botui` | `/opt/gbo/logs/out.log`<br>`/opt/gbo/logs/err.log` | `/opt/gbo/work/` | Main API + UI proxy |
|
||||
| **tables** | PostgreSQL | PostgreSQL 15+ | `/usr/lib/postgresql/*/bin/postgres` | `/opt/gbo/logs/postgresql/` | `/opt/gbo/data/pgdata/` | Primary database |
|
||||
| **vault** | HashiCorp Vault | Vault | `/opt/gbo/bin/vault` | `/opt/gbo/logs/vault/` | `/opt/gbo/data/vault/` | Secrets management |
|
||||
| **cache** | Valkey | Valkey (Redis fork) | `/opt/gbo/bin/valkey-server` | `/opt/gbo/logs/valkey/` | `/opt/gbo/data/valkey/` | Distributed cache |
|
||||
| **drive** | MinIO | MinIO | `/opt/gbo/bin/minio` | `/opt/gbo/logs/minio/` | `/opt/gbo/data/minio/` | Object storage (S3 API) |
|
||||
| **directory** | Zitadel | Zitadel (Go) | `/opt/gbo/bin/zitadel` | `/opt/gbo/logs/zitadel.log` | `PROD-DIRECTORY` DB | Identity provider |
|
||||
| **llm** | llama.cpp | C++/CUDA | `/opt/gbo/bin/llama-server` | `/opt/gbo/logs/llm/` | `/opt/gbo/models/` | Local LLM inference |
|
||||
| **vectordb** | Qdrant | Qdrant (Rust) | `/opt/gbo/bin/qdrant` | `/opt/gbo/logs/qdrant/` | `/opt/gbo/data/qdrant/` | Vector database |
|
||||
| **alm** | Forgejo | Forgejo (Go) | `/opt/gbo/bin/forgejo` | `/opt/gbo/logs/forgejo/` | `/opt/gbo/data/forgejo/` | Git server (port 4747) |
|
||||
| **alm-ci** | Forgejo Runner | Docker/runner | `/opt/gbo/bin/forgejo-runner` | `/opt/gbo/logs/forgejo-runner.log` | `/opt/gbo/data/ci/` | CI/CD runner |
|
||||
| **proxy** | Caddy | Caddy | `/opt/gbo/bin/caddy` | `/opt/gbo/logs/caddy/` | `/opt/gbo/conf/` | Reverse proxy |
|
||||
| **email** | Stalwart | Stalwart (Rust) | `/opt/gbo/bin/stalwart` | `/opt/gbo/logs/email/` | `/opt/gbo/data/email/` | Mail server |
|
||||
| **webmail** | Roundcube | PHP | `/usr/share/roundcube/` | `/var/log/php/` | `/var/lib/roundcube/` | Webmail frontend |
|
||||
| **dns** | CoreDNS | CoreDNS (Go) | `/opt/gbo/bin/coredns` | `/opt/gbo/logs/dns/` | `/opt/gbo/conf/Corefile` | DNS resolution |
|
||||
| **meet** | LiveKit | LiveKit (Go) | `/opt/gbo/bin/livekit-server` | `/opt/gbo/logs/meet/` | `/opt/gbo/data/meet/` | Video conferencing |
|
||||
| **table-editor** | NocoDB | NocoDB | `/opt/gbo/bin/nocodb` | `/opt/gbo/logs/nocodb/` | `/opt/gbo/data/nocodb/` | Database UI |
|
||||
|
||||
### Network Access
|
||||
|
||||
Externally, services are exposed via reverse proxy (Caddy). Internally, containers communicate via private IPs:
|
||||
|
||||
| Service | External URL | Internal Address |
|
||||
|---------|--------------|------------------|
|
||||
| BotServer | `https://<system-domain>` | `http://<system-ip>:8080` |
|
||||
| BotUI | `https://<chat-domain>` | `http://<system-ip>:3000` |
|
||||
| Zitadel | `https://<login-domain>` | `http://<directory-ip>:8080` |
|
||||
| Forgejo | `https://<alm-domain>` | `http://<alm-ip>:4747` |
|
||||
| Webmail | `https://<webmail-domain>` | `http://<webmail-ip>:80` |
|
||||
| Roundcube | `https://<roundcube-domain>` | `http://<webmail-ip>:80` |
|
||||
|
||||
**Note:** BotUI's `BOTSERVER_URL` must be `http://<system-ip>:8080` internally, NOT the external HTTPS URL.
|
||||
|
||||
---
|
||||
|
||||
## Daily Operations
|
||||
|
||||
### Daily Health Check (5 minutes)
|
||||
|
||||
Run this every morning or after any deploy:
|
||||
|
||||
```bash
|
||||
# 1. Container status
|
||||
sudo incus list
|
||||
|
||||
# 2. Service health - all should show "active (running)"
|
||||
sudo incus exec system -- systemctl is-active botserver
|
||||
sudo incus exec system -- systemctl is-active ui
|
||||
sudo incus exec directory -- systemctl is-active directory 2>/dev/null || echo "Directory check failed"
|
||||
sudo incus exec drive -- pgrep -f minio > /dev/null && echo "MinIO OK" || echo "MinIO DOWN"
|
||||
sudo incus exec tables -- pgrep -f postgres > /dev/null && echo "PostgreSQL OK" || echo "PostgreSQL DOWN"
|
||||
|
||||
# 3. IPv4 connectivity check - all containers should have IPv4
|
||||
sudo incus list -c n4 | grep -E "(system|tables|vault|directory|drive|cache|llm|vector_db)" | grep -v "10\." && echo "WARNING: Missing IPv4" || echo "IPv4 OK"
|
||||
|
||||
# 4. Application health endpoint
|
||||
curl -sf https://<system-domain>/api/health && echo "Health OK" || echo "Health FAILED"
|
||||
|
||||
# 5. Recent errors (last 10 lines)
|
||||
sudo incus exec system -- tail -10 /opt/gbo/logs/err.log | grep -i "error\|panic\|failed" | head -5
|
||||
```
|
||||
|
||||
**Expected Result:** All services "active", all containers have IPv4, health endpoint returns 200, no critical errors.
|
||||
|
||||
### Weekly Deep Check (15 minutes)
|
||||
|
||||
Run every Monday morning:
|
||||
|
||||
```bash
|
||||
# 1. Disk space on all containers
|
||||
for c in system tables vault directory drive cache llm vector_db; do
|
||||
echo "=== $c ==="
|
||||
sudo incus exec $c -- df -h / 2>/dev/null | tail -1
|
||||
done
|
||||
|
||||
# 2. Database connection pool status
|
||||
sudo incus exec tables -- psql -h localhost -U postgres -d botserver -c "SELECT count(*), state FROM pg_stat_activity GROUP BY state;"
|
||||
|
||||
# 3. Vault status (should be unsealed)
|
||||
sudo incus exec vault -- curl -ksf https://localhost:8200/v1/sys/health | grep -q '"sealed":false' && echo "Vault unsealed" || echo "Vault SEALED - CRITICAL"
|
||||
|
||||
# 4. CI runner status
|
||||
sudo incus exec alm-ci -- pgrep -f forgejo > /dev/null && echo "CI runner OK" || echo "CI runner DOWN"
|
||||
|
||||
# 5. MinIO buckets health
|
||||
sudo incus exec drive -- bash -c 'export PATH=/opt/gbo/bin:$PATH && mc admin info local' 2>&1 | head -10
|
||||
|
||||
# 6. Backup verification - check latest snapshot exists
|
||||
sudo incus snapshot list system | head -5
|
||||
```
|
||||
|
||||
### Quick Status Dashboard
|
||||
|
||||
One-line status of everything:
|
||||
|
||||
```bash
|
||||
echo "=== GBO Status Dashboard $(date) ==="
|
||||
echo "Containers:"
|
||||
sudo incus list -c n4,s | grep -E "(system|tables|vault|directory|drive|cache|llm|vector_db|alm-ci)" | awk '{print $1 ": " $3 " " $4}'
|
||||
echo ""
|
||||
echo "Services:"
|
||||
for svc in botserver ui; do
|
||||
sudo incus exec system -- systemctl is-active $svc 2>/dev/null && echo " $svc: ACTIVE" || echo " $svc: DOWN"
|
||||
done
|
||||
echo ""
|
||||
echo "Health:"
|
||||
curl -s -o /dev/null -w "%{http_code}" https://<system-domain>/api/health 2>/dev/null | grep -q "200" && echo " API: OK" || echo " API: FAIL"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alert Response Playbook
|
||||
|
||||
### Alert: "No IPv4 on container"
|
||||
|
||||
**Symptoms:** Container shows empty IPV4 column in `incus list`
|
||||
|
||||
**Quick Fix:**
|
||||
```bash
|
||||
# Identify container
|
||||
CONTAINER=<name>
|
||||
IP=<unused-ip-in-range> # e.g., 10.x.x.x
|
||||
GATEWAY=<gateway-ip>
|
||||
|
||||
# Set static IP
|
||||
sudo incus config device set $CONTAINER eth0 ipv4.address $IP
|
||||
|
||||
# Configure network inside
|
||||
sudo incus exec $CONTAINER -- bash -c "cat > /etc/network/interfaces << 'EOF'
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet static
|
||||
address $IP
|
||||
netmask 255.255.255.0
|
||||
gateway $GATEWAY
|
||||
dns-nameservers 8.8.8.8 8.8.4.4
|
||||
EOF"
|
||||
|
||||
# Restart
|
||||
sudo incus restart $CONTAINER
|
||||
|
||||
# Verify
|
||||
sudo incus exec $CONTAINER -- ip addr show eth0
|
||||
```
|
||||
|
||||
**Prevention:** Always configure static IP when creating new containers.
|
||||
|
||||
---
|
||||
|
||||
### Alert: "ALM botserver problem" / CI Build Failed
|
||||
|
||||
**Symptoms:** Deploy not working, CI status shows failure
|
||||
|
||||
**Quick Diagnostics:**
|
||||
```bash
|
||||
# Check CI database for recent runs
|
||||
sudo incus exec tables -- bash -c 'export PGPASSWORD=<password>; psql -h localhost -U postgres -d PROD-ALM -c "SELECT id, status, created FROM action_run ORDER BY id DESC LIMIT 5;"'
|
||||
# Status codes: 0=pending, 1=success, 2=failure, 3=cancelled, 6=running
|
||||
```
|
||||
|
||||
**Quick Fixes:**
|
||||
|
||||
1. **If stuck at status 6 (running):**
|
||||
```bash
|
||||
RUN_ID=<stuck-run-id>
|
||||
sudo incus exec tables -- bash -c "export PGPASSWORD=<password>; psql -h localhost -U postgres -d PROD-ALM -c \"UPDATE action_task SET status = 0 WHERE id = $RUN_ID; UPDATE action_run_job SET status = 0 WHERE run_id = $RUN_ID; UPDATE action_run SET status = 0 WHERE id = $RUN_ID;\""
|
||||
```
|
||||
|
||||
2. **If /tmp permission denied:**
|
||||
```bash
|
||||
sudo incus exec alm-ci -- chmod 1777 /tmp
|
||||
sudo incus exec alm-ci -- touch /tmp/build.log && chmod 666 /tmp/build.log
|
||||
```
|
||||
|
||||
3. **If CI runner down:**
|
||||
```bash
|
||||
sudo incus exec alm-ci -- pkill -9 forgejo
|
||||
sleep 2
|
||||
sudo incus exec alm-ci -- bash -c 'cd /opt/gbo/bin && nohup ./forgejo-runner daemon --config config.yaml >> /opt/gbo/logs/forgejo-runner.log 2>&1 &'
|
||||
```
|
||||
|
||||
**After fix:** Push a trivial change to re-trigger CI.
|
||||
|
||||
---
|
||||
|
||||
### Alert: "Email container stopping reach Internet"
|
||||
|
||||
**Symptoms:** Email notifications failing, container cannot resolve external domains
|
||||
|
||||
**Quick Diagnostics:**
|
||||
```bash
|
||||
# Test DNS from email container
|
||||
sudo incus exec email -- nslookup google.com
|
||||
|
||||
# Check network config
|
||||
sudo incus exec email -- cat /etc/resolv.conf
|
||||
sudo incus exec email -- ip route
|
||||
```
|
||||
|
||||
**Quick Fixes:**
|
||||
|
||||
1. **If IPv6-only (no IPv4):** Follow "No IPv4 on container" playbook above.
|
||||
|
||||
2. **If DNS not working:**
|
||||
```bash
|
||||
# Force Google DNS
|
||||
sudo incus exec email -- bash -c 'echo "nameserver 8.8.8.8" > /etc/resolv.conf'
|
||||
|
||||
# Or configure via interfaces file
|
||||
sudo incus exec email -- bash -c "cat > /etc/network/interfaces << 'EOF'
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet static
|
||||
address <email-container-ip>
|
||||
netmask 255.255.255.0
|
||||
gateway <gateway>
|
||||
dns-nameservers 8.8.8.8 8.8.4.4
|
||||
EOF"
|
||||
sudo incus restart email
|
||||
```
|
||||
|
||||
3. **If firewall blocking:** Check iptables rules on host for email container IP.
|
||||
|
||||
---
|
||||
|
||||
### Alert: "Vault sealed"
|
||||
|
||||
**Symptoms:** All services failing, Vault health shows "sealed": true
|
||||
|
||||
**Quick Fix:**
|
||||
```bash
|
||||
# Get unseal keys from secure location (not in git!)
|
||||
KEY1=<key-from-secure-location>
|
||||
KEY2=<key-from-secure-location>
|
||||
KEY3=<key-from-secure-location>
|
||||
|
||||
sudo incus exec vault -- vault operator unseal $KEY1
|
||||
sudo incus exec vault -- vault operator unseal $KEY2
|
||||
sudo incus exec vault -- vault operator unseal $KEY3
|
||||
|
||||
# Verify
|
||||
sudo incus exec vault -- vault status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Alert: "Botserver not responding"
|
||||
|
||||
**Quick Diagnostics:**
|
||||
```bash
|
||||
# Check process
|
||||
sudo incus exec system -- pgrep -f botserver || echo "NOT RUNNING"
|
||||
|
||||
# Check systemd status
|
||||
sudo incus exec system -- systemctl status botserver --no-pager
|
||||
|
||||
# Check recent logs
|
||||
sudo incus exec system -- tail -20 /opt/gbo/logs/err.log
|
||||
|
||||
# Check for GLIBC errors
|
||||
sudo incus exec system -- ldd /opt/gbo/bin/botserver | grep "not found"
|
||||
```
|
||||
|
||||
**Quick Fixes:**
|
||||
|
||||
1. **If systemd failed:**
|
||||
```bash
|
||||
sudo incus exec system -- systemctl restart botserver
|
||||
sudo incus exec system -- systemctl restart ui
|
||||
```
|
||||
|
||||
2. **If GLIBC mismatch:** Binary compiled with wrong glibc. Must rebuild inside system container (Debian 12, glibc 2.36).
|
||||
|
||||
3. **If port conflict:**
|
||||
```bash
|
||||
sudo incus exec system -- lsof -i :8080
|
||||
sudo incus exec system -- killall botserver
|
||||
sudo incus exec system -- systemctl start botserver
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Services Detail
|
||||
|
||||
Botserver runs as user `gbuser`, binary at `/opt/gbo/bin/botserver`, logs at `/opt/gbo/logs/out.log` and `/opt/gbo/logs/err.log`, systemd unit at `/etc/systemd/system/botserver.service`, env loaded from `/opt/gbo/bin/.env`. Bot BASIC scripts are stored in MinIO Drive under `{bot}.gbai/{bot}.gbdialog/*.bas` and are downloaded/compiled by DriveMonitor to `/opt/gbo/work/{bot}.gbai/{bot}.gbdialog/*.ast`.
|
||||
|
||||
The directory service runs Zitadel as user `root`, binary at `/opt/gbo/bin/zitadel`, logs at `/opt/gbo/logs/zitadel.log`, systemd unit at `/etc/systemd/system/directory.service`, and loads environment from the service configuration. Zitadel provides identity management and OAuth2 services for the platform.
|
||||
|
||||
Internally, Zitadel listens on port 8080 within the directory container. For external access:
|
||||
- Via public domain (HTTPS): `https://<login-domain>` (configured through proxy container)
|
||||
- Via host IP (HTTP): `http://<host-ip>:9000` (direct container port forwarding)
|
||||
- Via container IP (HTTP): `http://<directory-container-ip>:9000` (direct container access)
|
||||
|
||||
Access the Zitadel console at `https://<login-domain>/ui/console` with admin credentials. Zitadel implements v1 Management API (deprecated) and v2 Organization/User services. Always use the v2 endpoints under `/v2/organizations` and `/v2/users` for all operations.
|
||||
|
||||
The botserver bootstrap also manages: Vault (secrets), PostgreSQL (database), Valkey (cache, password auth), MinIO (object storage), Zitadel (identity provider), and llama.cpp (LLM).
|
||||
|
||||
To obtain a PAT for Zitadel API access, check /opt/gbo/conf/directory/admin-pat.txt in the directory container. Use it with curl by setting the Authorization header: `Authorization: Bearer $(cat /opt/gbo/conf/directory/admin-pat.txt)` and include `-H "Host: <directory-ip> "` for correct host resolution.
|
||||
|
||||
---
|
||||
|
||||
## Directory Management (Zitadel)
|
||||
|
||||
### Getting Admin PAT (Personal Access Token)
|
||||
|
||||
```bash
|
||||
# Get the admin PAT from directory container
|
||||
PAT=$(ssh administrator@<hostname> "sudo incus exec directory -- cat /opt/gbo/conf/directory/admin-pat.txt")
|
||||
```
|
||||
|
||||
### User Management via API (v2)
|
||||
|
||||
**Create a Human User:**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/users/human" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{
|
||||
"username": "testuser",
|
||||
"profile": {"givenName": "Test", "familyName": "User"},
|
||||
"email": {"email": "test@example.com", "isVerified": true},
|
||||
"password": {"password": "<password>", "changeRequired": false}
|
||||
}'
|
||||
```
|
||||
|
||||
**List Users:**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/users" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{"query": {"offset": 0, "limit": 100}}'
|
||||
```
|
||||
|
||||
**Update User Password:**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/users/<user-id>/password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{
|
||||
"newPassword": {"password": "<password>", "changeRequired": false}
|
||||
}'
|
||||
```
|
||||
|
||||
**Delete User:**
|
||||
```bash
|
||||
curl -X DELETE "http://<directory-ip>:8080/v2/users/<user-id>" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>"
|
||||
```
|
||||
|
||||
### Directory Quick Reference
|
||||
|
||||
| Task | Command |
|
||||
|------|---------|
|
||||
| Get PAT | `sudo incus exec directory -- cat /opt/gbo/conf/directory/admin-pat.txt` |
|
||||
| Check health | `curl -sf http://<directory-ip>:8080/debug/healthz` |
|
||||
| Console UI | `http://<host-ip>:9000/ui/console` |
|
||||
| Create user | `POST /v2/users/human` |
|
||||
| List users | `POST /v2/users` |
|
||||
| Update password | `POST /v2/users/{id}/password` |
|
||||
|
||||
# /tmp permission denied for build.log
|
||||
sudo incus exec alm-ci -- chmod 1777 /tmp
|
||||
sudo incus exec alm-ci -- touch /tmp/build.log && chmod 666 /tmp/build.log
|
||||
|
||||
# Clean old CI runs (keep recent)
|
||||
sudo incus exec tables -- bash -c 'export PGPASSWORD=<postgres-password>; psql -h localhost -U postgres -d PROD-ALM -c "DELETE FROM action_run WHERE id < <RECENT_ID>;"'
|
||||
sudo incus exec tables -- bash -c 'export PGPASSWORD=<postgres-password>; psql -h localhost -U postgres -d PROD-ALM -c "DELETE FROM action_run_job WHERE run_id < <RECENT_ID>;"'
|
||||
```
|
||||
|
||||
**Watch CI in real-time:**
|
||||
```bash
|
||||
# Tail runner logs
|
||||
sudo incus exec alm-ci -- tail -f /opt/gbo/logs/forgejo-runner.log
|
||||
|
||||
# Check if new builds appear
|
||||
watch -n 5 'sudo incus exec tables -- bash -c "export PGPASSWORD=<postgres-password>; psql -h localhost -U postgres -d PROD-ALM -c \\"SELECT id, status, created FROM action_run ORDER BY id DESC LIMIT 3;\\""'
|
||||
|
||||
# Verify botserver deployed correctly
|
||||
sudo incus exec system -- /opt/gbo/bin/botserver --version 2>&1 | head -3
|
||||
sudo incus exec system -- tail -5 /opt/gbo/logs/err.log
|
||||
```
|
||||
|
||||
### Monitor CI/CD Build Status
|
||||
|
||||
**Check latest build status:**
|
||||
```bash
|
||||
# View latest 3 builds with status
|
||||
sudo incus exec alm -- bash -c 'cd /opt/gbo/data/GeneralBots/BotServer/actions/runs && for dir in $(ls -t | head -3); do echo "=== Build $dir ==="; cat $dir/jobs/0.json 2>/dev/null | grep -E "\"status\"|\"commit\"|\"workflow\"" | head -5; done'
|
||||
|
||||
# Watch runner logs in real-time
|
||||
sudo incus exec alm-ci -- tail -f /opt/gbo/logs/forgejo-runner.log | grep -E "Clone|Build|Deploy|Success|Failure"
|
||||
```
|
||||
|
||||
**Understand build timing:**
|
||||
- **Rust compilation**: 2-5 minutes (cold build), 30-60 seconds (incremental)
|
||||
- **Dependencies**: First build downloads ~200 dependencies
|
||||
- **Deploy step**: ~5 seconds
|
||||
- **Total CI time**: 2-6 minutes depending on cache
|
||||
|
||||
**Verify binary was updated:**
|
||||
```bash
|
||||
# Check binary timestamp
|
||||
ssh administrator@63.141.255.9 "sudo incus exec system -- stat -c '%y' /opt/gbo/bin/botserver"
|
||||
|
||||
# Check running version
|
||||
ssh administrator@63.141.255.9 "sudo incus exec system -- /opt/gbo/bin/botserver --version"
|
||||
|
||||
# Check health endpoint
|
||||
curl -sf https://chat.pragmatismo.com.br/api/health || echo "Health check failed"
|
||||
```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DriveMonitor & Bot Configuration
|
||||
|
||||
DriveMonitor is a background service inside botserver that watches MinIO buckets and syncs changes to the local filesystem and database every 10 seconds. It monitors three directory types per bot: the `.gbdialog/` folder for BASIC scripts (downloads and recompiles on change), the `.gbot/` folder for `config.csv` (syncs to the `bot_configuration` database table), and the `.gbkb/` folder for knowledge base documents (downloads and indexes for vector search).
|
||||
|
||||
Bot configuration is stored in two PostgreSQL tables inside the `botserver` database. The `bot_configuration` table holds key-value pairs with columns `bot_id`, `config_key`, `config_value`, `config_type`, `is_encrypted`, and `updated_at`. The `gbot_config_sync` table tracks sync state with columns `bot_id`, `config_file_path`, `last_sync_at`, `file_hash`, and `sync_count`.
|
||||
|
||||
The `config.csv` format is a plain CSV with no header: each line is `key,value`, for example `llm-provider,groq` or `theme-color1,#cc0000`. DriveMonitor syncs it when the file ETag changes in MinIO, on botserver startup, or after a restart.
|
||||
|
||||
**Check config status:** Query `bot_configuration` via `sudo incus exec tables -- psql -h localhost -U postgres -d botserver -c "SELECT config_key, config_value FROM bot_configuration WHERE bot_id = (SELECT id FROM bots WHERE name = '<botname>') ORDER BY config_key;"`. Check sync state via the `gbot_config_sync` table. Inspect the bucket directly with `sudo incus exec drive -- /opt/gbo/bin/mc cat local/<botname>.gbai/<botname>.gbot/config.csv`.
|
||||
|
||||
**Debug DriveMonitor:** Monitor live logs with `sudo incus exec system -- tail -f /opt/gbo/logs/out.log | grep -E "(DRIVE_MONITOR|check_gbot|config)"`. An empty `gbot_config_sync` table means DriveMonitor has not synced yet. If no new log entries appear after 30 seconds, the loop may be stuck — restart botserver with systemctl to clear the state.
|
||||
|
||||
**Common config issues:** If config.csv is missing from the bucket, create and upload it with `mc cp`. If the database shows stale values, restart botserver to force a fresh sync, or as a temporary fix update the database directly with `UPDATE bot_configuration SET config_value = 'groq', updated_at = NOW() WHERE ...`. To force a re-sync without restarting, copy config.csv over itself with `mc cp local/... local/...` to change the ETag.
|
||||
|
||||
---
|
||||
|
||||
## MinIO (Drive) Operations
|
||||
|
||||
All bot files live in MinIO buckets. Use the `mc` CLI at `/opt/gbo/bin/mc` from inside the `drive` container. The bucket structure per bot is: `{bot}.gbai/` as root, `{bot}.gbai/{bot}.gbdialog/` for BASIC scripts, `{bot}.gbai/{bot}.gbot/` for config.csv, and `{bot}.gbai/{bot}.gbkb/` for knowledge base folders.
|
||||
|
||||
Common mc commands: `mc ls local/` lists all buckets; `mc ls local/botname.gbai/` lists a bucket; `mc cat local/.../start.bas` prints a file; `mc cp local/.../file /tmp/file` downloads; `mc cp /tmp/file local/.../file` uploads (this triggers DriveMonitor recompile); `mc stat local/.../config.csv` shows ETag and metadata; `mc mb local/newbot.gbai` creates a bucket; `mc rb local/oldbot.gbai` removes an empty bucket.
|
||||
|
||||
If mc is not found, use the full path `/opt/gbo/bin/mc`. If alias `local` is not configured, check with `mc config host list`. If MinIO is not running, check with `sudo incus exec drive -- systemctl status minio`.
|
||||
|
||||
---
|
||||
|
||||
## Vault Security Architecture
|
||||
|
||||
HashiCorp Vault is the single source of truth for all secrets. Botserver reads `VAULT_ADDR` and `VAULT_TOKEN` from `/opt/gbo/bin/.env` at startup, initializes a TLS/mTLS client, then reads credentials from Vault paths. If Vault is unavailable, it falls back to defaults. The `.env` file must only contain `VAULT_*` variables plus `PORT`, `DATA_DIR`, `WORK_DIR`, and `LOAD_ONLY`.
|
||||
|
||||
**Global Vault paths:** `gbo/tables` holds PostgreSQL credentials; `gbo/drive` holds MinIO access key and secret; `gbo/cache` holds Valkey password; `gbo/llm` holds LLM URL and API keys; `gbo/directory` holds Zitadel config; `gbo/email` holds SMTP credentials; `gbo/vectordb` holds Qdrant config; `gbo/jwt` holds JWT signing secret; `gbo/encryption` holds the master encryption key. Organization-scoped secrets follow patterns like `gbo/orgs/{org_id}/bots/{bot_id}` and tenant infrastructure uses `gbo/tenants/{tenant_id}/infrastructure`.
|
||||
|
||||
**Credential resolution:** For any service, botserver checks the most specific Vault path first (org+bot level), falls back to a default bot path, then falls back to the global path, and only uses environment variables as a last resort in development.
|
||||
|
||||
**Verify Vault health:** `sudo incus exec vault -- curl -k -sf https://localhost:8200/v1/sys/health` should return JSON with `"sealed":false`. To read a secret: set `VAULT_ADDR`, `VAULT_TOKEN`, and `VAULT_CACERT` then run `vault kv get secret/gbo/tables`. To test from the system container, use curl with `--cacert /opt/gbo/conf/system/certificates/ca/ca.crt` and `-H "X-Vault-Token: <token>"`.
|
||||
|
||||
**init.json** is stored at `/opt/gbo/bin/botserver-stack/conf/vault/vault-conf/init.json` and contains the root token and 5 unseal keys (3 needed to unseal). Never commit this file to git. Store it encrypted in a secure location.
|
||||
|
||||
**Vault troubleshooting — cannot connect:** Check that the vault container's systemd unit is running, verify the token in `.env` is not expired with `vault token lookup`, confirm the CA cert path in `.env` matches the actual file location, and test network connectivity from system to vault container. To generate a new token: `vault token create -policy="botserver" -ttl="8760h" -format=json` then update `.env` and restart botserver.
|
||||
|
||||
**Get database credentials from Vault v2 API:**
|
||||
```bash
|
||||
ssh user@<hostname> "sudo incus exec system -- curl -s --cacert /opt/gbo/conf/system/certificates/ca/ca.crt -H 'X-Vault-Token: <vault-token>' https://<vault-ip>:8200/v1/secret/data/gbo/tables 2>/dev/null"
|
||||
```
|
||||
|
||||
**Vault troubleshooting — secrets missing:** Run `vault kv get secret/gbo/tables` (and other paths) to check if secrets exist. If a path returns NOT FOUND, add secrets with `vault kv put secret/gbo/tables host=<ip> port=5432 database=botserver username=gbuser password=<pw>` and similar for other paths.
|
||||
|
||||
**Vault sealed after restart:** Run `vault operator unseal <key1>`, repeat with key2 and key3 (3 of 5 keys from init.json), then verify with `vault status`.
|
||||
|
||||
**TLS certificate errors:** Confirm `/opt/gbo/conf/system/certificates/ca/ca.crt` exists in the system container. If missing, copy it from the vault container using `incus file pull vault/opt/gbo/conf/vault/ca.crt /tmp/ca.crt` then place it at the expected path.
|
||||
|
||||
**Vault snapshots:** Stop vault, run `sudo incus snapshot create vault backup-$(date +%Y%m%d-%H%M)`, start vault. Restore with `sudo incus snapshot restore vault <name>` while vault is stopped.
|
||||
|
||||
---
|
||||
|
||||
## DNS Management
|
||||
|
||||
### Updating DNS Records
|
||||
|
||||
**CRITICAL:** When updating DNS zone files, you MUST:
|
||||
|
||||
1. **Update the serial number** in the SOA record (format: YYYYMMDDNN)
|
||||
2. **Run sync-zones.sh** to propagate changes to secondary nameservers
|
||||
3. **Anonymize IPs and credentials** in all documentation and logs
|
||||
|
||||
**Workflow:**
|
||||
```bash
|
||||
# 1. Edit zone file
|
||||
sudo incus exec dns -- nano /opt/gbo/data/pragmatismo.com.br.zone
|
||||
|
||||
# 2. Update serial (YYYYMMDDNN format)
|
||||
# Example: 2026041801 (April 18, 2026, change #1)
|
||||
sudo incus exec dns -- sed -i 's/2026041801/2026041802/' /opt/gbo/data/pragmatismo.com.br.zone
|
||||
|
||||
# 3. Reload CoreDNS
|
||||
sudo incus exec dns -- pkill -HUP coredns
|
||||
|
||||
# 4. Sync to secondary NS
|
||||
sudo /opt/gbo/bin/sync-zones.sh
|
||||
|
||||
# 5. Verify on secondary
|
||||
ssh -o StrictHostKeyChecking=no -i /home/administrator/.ssh/id_ed25519 admin@<secondary-ip> 'getent hosts <domain>'
|
||||
```
|
||||
|
||||
**Zone File Location:** `/opt/gbo/data/<domain>.zone` in the `dns` container
|
||||
|
||||
**Sync Script:** `/opt/gbo/bin/sync-zones.sh` - copies zone files to secondary NS (3.218.224.38)
|
||||
|
||||
**⚠️ Security Rules:**
|
||||
- NEVER include real IPs in documentation - use `<ip>` or `10.x.x.x`
|
||||
- NEVER include credentials - use `<password>` or `<token>`
|
||||
- NEVER commit zone files with secrets to git
|
||||
|
||||
---
|
||||
|
||||
### Adding New Subdomains (HTTPS with Caddy)
|
||||
|
||||
**CRITICAL:** When adding new subdomains that need HTTPS, follow this order:
|
||||
|
||||
1. **Add DNS record FIRST** (see above workflow)
|
||||
2. **Wait for DNS propagation** (can take up to 1 hour)
|
||||
3. **Add Caddy config** - Caddy will automatically obtain Let's Encrypt certificate
|
||||
|
||||
**Complete Workflow:**
|
||||
```bash
|
||||
# 1. Add DNS record (update serial, sync zones)
|
||||
sudo incus exec dns -- nano /opt/gbo/data/pragmatismo.com.br.zone
|
||||
# Add: news IN A <ip>
|
||||
sudo incus exec dns -- sed -i 's/2026041801/2026041802/' /opt/gbo/data/pragmatismo.com.br.zone
|
||||
sudo incus exec dns -- pkill -HUP coredns
|
||||
sudo /opt/gbo/bin/sync-zones.sh
|
||||
|
||||
# 2. Verify DNS propagation (wait until this works)
|
||||
dig @9.9.9.9 news.pragmatismo.com.br A +short
|
||||
|
||||
# 3. Add Caddy config (AFTER DNS is working)
|
||||
sudo sh -c 'cat >> /opt/gbo/conf/config << EOF
|
||||
|
||||
news.pragmatismo.com.br {
|
||||
import tls_config
|
||||
reverse_proxy http://<container-ip>:<port> {
|
||||
header_up Host {host}
|
||||
header_up X-Real-IP {remote}
|
||||
header_up X-Forwarded-Proto https
|
||||
}
|
||||
}
|
||||
EOF'
|
||||
|
||||
# 4. Restart Caddy
|
||||
sudo incus exec proxy -- systemctl restart proxy
|
||||
|
||||
# 5. Wait for certificate (Caddy will auto-obtain from Let's Encrypt)
|
||||
# Check logs: sudo incus exec proxy -- tail -f /opt/gbo/logs/access.log
|
||||
```
|
||||
|
||||
**⚠️ Important:**
|
||||
- Caddy will fail to obtain certificate if DNS is not propagated
|
||||
- Wait up to 1 hour for DNS propagation before adding Caddy config
|
||||
- Check Caddy logs for "challenge failed" errors - indicates DNS not ready
|
||||
- Certificate is automatically renewed by Caddy
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Quick Reference
|
||||
|
||||
**botserver won't start:** Run `sudo incus exec system -- ldd /opt/gbo/bin/botserver | grep "not found"` to check for missing libraries. Run `sudo incus exec system -- timeout 10 /opt/gbo/bin/botserver 2>&1` to see startup errors. Confirm `/opt/gbo/work/` exists and is accessible.
|
||||
|
||||
**botui can't reach botserver:** Check that the `ui.service` systemd file has `BOTSERVER_URL=http://localhost:5858` — not the external HTTPS URL. Fix with `sed -i 's|BOTSERVER_URL=.*|BOTSERVER_URL=http://localhost:5858|'` on the service file, then `systemctl daemon-reload` and `systemctl restart ui`.
|
||||
|
||||
**Suggestions not showing:** Confirm bot `.bas` files exist in MinIO Drive under `{bot}.gbai/{bot}.gbdialog/`. Check logs for compilation errors. Clear the AST cache in `/opt/gbo/work/` and restart botserver.
|
||||
|
||||
**IPv6 DNS timeouts on external APIs (Groq, Cloudflare):** The container's DNS may return AAAA records without IPv6 connectivity. The container should have `IPV6=no` in its network config and `gai.conf` set appropriately. Check for `RES_OPTIONS=inet4` in `botserver.service` if issues persist.
|
||||
|
||||
**Logs show development paths instead of Drive:** Botserver is using hardcoded dev paths. Check `.env` has `DATA_DIR=/opt/gbo/work/` and `WORK_DIR=/opt/gbo/work/`, verify the systemd unit has `EnvironmentFile=/opt/gbo/bin/.env`, and confirm Vault is reachable so service discovery works. Expected startup log lines include `info watcher:Watching data directory /opt/gbo/work` and `info botserver:BotServer started successfully on port 5858`.
|
||||
|
||||
**Migrations not running after push:** If `stat /opt/gbo/bin/botserver` shows old timestamp and `__diesel_schema_migrations` table has no new entries, CI did not rebuild. Make a trivial code change (e.g., add a comment) in botserver and push again to force rebuild.
|
||||
|
||||
---
|
||||
|
||||
## Drive (MinIO) File Operations Cheatsheet
|
||||
|
||||
All `mc` commands run inside the `drive` container with `PATH` set: `sudo incus exec drive -- bash -c 'export PATH=/opt/gbo/bin:$PATH && mc <command>'`. If `local` alias is missing, create it with credentials from Vault path `gbo/drive`.
|
||||
|
||||
**List bucket contents recursively:** `mc ls local/<bot>.gbai/ --recursive`
|
||||
|
||||
**Read a file from Drive:** `mc cat local/<bot>.gbai/<bot>.gbdialog/start.bas`
|
||||
|
||||
**Download a file:** `mc cp local/<bot>.gbai/<bot>.gbdialog/start.bas /tmp/start.bas`
|
||||
|
||||
**Upload a file to Drive (triggers DriveMonitor recompile):** Transfer file to host via `scp`, push into drive container with `sudo incus file push /tmp/file drive/tmp/file`, then `mc put /tmp/file local/<bot>.gbai/<bot>.gbdialog/start.bas`
|
||||
|
||||
**Full upload workflow example — updating config.csv:**
|
||||
```bash
|
||||
# 1. Download current config from Drive
|
||||
ssh user@host "sudo incus exec drive -- bash -c 'export PATH=/opt/gbo/bin:\$PATH && mc cat local/botname.gbai/botname.gbot/config.csv'" > /tmp/config.csv
|
||||
|
||||
# 2. Edit locally (change model, keys, etc.)
|
||||
sed -i 's/llm-model,old-model/llm-model,new-model/' /tmp/config.csv
|
||||
|
||||
# 3. Push edited file back to Drive
|
||||
scp /tmp/config.csv user@host:/tmp/config.csv
|
||||
ssh user@host "sudo incus file push /tmp/config.csv drive/tmp/config.csv"
|
||||
ssh user@host "sudo incus exec drive -- bash -c 'export PATH=/opt/gbo/bin:\$PATH && mc put /tmp/config.csv local/botname.gbai/botname.gbot/config.csv'"
|
||||
|
||||
# 4. Wait ~15 seconds, then verify DriveMonitor picked up the change
|
||||
ssh user@host "sudo incus exec system -- bash -c 'grep -i \"Model:\" /opt/gbo/logs/err.log | tail -3'"
|
||||
```
|
||||
|
||||
**Force re-sync of config.csv** (change ETag without content change): `mc cp local/<bot>.gbai/<bot>.gbot/config.csv local/<bot>.gbai/<bot>.gbot/config.csv`
|
||||
|
||||
**Create a new bot bucket:** `mc mb local/newbot.gbai`
|
||||
|
||||
**Check MinIO health:** `sudo incus exec drive -- bash -c '/opt/gbo/bin/mc admin info local'`
|
||||
|
||||
---
|
||||
|
||||
## Logging Quick Reference
|
||||
|
||||
**Application logs** (searchable, timestamped, most useful): `sudo incus exec system -- tail -f /opt/gbo/logs/err.log` (errors and debug) or `/opt/gbo/logs/out.log` (stdout). The systemd journal only captures process lifecycle events, not application output.
|
||||
|
||||
**Search logs for specific bot activity:** `grep -i "botname\|llm\|Model:\|KB\|USE_KB\|drive_monitor" /opt/gbo/logs/err.log | tail -30`
|
||||
|
||||
**Check which LLM model a bot is using:** `grep "Model:" /opt/gbo/logs/err.log | tail -5`
|
||||
|
||||
**Check DriveMonitor config sync:** `grep "check_gbot\|config.csv\|should_sync" /opt/gbo/logs/err.log | tail -20`
|
||||
|
||||
**Check KB/vector operations:** `grep -i "gbkb\|qdrant\|embedding\|index" /opt/gbo/logs/err.log | tail -20`
|
||||
|
||||
**Live tail with filter:** `sudo incus exec system -- bash -c 'tail -f /opt/gbo/logs/err.log | grep --line-buffered -i "botname\|error\|KB"'`
|
||||
|
||||
---
|
||||
|
||||
## Program Access Cheatsheet
|
||||
|
||||
| Program | Container | Path | Notes |
|
||||
|---------|-----------|------|-------|
|
||||
| botserver | system | `/opt/gbo/bin/botserver` | Run via systemctl only |
|
||||
| botui | system | `/opt/gbo/bin/botui` | Run via systemctl only |
|
||||
| mc (MinIO Client) | drive | `/opt/gbo/bin/mc` | Must set `PATH=/opt/gbo/bin:$PATH` |
|
||||
| psql | tables | `/usr/bin/psql` | `psql -h localhost -U postgres -d botserver` |
|
||||
| vault | vault | `/opt/gbo/bin/vault` | Needs `VAULT_ADDR`, `VAULT_TOKEN`, `VAULT_CACERT` |
|
||||
| zitadel | directory | `/opt/gbo/bin/zitadel` | Runs as root on port 8080 internally |
|
||||
|
||||
**Quick psql query — bot config:** `sudo incus exec tables -- psql -h localhost -U postgres -d botserver -c "SELECT config_key, config_value FROM bot_configuration WHERE bot_id = (SELECT id FROM bots WHERE name = 'botname') ORDER BY config_key;"`
|
||||
|
||||
**Quick psql query — active KBs for session:** `sudo incus exec tables -- psql -h localhost -U postgres -d botserver -c "SELECT * FROM session_kb_associations WHERE session_id = '<uuid>' AND is_active = true;"`
|
||||
|
||||
---
|
||||
|
||||
## BASIC Compilation Architecture
|
||||
|
||||
Compilation and runtime are now strictly separated. **Compilation** happens only in `BasicCompiler` inside DriveMonitor when it detects `.bas` file changes. The output is a fully preprocessed `.ast` file written to `work/<bot>.gbai/<bot>.gbdialog/<tool>.ast`. **Runtime** (start.bas, TOOL_EXEC, automation, schedule) loads only `.ast` files and calls `ScriptService::run()` which does `engine.compile() + eval_ast_with_scope()` on the already-preprocessed Rhai source — no preprocessing at runtime.
|
||||
|
||||
The `.ast` file has all transforms applied: `USE KB "cartas"` becomes `USE_KB("cartas")`, `IF/END IF` → `if/{ }`, `WHILE/WEND` → `while/{ }`, `BEGIN TALK/END TALK` → function calls, `SAVE`, `FOR EACH/NEXT`, `SELECT CASE`, `SET SCHEDULE`, `WEBHOOK`, `USE WEBSITE`, `LLM` keyword expansion, variable predeclaration, and keyword lowercasing. Runtime never calls `compile()`, `compile_tool_script()`, or `compile_preprocessed()` — those methods no longer exist.
|
||||
|
||||
**Tools (TOOL_EXEC) load `.ast` only** — there is no `.bas` fallback. If an `.ast` file is missing, the tool fails with "Failed to read tool .ast file". DriveMonitor must have compiled it first.
|
||||
|
||||
**Suggestion deduplication** uses Redis `SADD` (set) instead of `RPUSH` (list). This prevents duplicate suggestion buttons when `start.bas` runs multiple times per session. The key format is `suggestions:{bot_id}:{session_id}` and `get_suggestions` uses `SMEMBERS` to read it.
|
||||
|
||||
---
|
||||
|
||||
## Container Quick Reference
|
||||
|
||||
| Container | Critical | Check Command | Restart Command |
|
||||
|-----------|----------|---------------|-----------------|
|
||||
| system | YES | `systemctl is-active botserver` | `systemctl restart botserver` |
|
||||
| tables | YES | `pgrep -f postgres` | `systemctl restart postgresql` |
|
||||
| vault | YES | `curl -ksf https://localhost:8200/v1/sys/health` | `systemctl restart vault` |
|
||||
| drive | YES | `pgrep -f minio` | `systemctl restart minio` |
|
||||
| cache | HIGH | `pgrep -f valkey` | `systemctl restart valkey` |
|
||||
| directory | HIGH | `curl -sf http://localhost:8080/debug/healthz` | `systemctl restart directory` |
|
||||
| alm-ci | MED | `pgrep -f forgejo` | manual restart |
|
||||
| llm | MED | `curl -sf http://localhost:8081/health` | `systemctl restart llm` |
|
||||
| vector_db | LOW | `curl -sf http://localhost:6333/healthz` | `systemctl restart qdrant` |
|
||||
|
||||
---
|
||||
|
||||
## Log Tailing Commands
|
||||
|
||||
```bash
|
||||
# Live error monitoring
|
||||
sudo incus exec system -- tail -f /opt/gbo/logs/err.log | grep -i "error\|panic\|failed"
|
||||
|
||||
# Bot-specific activity
|
||||
sudo incus exec system -- tail -f /opt/gbo/logs/err.log | grep -i "<botname>"
|
||||
|
||||
# DriveMonitor activity
|
||||
sudo incus exec system -- tail -f /opt/gbo/logs/err.log | grep -i "drive\|config"
|
||||
|
||||
# LLM calls
|
||||
sudo incus exec system -- tail -f /opt/gbo/logs/err.log | grep -i "model\|llm\|groq"
|
||||
|
||||
# CI runner
|
||||
sudo incus exec alm-ci -- tail -f /opt/gbo/logs/forgejo-runner.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Health Endpoint Monitoring
|
||||
|
||||
Set up a simple cron job to alert if health fails:
|
||||
|
||||
```bash
|
||||
# Add to host crontab (crontab -e)
|
||||
*/5 * * * * curl -sf https://<system-domain>/api/health || echo "ALERT: Health check failed at $(date)" >> /var/log/gbo-health.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Quick Reference
|
||||
|
||||
### Container Won't Start (No IPv4)
|
||||
|
||||
**Symptom:** Container shows empty IPV4 column in `sudo incus list`
|
||||
|
||||
**Diagnose:**
|
||||
```bash
|
||||
sudo incus list <container> -c n4
|
||||
sudo incus exec <container> -- ip addr show eth0
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# 1. Stop container
|
||||
sudo incus stop <container>
|
||||
|
||||
# 2. Set static IP
|
||||
sudo incus config device set <container> eth0 ipv4.address <ip-address>
|
||||
|
||||
# 3. Configure network inside
|
||||
sudo incus exec <container> -- bash -c 'cat > /etc/network/interfaces << EOF
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet static
|
||||
address <ip-address>
|
||||
netmask 255.255.255.0
|
||||
gateway <gateway>
|
||||
dns-nameservers 8.8.8.8 8.8.4.4
|
||||
EOF'
|
||||
|
||||
# 4. Restart
|
||||
sudo incus restart <container>
|
||||
|
||||
# 5. Verify
|
||||
sudo incus exec <container> -- ip addr show eth0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CI/ALM Permission Errors
|
||||
|
||||
**Symptom:** `/tmp permission denied` during CI build
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# On alm-ci container
|
||||
sudo incus exec alm-ci -- chmod 1777 /tmp
|
||||
sudo incus exec alm-ci -- touch /tmp/build.log && chmod 666 /tmp/build.log
|
||||
|
||||
# Check runner user
|
||||
sudo incus exec alm-ci -- ls -la /opt/gbo/
|
||||
|
||||
# Fix ownership
|
||||
sudo incus exec alm-ci -- chown -R gbuser:gbuser /opt/gbo/bin/
|
||||
sudo incus exec alm-ci -- chown -R gbuser:gbuser /opt/gbo/work/
|
||||
```
|
||||
|
||||
**CI Runner Down:**
|
||||
```bash
|
||||
sudo incus exec alm-ci -- pkill -9 forgejo
|
||||
sleep 2
|
||||
sudo incus exec alm-ci -- bash -c 'cd /opt/gbo/bin && nohup ./forgejo-runner daemon --config config.yaml >> /opt/gbo/logs/forgejo-runner.log 2>&1 &'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### MinIO (Drive) Operations with `mc`
|
||||
|
||||
**Setup:**
|
||||
```bash
|
||||
# Access drive container
|
||||
sudo incus exec drive -- bash
|
||||
|
||||
# Set PATH
|
||||
export PATH=/opt/gbo/bin:$PATH
|
||||
|
||||
# Verify mc works
|
||||
mc --version
|
||||
```
|
||||
|
||||
**Common Commands:**
|
||||
```bash
|
||||
# List all buckets
|
||||
mc ls local/
|
||||
|
||||
# List bot bucket
|
||||
mc ls local/<botname>.gbai/
|
||||
|
||||
# Read start.bas
|
||||
mc cat local/<botname>.gbai/<botname>.gbdialog/start.bas
|
||||
|
||||
# Download file
|
||||
mc cp local/<botname>.gbai/<botname>.gbdialog/config.csv /tmp/config.csv
|
||||
|
||||
# Upload file (triggers DriveMonitor)
|
||||
mc cp /tmp/config.csv local/<botname>.gbai/<botname>.gbot/config.csv
|
||||
|
||||
# Force re-sync (change ETag)
|
||||
mc cp local/<bot>.gbai/<bot>.gbot/config.csv local/<bot>.gbai/<bot>.gbot/config.csv
|
||||
|
||||
# Create new bucket
|
||||
mc mb local/newbot.gbai
|
||||
|
||||
# Check MinIO health
|
||||
mc admin info local
|
||||
```
|
||||
|
||||
**If `local` alias missing:**
|
||||
```bash
|
||||
# Create alias
|
||||
mc alias set local http://localhost:9000 <access-key> <secret-key>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Forgejo ALM Database Operations
|
||||
|
||||
**Access ALM database (PROD-ALM):**
|
||||
```bash
|
||||
# On tables container
|
||||
sudo incus exec tables -- psql -h localhost -U postgres -d PROD-ALM
|
||||
```
|
||||
|
||||
**Common Queries:**
|
||||
```sql
|
||||
-- Check CI runs
|
||||
SELECT id, status, commit_sha, created FROM action_run ORDER BY id DESC LIMIT 10;
|
||||
|
||||
-- Status codes: 0=pending, 1=success, 2=failure, 3=cancelled, 6=running
|
||||
|
||||
-- Check specific run jobs
|
||||
SELECT id, status, name FROM action_run_job WHERE run_id = <ID>;
|
||||
|
||||
-- Reset stuck run
|
||||
UPDATE action_task SET status = 0 WHERE id = <ID>;
|
||||
UPDATE action_run_job SET status = 0 WHERE run_id = <RUN_ID>;
|
||||
UPDATE action_run SET status = 0 WHERE id = <RUN_ID>;
|
||||
|
||||
-- Check runner token
|
||||
SELECT * FROM action_runner_token;
|
||||
|
||||
-- List runners
|
||||
SELECT * FROM action_runner;
|
||||
```
|
||||
|
||||
**Check CI from host:**
|
||||
```bash
|
||||
export PGPASSWORD=<password>
|
||||
sudo incus exec tables -- psql -h localhost -U postgres -d PROD-ALM -c "SELECT id, status, created FROM action_run ORDER BY id DESC LIMIT 5;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Zitadel API v2 Operations
|
||||
|
||||
**Important:** Always use **v2 API** - v1 is deprecated and non-functional.
|
||||
|
||||
**Get PAT:**
|
||||
```bash
|
||||
PAT=$(sudo incus exec directory -- cat /opt/gbo/conf/directory/admin-pat.txt)
|
||||
```
|
||||
|
||||
**Common Operations:**
|
||||
|
||||
**Create User (v2):**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/users/human" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{
|
||||
"username": "newuser",
|
||||
"profile": {"givenName": "New", "familyName": "User"},
|
||||
"email": {"email": "user@example.com", "isVerified": true},
|
||||
"password": {"password": "<password>", "changeRequired": false}
|
||||
}'
|
||||
```
|
||||
|
||||
**List Users (v2):**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/users" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{"query": {"offset": 0, "limit": 100}}'
|
||||
```
|
||||
|
||||
**Create Organization (v2):**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/organizations" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{"name": "organization-name"}'
|
||||
```
|
||||
|
||||
**Add Domain to Org (v2):**
|
||||
```bash
|
||||
curl -X POST "http://<directory-ip>:8080/v2/organizations/<org-id>/domains" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAT" \
|
||||
-H "Host: <directory-ip>" \
|
||||
-d '{"domainName": "example.com"}'
|
||||
```
|
||||
|
||||
**⚠️ Critical:** Always include `-H "Host: <directory-ip>"` header or API returns 404.
|
||||
|
||||
---
|
||||
|
||||
### Common Errors & Quick Fixes
|
||||
|
||||
| Error | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| `No IPv4 on container` | DHCP failed | Set static IP (see above) |
|
||||
| `/tmp permission denied` | Wrong permissions | `chmod 1777 /tmp` |
|
||||
| `Errors.Token.Invalid (AUTH-7fs1e)` | Zitadel PAT expired | Regenerate via console |
|
||||
| `failed SASL auth` | Wrong DB password | Check Vault credentials |
|
||||
| `GLIBC_2.39 not found` | Wrong build environment | Rebuild in system container |
|
||||
| `connection refused` | Service down | `systemctl restart <service>` |
|
||||
| `exec format error` | Architecture mismatch | Recompile for target arch |
|
||||
| `address already in use` | Port conflict | `lsof -i :<port>` |
|
||||
| `certificate verify failed` | Wrong CA cert | Copy from vault container |
|
||||
| `DNS lookup failed` | No IPv4 connectivity | Check network config |
|
||||
|
||||
---
|
||||
|
||||
## Contact Escalation
|
||||
|
||||
If quick fixes don't work:
|
||||
|
||||
1. Capture logs: `sudo incus exec system -- tar czf /tmp/debug-$(date +%Y%m%d).tar.gz /opt/gbo/logs/`
|
||||
2. Check AGENTS.md for development troubleshooting
|
||||
3. Review recent commits for breaking changes
|
||||
4. Consider snapshot rollback (last resort)
|
||||
743
README.md
743
README.md
|
|
@ -1,8 +1,27 @@
|
|||
RULE 0: Never call tool_call while thinking. Ex NEVER do this: Let me check if the API call succeeded:<tool_call>terminal<arg_key>command</arg_key><arg_value>tail -50 botserver.log | grep -E "LLM streaming error|error|Error|SUCCESS|200"</arg_value><arg_key>cd</arg_key><arg_value>gb</arg_value></tool_call>. First finish Thinking, then emit a explanation and tool!
|
||||
# General Bots Workspace
|
||||
|
||||
## ⚠️ CRITICAL SECURITY WARNING
|
||||
|
||||
**Version:** 6.2.0
|
||||
**NEVER CREATE FILES WITH SECRETS IN THE REPOSITORY ROOT**
|
||||
|
||||
Secret files MUST be placed in `/tmp/` only:
|
||||
- ✅ `/tmp/vault-token-gb` - Vault root token
|
||||
- ✅ `/tmp/vault-unseal-key-gb` - Vault unseal key
|
||||
- ❌ `vault-unseal-keys` - FORBIDDEN (tracked by git)
|
||||
- ❌ `start-and-unseal.sh` - FORBIDDEN (contains secrets)
|
||||
|
||||
**Files added to .gitignore:** `vault-unseal-keys`, `start-and-unseal.sh`, `vault-token-*`
|
||||
|
||||
**Why `/tmp/`?**
|
||||
- Cleared on reboot (ephemeral)
|
||||
- Not tracked by git
|
||||
- Standard Unix security practice
|
||||
- Prevents accidental commits
|
||||
|
||||
---
|
||||
|
||||
|
||||
**Version:** 6.3.0
|
||||
**Type:** Rust Workspace (Monorepo with Independent Subproject Repos)
|
||||
|
||||
---
|
||||
|
|
@ -19,7 +38,7 @@ For comprehensive documentation, see **[docs.pragmatismo.com.br](https://docs.pr
|
|||
|
||||
| Crate | Purpose | Port | Tech Stack |
|
||||
|-------|---------|------|------------|
|
||||
| **botserver** | Main API server, business logic | 8088 | Axum, Diesel, Rhai BASIC |
|
||||
| **botserver** | Main API server, business logic | 9000 | Axum, Diesel, Rhai BASIC |
|
||||
| **botui** | Web UI server (dev) + proxy | 3000 | Axum, HTML/HTMX/CSS |
|
||||
| **botapp** | Desktop app wrapper | - | Tauri 2 |
|
||||
| **botlib** | Shared library | - | Core types, errors |
|
||||
|
|
@ -35,6 +54,35 @@ For comprehensive documentation, see **[docs.pragmatismo.com.br](https://docs.pr
|
|||
- **Env file:** `botserver/.env`
|
||||
- **Stack:** `botserver-stack/`
|
||||
- **UI Files:** `botui/ui/suite/`
|
||||
- **Local Bot Data:** `/opt/gbo/data/` (place `.gbai` packages here)
|
||||
|
||||
### Local Bot Data Directory
|
||||
|
||||
Place local bot packages in `/opt/gbo/data/` for automatic loading and monitoring:
|
||||
|
||||
**Directory Structure:**
|
||||
```
|
||||
/opt/gbo/data/
|
||||
└── mybot.gbai/
|
||||
├── mybot.gbdialog/
|
||||
│ ├── start.bas
|
||||
│ └── main.bas
|
||||
└── mybot.gbot/
|
||||
└── config.csv
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- **Auto-loading:** Bots automatically mounted on server startup
|
||||
- **Auto-compilation:** `.bas` files compiled to `.ast` on change
|
||||
- **Auto-creation:** New bots automatically added to database
|
||||
- **Hot-reload:** Changes trigger immediate recompilation
|
||||
- **Monitored by:** LocalFileMonitor and ConfigWatcher services
|
||||
|
||||
**Usage:**
|
||||
1. Create bot directory structure in `/opt/gbo/data/`
|
||||
2. Add `.bas` files to `<bot_name>.gbai/<bot_name>.gbdialog/`
|
||||
3. Server automatically detects and loads the bot
|
||||
4. Optional: Add `config.csv` for bot configuration
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -44,15 +92,36 @@ For comprehensive documentation, see **[docs.pragmatismo.com.br](https://docs.pr
|
|||
|
||||
BotServer automatically installs, configures, and manages all infrastructure components on first run. **DO NOT manually start these services** - BotServer handles everything.
|
||||
|
||||
| Component | Purpose | Port | Binary Location | Managed By |
|
||||
|-----------|---------|------|-----------------|------------|
|
||||
| **Vault** | Secrets management | 8200 | `botserver-stack/bin/vault/vault` | botserver |
|
||||
| **PostgreSQL** | Primary database | 5432 | `botserver-stack/bin/tables/bin/postgres` | botserver |
|
||||
| **MinIO** | Object storage (S3-compatible) | 9000/9001 | `botserver-stack/bin/drive/minio` | botserver |
|
||||
| **Zitadel** | Identity/Authentication | 8300 | `botserver-stack/bin/directory/zitadel` | botserver |
|
||||
| **Qdrant** | Vector database (embeddings) | 6333 | `botserver-stack/bin/vector_db/qdrant` | botserver |
|
||||
| **Valkey** | Cache/Queue (Redis-compatible) | 6379 | `botserver-stack/bin/cache/valkey-server` | botserver |
|
||||
| **Llama.cpp** | Local LLM server | 8081 | `botserver-stack/bin/llm/build/bin/llama-server` | botserver |
|
||||
**Automatic Service Lifecycle:**
|
||||
1. **Start**: When botserver starts, it automatically launches all infrastructure components (PostgreSQL, Vault, MinIO, Valkey, Qdrant, etc.)
|
||||
2. **Credentials**: BotServer retrieves all service credentials (passwords, tokens, API keys) from Vault
|
||||
3. **Connection**: BotServer uses these credentials to establish secure connections to each service
|
||||
4. **Query**: All database queries, cache operations, and storage requests are authenticated using Vault-managed credentials
|
||||
|
||||
**Credential Flow:**
|
||||
```
|
||||
botserver starts
|
||||
↓
|
||||
Launch PostgreSQL, MinIO, Valkey, Qdrant
|
||||
↓
|
||||
Connect to Vault
|
||||
↓
|
||||
Retrieve service credentials (from database)
|
||||
↓
|
||||
Authenticate with each service using retrieved credentials
|
||||
↓
|
||||
Ready to handle requests
|
||||
```
|
||||
|
||||
| Component | Purpose | Port | Binary Location | Credentials From |
|
||||
|-----------|---------|------|-----------------|------------------|
|
||||
| **Vault** | Secrets management | 8200 | `botserver-stack/bin/vault/vault` | Auto-unsealed |
|
||||
| **PostgreSQL** | Primary database | 5432 | `botserver-stack/bin/tables/bin/postgres` | Vault → database |
|
||||
| **MinIO** | Object storage (S3-compatible) | 9000/9001 | `botserver-stack/bin/drive/minio` | Vault → database |
|
||||
| **Zitadel** | Identity/Authentication | 8300 | `botserver-stack/bin/directory/zitadel` | Vault → database |
|
||||
| **Qdrant** | Vector database (embeddings) | 6333 | `botserver-stack/bin/vector_db/qdrant` | Vault → database |
|
||||
| **Valkey** | Cache/Queue (Redis-compatible) | 6379 | `botserver-stack/bin/cache/valkey-server` | Vault → database |
|
||||
| **Llama.cpp** | Local LLM server | 8081 | `botserver-stack/bin/llm/build/bin/llama-server` | Vault → database |
|
||||
|
||||
### 📦 Component Installation System
|
||||
|
||||
|
|
@ -271,9 +340,12 @@ cd botserver-stack/bin/cache && ./valkey-cli ping
|
|||
The script handles BOTH servers properly:
|
||||
1. Stop existing processes cleanly
|
||||
2. Build botserver and botui sequentially (no race conditions)
|
||||
3. Start botserver in background → auto-bootstrap infrastructure
|
||||
4. Start botui in background → proxy to botserver
|
||||
5. Show process IDs and monitoring commands
|
||||
3. Start botserver in background → **automatically starts all infrastructure services (PostgreSQL, Vault, MinIO, Valkey, Qdrant)**
|
||||
4. BotServer retrieves credentials from Vault and authenticates with all services
|
||||
5. Start botui in background → proxy to botserver
|
||||
6. Show process IDs and monitoring commands
|
||||
|
||||
**Infrastructure services are fully automated - no manual configuration required!**
|
||||
|
||||
**Monitor startup:**
|
||||
```bash
|
||||
|
|
@ -282,7 +354,7 @@ tail -f botserver.log botui.log
|
|||
|
||||
**Access:**
|
||||
- Web UI: http://localhost:3000
|
||||
- API: http://localhost:8088
|
||||
- API: http://localhost:9000
|
||||
|
||||
### 📊 Monitor & Debug
|
||||
|
||||
|
|
@ -306,7 +378,7 @@ grep -E " E |W |CLIENT:" botserver.log | tail -20
|
|||
|
||||
```bash
|
||||
cd botserver && cargo run -- --noconsole > ../botserver.log 2>&1 &
|
||||
cd botui && BOTSERVER_URL="http://localhost:8088" cargo run > ../botui.log 2>&1 &
|
||||
cd botui && BOTSERVER_URL="http://localhost:9000" cargo run > ../botui.log 2>&1 &
|
||||
```
|
||||
|
||||
### 🛑 Stop Servers
|
||||
|
|
@ -324,7 +396,7 @@ rm -rf botserver-stack/data/vault botserver-stack/conf/vault/init.json && ./rest
|
|||
|
||||
**Port in use?** Find and kill:
|
||||
```bash
|
||||
lsof -ti:8088 | xargs kill -9
|
||||
lsof -ti:9000 | xargs kill -9
|
||||
lsof -ti:3000 | xargs kill -9
|
||||
```
|
||||
|
||||
|
|
@ -335,8 +407,59 @@ All infrastructure services (PostgreSQL, Vault, Redis, Qdrant, MinIO, etc.) are
|
|||
- **Configurations:** `botserver-stack/conf/`
|
||||
- **Data storage:** `botserver-stack/data/`
|
||||
- **Service logs:** `botserver-stack/logs/` (check here for troubleshooting)
|
||||
- **Credentials:** Stored in Vault, retrieved by botserver at startup
|
||||
|
||||
**Do NOT install or reference global PostgreSQL, Redis, or other services.** When botserver starts, it automatically launches all required stack services. If you encounter service errors, check the individual service logs in `./botserver-stack/logs/[service]/` directories.
|
||||
**Do NOT install or reference global PostgreSQL, Redis, or other services.** When botserver starts, it automatically:
|
||||
1. Launches all required stack services
|
||||
2. Connects to Vault
|
||||
3. Retrieves credentials from the `bot_configuration` database table
|
||||
4. Authenticates with each service using retrieved credentials
|
||||
5. Begins handling requests with authenticated connections
|
||||
|
||||
If you encounter service errors, check the individual service logs in `./botserver-stack/logs/[service]/` directories.
|
||||
|
||||
### UI File Deployment - Production Options
|
||||
|
||||
**Option 1: Embedded UI (Recommended for Production)**
|
||||
|
||||
The `embed-ui` feature compiles UI files directly into the botui binary, eliminating the need for separate file deployment:
|
||||
|
||||
```bash
|
||||
# Build with embedded UI files
|
||||
cargo build --release -p botui --features embed-ui
|
||||
|
||||
# The binary now contains all UI files - no additional deployment needed!
|
||||
# The botui binary is self-contained and production-ready
|
||||
```
|
||||
|
||||
**Benefits of embed-ui:**
|
||||
- ✅ Single binary deployment (no separate UI files)
|
||||
- ✅ Faster startup (no filesystem access)
|
||||
- ✅ Smaller attack surface
|
||||
- ✅ Simpler deployment process
|
||||
|
||||
**Option 2: Filesystem Deployment (Development Only)**
|
||||
|
||||
For development, UI files are served from the filesystem:
|
||||
|
||||
```bash
|
||||
# UI files must exist at botui/ui/suite/
|
||||
# This is automatically available in development builds
|
||||
```
|
||||
|
||||
**Option 3: Manual File Deployment (Legacy)**
|
||||
|
||||
If you need to deploy UI files separately (not recommended):
|
||||
|
||||
```bash
|
||||
# Deploy UI files to production location
|
||||
./botserver/deploy/deploy-ui.sh /opt/gbo
|
||||
|
||||
# Verify deployment
|
||||
ls -la /opt/gbo/bin/ui/suite/index.html
|
||||
```
|
||||
|
||||
See `botserver/deploy/README.md` for deployment scripts.
|
||||
|
||||
### Start Both Servers (Automated)
|
||||
```bash
|
||||
|
|
@ -350,7 +473,7 @@ All infrastructure services (PostgreSQL, Vault, Redis, Qdrant, MinIO, etc.) are
|
|||
cd botserver && cargo run -- --noconsole
|
||||
|
||||
# Terminal 2: botui
|
||||
cd botui && BOTSERVER_URL="http://localhost:8088" cargo run
|
||||
cd botui && BOTSERVER_URL="http://localhost:9000" cargo run
|
||||
```
|
||||
|
||||
### Build Commands
|
||||
|
|
@ -367,234 +490,11 @@ cargo test -p bottest
|
|||
|
||||
---
|
||||
|
||||
## 🧭 LLM Navigation Guide
|
||||
## 🤖 AI Agent Guidelines
|
||||
|
||||
### Quick Context Jump
|
||||
- [Primary Purpose](#overview) - Unified workspace for AI automation platform
|
||||
- [Crate Structure](#-workspace-structure) - 9 independent crates with shared libraries
|
||||
- [Dependencies](#-component-dependency-graph) - How crates depend on each other
|
||||
- [Quick Start](#quick-start) - Get running in 2 commands
|
||||
- [Error Patterns](#common-error-patterns) - Fix compilation errors efficiently
|
||||
- [Security Rules](#-security-directives---mandatory) - MUST-FOLLOW security patterns
|
||||
- [Code Patterns](#-mandatory-code-patterns) - Required coding conventions
|
||||
- [Testing](#testing-strategy) - How to test changes
|
||||
- [Debugging](#debugging-guide) - Troubleshoot common issues
|
||||
> **For LLM instructions, coding rules, security directives, testing workflows, and error handling patterns, see [AGENTS.md](./AGENTS.md).**
|
||||
|
||||
### Reading This Workspace
|
||||
|
||||
**For LLMs analyzing this codebase:**
|
||||
1. Start with [Component Dependency Graph](#-component-dependency-graph) to understand relationships
|
||||
2. Review [Module Responsibility Matrix](#-module-responsibility-matrix) for what each module does
|
||||
3. Study [Data Flow Patterns](#-data-flow-patterns) to understand execution flow
|
||||
4. Reference [Common Architectural Patterns](#-common-architectural-patterns) before making changes
|
||||
5. Check [Security Rules](#-security-directives---mandatory) - violations are blocking issues
|
||||
6. Follow [Code Patterns](#-mandatory-code-patterns) - consistency is mandatory
|
||||
|
||||
**For Humans working on this codebase:**
|
||||
1. Follow [Error Fixing Workflow](#-error-fixing-workflow) for compilation errors
|
||||
2. Observe [File Size Limits](#-file-size-limits---mandatory) - max 450 lines per file
|
||||
3. Run [Weekly Maintenance Tasks](#-weekly-maintenance-tasks) to keep codebase healthy
|
||||
4. Read project-specific READMEs in [Project-Specific Guidelines](#-project-specific-guidelines)
|
||||
|
||||
## 🧪 Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- **Location**: Each crate has `tests/` directory or inline `#[cfg(test)]` modules
|
||||
- **Naming**: Test functions use `test_` prefix or describe what they test
|
||||
- **Running**: `cargo test -p <crate_name>` or `cargo test` for all
|
||||
|
||||
### Integration Tests
|
||||
- **Location**: `bottest/` crate contains integration tests
|
||||
- **Scope**: Tests full workflows across multiple crates
|
||||
- **Running**: `cargo test -p bottest`
|
||||
- **Database**: Uses test database, automatically migrates on first run
|
||||
|
||||
### Test Utilities Available
|
||||
- **TestAppStateBuilder** (`bottest/src/harness.rs`) - Build test state with mocked components
|
||||
- **TestBot** (`bottest/src/bot/mod.rs`) - Mock bot for testing
|
||||
- **Test Database**: Auto-created, migrations run automatically
|
||||
|
||||
### Coverage Goals
|
||||
- **Critical paths**: 80%+ coverage required
|
||||
- **Error handling**: ALL error paths must have tests
|
||||
- **Security**: All security guards must have tests
|
||||
|
||||
## 🚨 CRITICAL ERROR HANDLING RULE
|
||||
|
||||
**STOP EVERYTHING WHEN ERRORS APPEAR**
|
||||
|
||||
When ANY error appears in logs during startup or operation:
|
||||
1. **IMMEDIATELY STOP** - Do not continue with other tasks
|
||||
2. **IDENTIFY THE ERROR** - Read the full error message and context
|
||||
3. **FIX THE ERROR** - Address the root cause, not symptoms
|
||||
4. **VERIFY THE FIX** - Ensure error is completely resolved
|
||||
5. **ONLY THEN CONTINUE** - Never ignore or work around errors
|
||||
|
||||
**NEVER restart servers to "fix" errors - FIX THE ACTUAL PROBLEM**
|
||||
|
||||
Examples of errors that MUST be fixed immediately:
|
||||
- Database connection errors
|
||||
- Component initialization failures
|
||||
- Service startup errors
|
||||
- Configuration errors
|
||||
- Any error containing "Error:", "Failed:", "Cannot", "Unable"
|
||||
|
||||
## 🐛 Debugging Guide
|
||||
|
||||
### Log Locations
|
||||
|
||||
| Component | Log File | What's Logged |
|
||||
|-----------|----------|---------------|
|
||||
| **botserver** | `botserver.log` | API requests, errors, script execution, **client navigation events** |
|
||||
| **botui** | `botui.log` | UI rendering, WebSocket connections |
|
||||
| **drive_monitor** | In botserver logs with `[drive_monitor]` prefix | File sync, compilation |
|
||||
| **script execution** | In botserver logs with `[ScriptService]` prefix | BASIC compilation, runtime errors |
|
||||
| **client errors** | In botserver logs with `CLIENT:` prefix | JavaScript errors, navigation events |
|
||||
|
||||
### Client-Side Logging
|
||||
|
||||
**Navigation Tracking:** All client-side navigation is logged to botserver.log with `CLIENT:` prefix:
|
||||
```
|
||||
CLIENT:NAVIGATION: click: home -> drive
|
||||
CLIENT:NAVIGATION: hashchange: drive -> chat
|
||||
```
|
||||
|
||||
**Error Reporting:** JavaScript errors automatically appear in server logs:
|
||||
```
|
||||
CLIENT:ERROR: Uncaught TypeError: Cannot read property 'x' of undefined at /suite/js/app.js:123
|
||||
```
|
||||
|
||||
**For LLM Troubleshooting:** ALWAYS check both:
|
||||
1. `botserver.log` - Server errors + client navigation/errors (prefixed with `CLIENT:`)
|
||||
2. `botui.log` - UI server logs
|
||||
|
||||
### USE WEBSITE Feature - Vector DB Context Injection
|
||||
|
||||
**FIXED (v6.2.0+):** The `USE WEBSITE` BASIC command now properly injects vector database embeddings into chat context.
|
||||
|
||||
**How it works:**
|
||||
1. **Preprocessing:** When a `.bas` file containing `USE WEBSITE "https://..."` is compiled, the website is registered for crawling
|
||||
2. **Crawling:** Content is extracted, chunked, and embedded into Qdrant vector DB (collection name: `website_<url_hash>`)
|
||||
3. **Runtime Association:** The compiled `.ast` file contains `USE_WEBSITE()` function call that creates session-website association
|
||||
4. **Context Injection:** During chat, `inject_kb_context()` searches active websites' embeddings and includes relevant chunks in LLM prompt
|
||||
|
||||
**Example BASIC script:**
|
||||
```basic
|
||||
USE WEBSITE "https://docs.pragmatismo.com.br" REFRESH "1h"
|
||||
|
||||
TALK "Hello! I can now answer questions about the documentation."
|
||||
```
|
||||
|
||||
**Database tables involved:**
|
||||
- `session_website_associations` - Links sessions to websites
|
||||
- `website_embeddings` - Stores crawled content vectors in Qdrant
|
||||
|
||||
**Verification:**
|
||||
```sql
|
||||
-- Check if website is associated with session
|
||||
SELECT * FROM session_website_associations WHERE session_id = '<uuid>';
|
||||
|
||||
-- Check if embeddings exist in Qdrant (via HTTP API)
|
||||
curl http://localhost:6333/collections/website_<hash>/points/scroll
|
||||
```
|
||||
|
||||
**Previous Issue:** In earlier versions, `USE WEBSITE` was removed during preprocessing and never executed at runtime, preventing context injection. Now the function call is preserved in the compiled AST.
|
||||
|
||||
### Common Error Messages
|
||||
|
||||
| Error | Meaning | Fix |
|
||||
|-------|---------|-----|
|
||||
| `Session not found` | Invalid session_id in request | Check auth flow, verify session exists in DB |
|
||||
| `Bot not found` | Invalid bot_name or bot_id | Verify bot exists in `bots` table |
|
||||
| `Script compilation error` | BASIC syntax error in .bas file | Check .bas file syntax, look for typos |
|
||||
| `Failed to send TALK message` | WebSocket disconnected | Check client connection, verify web_adapter running |
|
||||
| `Drive sync failed` | S3 connection or permission issue | Verify S3 credentials, check bucket exists |
|
||||
| `unwrap() called on None value` | Panic in production code | MUST FIX - replace with proper error handling |
|
||||
| `Component not responding: <component_name>` | Infrastructure component not accessible | Check component status: `ps aux | grep <component>`. View logs: `tail -f botserver-stack/logs/<component>/`. Restart via ./restart.sh |
|
||||
| `Config key not found: <key>` | Missing configuration in database | Check `bot_configuration` table. Set correct value via API or direct SQL update. |
|
||||
| `403 Forbidden on POST /api/client-errors` | RBAC blocking client error reporting | FIXED in v6.2.0+ - endpoint now allows anonymous access |
|
||||
|
||||
### Useful Debugging Commands
|
||||
|
||||
```bash
|
||||
# Check if botserver is running
|
||||
ps aux | grep botserver
|
||||
|
||||
# View botserver logs in real-time
|
||||
tail -f botserver/logs/botserver.log
|
||||
|
||||
# Check work directory structure
|
||||
ls -la ./work/*.gbai/*/
|
||||
|
||||
# Test database connection
|
||||
cd botserver && cargo run --bin botserver -- --test-db
|
||||
|
||||
# Run specific test with output
|
||||
cargo test -p botserver test_name -- --nocapture
|
||||
|
||||
# Check for memory leaks during compilation
|
||||
CARGO_BUILD_JOBS=1 cargo check -p botserver 2>&1 | grep -i error
|
||||
```
|
||||
|
||||
### Troubleshooting Workflows
|
||||
|
||||
**Problem: Script not executing**
|
||||
1. Check if .bas file exists in `./work/{bot_name}.gbai/{bot_name}.gbdialog/`
|
||||
2. Verify file has correct syntax (compile with ScriptService)
|
||||
3. Check logs for compilation errors
|
||||
4. Verify drive_monitor is running and syncing files
|
||||
|
||||
**Problem: WebSocket messages not received**
|
||||
1. Check browser console for WebSocket errors
|
||||
2. Verify session_id is valid in database
|
||||
3. Check web_adapter is registered for session
|
||||
4. Look for TALK execution in botserver logs
|
||||
|
||||
**Problem: Component not starting or crashing**
|
||||
1. Identify the component from error message (e.g., Vault, PostgreSQL, MinIO, Qdrant, Valkey)
|
||||
2. Check if process is running: `ps aux | grep <component_name>`
|
||||
3. Check component logs: `tail -f botserver-stack/logs/<component_name>/`
|
||||
4. Common fixes:
|
||||
- Config error: Check `botserver-stack/conf/<component_name>/` for valid configuration
|
||||
- Port conflict: Ensure no other process using the component's port
|
||||
- Permission error: Check file permissions in `botserver-stack/data/<component_name>/`
|
||||
- Missing binary: Re-run `./reset.sh && ./restart.sh` to reinstall components
|
||||
5. Restart: `./restart.sh`
|
||||
|
||||
**Problem: Component configuration errors**
|
||||
1. All component configs stored in database `bot_configuration` table
|
||||
2. Check current value: `SELECT * FROM bot_configuration WHERE config_key = '<key_name>';`
|
||||
3. Update incorrect config: `UPDATE bot_configuration SET config_value = '<correct_value>' WHERE config_key = '<key_name>';`
|
||||
4. For path configs: Ensure paths are relative to component binary or absolute
|
||||
5. Restart botserver after config changes
|
||||
|
||||
**Problem: File not found errors**
|
||||
1. Check if file exists in expected location
|
||||
2. Verify config paths use correct format (relative/absolute)
|
||||
3. Check file permissions: `ls -la <file_path>`
|
||||
4. For model/data files: Ensure downloaded to `botserver-stack/data/<component>/`
|
||||
|
||||
**Problem: LLM not responding**
|
||||
1. Check LLM API credentials in config
|
||||
2. Verify API key has available quota
|
||||
3. Check network connectivity to LLM provider
|
||||
4. Review request/response logs for API errors
|
||||
|
||||
### Performance Profiling
|
||||
|
||||
```bash
|
||||
# Profile compilation time
|
||||
cargo build --release --timings
|
||||
|
||||
# Profile runtime performance
|
||||
cargo flamegraph --bin botserver
|
||||
|
||||
# Check binary size
|
||||
ls -lh target/release/botserver
|
||||
|
||||
# Memory usage
|
||||
valgrind --leak-check=full target/release/botserver
|
||||
```
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
|
||||
|
|
@ -614,284 +514,7 @@ valgrind --leak-check=full target/release/botserver
|
|||
|
||||
---
|
||||
|
||||
## 🔥 Error Fixing Workflow
|
||||
|
||||
### Mode 1: OFFLINE Batch Fix (PREFERRED)
|
||||
|
||||
When given error output:
|
||||
|
||||
```
|
||||
1. Read ENTIRE error list first
|
||||
2. Group errors by file
|
||||
3. For EACH file with errors:
|
||||
a. View file → understand context
|
||||
b. Fix ALL errors in that file
|
||||
c. Write once with all fixes
|
||||
4. Move to next file
|
||||
5. REPEAT until ALL errors addressed
|
||||
6. ONLY THEN → verify with build/diagnostics
|
||||
```
|
||||
|
||||
**NEVER run cargo build/check/clippy DURING fixing**
|
||||
**Fix ALL errors OFFLINE first, verify ONCE at the end**
|
||||
|
||||
### Mode 2: Interactive Loop
|
||||
|
||||
```
|
||||
LOOP UNTIL (0 warnings AND 0 errors):
|
||||
1. Run diagnostics → pick file with issues
|
||||
2. Read entire file
|
||||
3. Fix ALL issues in that file
|
||||
4. Write file once with all fixes
|
||||
5. Verify with diagnostics
|
||||
6. CONTINUE LOOP
|
||||
END LOOP
|
||||
```
|
||||
|
||||
### Common Error Patterns
|
||||
|
||||
| Error | Fix |
|
||||
|-------|-----|
|
||||
| `expected i64, found u64` | `value as i64` |
|
||||
| `expected Option<T>, found T` | `Some(value)` |
|
||||
| `expected T, found Option<T>` | `value.unwrap_or(default)` |
|
||||
| `cannot multiply f32 by f64` | `f64::from(f32_val) * f64_val` |
|
||||
| `no field X on type Y` | Check struct definition |
|
||||
| `no variant X found` | Check enum definition |
|
||||
| `function takes N arguments` | Match function signature |
|
||||
| `cannot find function` | Add missing function or fix import |
|
||||
| `unused variable` | Delete or use with `..` in patterns |
|
||||
| `unused import` | Delete the import line |
|
||||
| `cannot move out of X because borrowed` | Use scoping `{ }` to limit borrow |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Memory Management
|
||||
|
||||
When compilation fails due to memory issues (process "Killed"):
|
||||
|
||||
```bash
|
||||
pkill -9 cargo; pkill -9 rustc; pkill -9 botserver
|
||||
CARGO_BUILD_JOBS=1 cargo check -p botserver 2>&1 | tail -200
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📏 File Size Limits - MANDATORY
|
||||
|
||||
### Maximum 450 Lines Per File
|
||||
|
||||
When a file grows beyond this limit:
|
||||
|
||||
1. **Identify logical groups** - Find related functions
|
||||
2. **Create subdirectory module** - e.g., `handlers/`
|
||||
3. **Split by responsibility:**
|
||||
- `types.rs` - Structs, enums, type definitions
|
||||
- `handlers.rs` - HTTP handlers and routes
|
||||
- `operations.rs` - Core business logic
|
||||
- `utils.rs` - Helper functions
|
||||
- `mod.rs` - Re-exports and configuration
|
||||
4. **Keep files focused** - Single responsibility
|
||||
5. **Update mod.rs** - Re-export all public items
|
||||
|
||||
**NEVER let a single file exceed 450 lines - split proactively at 350 lines**
|
||||
|
||||
### Current Files Requiring Immediate Refactoring
|
||||
|
||||
| File | Lines | Target Split |
|
||||
|------|-------|--------------|
|
||||
| `botserver/src/drive/mod.rs` | 1522 | → 4 files |
|
||||
| `botserver/src/auto_task/app_generator.rs` | 2981 | → 7 files |
|
||||
| `botui/ui/suite/sheet/sheet.js` | 3220 | → 8 files |
|
||||
| `botserver/src/tasks/mod.rs` | 2651 | → 6 files |
|
||||
| `botserver/src/learn/mod.rs` | 2306 | → 5 files |
|
||||
|
||||
See `TODO-refactor1.md` for detailed refactoring plans.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Continuous Monitoring
|
||||
|
||||
**YOLO Forever Monitoring Pattern:**
|
||||
|
||||
The system includes automated log monitoring to catch errors in real-time:
|
||||
|
||||
```bash
|
||||
# Continuous monitoring (check every 5 seconds)
|
||||
while true; do
|
||||
sleep 5
|
||||
echo "=== Check at $(date +%H:%M:%S) ==="
|
||||
tail -50 botserver.log | grep -E "ERROR|WARN|CLIENT:" | tail -5 || echo "✓ Clean"
|
||||
done
|
||||
```
|
||||
|
||||
**Quick Status Check:**
|
||||
```bash
|
||||
# Check last 200 lines for any issues
|
||||
tail -200 botserver.log | grep -E "ERROR|WARN|CLIENT:" | tail -10
|
||||
|
||||
# Show recent server activity
|
||||
tail -30 botserver.log
|
||||
|
||||
# Check if server is running
|
||||
ps aux | grep botserver | grep -v grep
|
||||
```
|
||||
|
||||
**Monitoring Dashboard:**
|
||||
- **Server Status**: https://localhost:8088 (health endpoint)
|
||||
- **Logs**: `tail -f botserver.log`
|
||||
- **Client Errors**: Look for `CLIENT:` prefix
|
||||
- **Server Errors**: Look for `ERROR` or `WARN` prefixes
|
||||
|
||||
**Status Indicators:**
|
||||
- ✅ **Clean**: No ERROR/WARN/CLIENT: entries in logs
|
||||
- ⚠️ **Warnings**: Non-critical issues that should be reviewed
|
||||
- ❌ **Errors**: Critical issues requiring immediate attention
|
||||
|
||||
**When Errors Appear:**
|
||||
1. Capture the full error context (50 lines before/after)
|
||||
2. Identify the component (server, client, database, etc.)
|
||||
3. Check troubleshooting section for specific fixes
|
||||
4. Update this README with discovered issues and resolutions
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Performance & Size Standards
|
||||
|
||||
### Binary Size Optimization
|
||||
- **Release Profile**: Always maintain `opt-level = "z"`, `lto = true`, `codegen-units = 1`, `strip = true`, `panic = "abort"`.
|
||||
- **Dependencies**:
|
||||
- Run `cargo tree --duplicates` weekly to find and resolve duplicate versions.
|
||||
- Run `cargo machete` to remove unused dependencies.
|
||||
- Use `default-features = false` and explicitly opt-in to needed features.
|
||||
|
||||
### Memory Optimization
|
||||
- **Strings**: Prefer `&str` over `String` where possible. Use `Cow<str>` for conditional ownership.
|
||||
- **Collections**: Use `Vec::with_capacity` when size is known. Consider `SmallVec` for hot paths.
|
||||
- **Allocations**: Minimize heap allocations in hot paths.
|
||||
- **Cloning**: Avoid unnecessary `.clone()` calls. Use references or `Cow` types.
|
||||
|
||||
### Code Quality Issues Found
|
||||
- **955 instances** of `unwrap()`/`expect()` in codebase - ALL must be replaced with proper error handling
|
||||
- **12,973 instances** of excessive `clone()`/`to_string()` calls - optimize for performance
|
||||
- **Test code exceptions**: `unwrap()` allowed in test files only
|
||||
|
||||
### Linting & Code Quality
|
||||
- **Clippy**: Code MUST pass `cargo clippy --all-targets --all-features` with **0 warnings**.
|
||||
- **No Allow**: Do not use `#[allow(clippy::...)]` unless absolutely necessary and documented. Fix the underlying issue.
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Directives - MANDATORY
|
||||
|
||||
### Error Handling - NO PANICS IN PRODUCTION
|
||||
|
||||
```rust
|
||||
// ❌ FORBIDDEN
|
||||
value.unwrap()
|
||||
value.expect("message")
|
||||
panic!("error")
|
||||
todo!()
|
||||
unimplemented!()
|
||||
|
||||
// ✅ REQUIRED
|
||||
value?
|
||||
value.ok_or_else(|| Error::NotFound)?
|
||||
value.unwrap_or_default()
|
||||
value.unwrap_or_else(|e| { log::error!("{}", e); default })
|
||||
if let Some(v) = value { ... }
|
||||
match value { Ok(v) => v, Err(e) => return Err(e.into()) }
|
||||
```
|
||||
|
||||
### Command Execution - USE SafeCommand
|
||||
|
||||
```rust
|
||||
// ❌ FORBIDDEN
|
||||
Command::new("some_command").arg(user_input).output()
|
||||
|
||||
// ✅ REQUIRED
|
||||
use crate::security::command_guard::SafeCommand;
|
||||
SafeCommand::new("allowed_command")?
|
||||
.arg("safe_arg")?
|
||||
.execute()
|
||||
```
|
||||
|
||||
### Error Responses - USE ErrorSanitizer
|
||||
|
||||
```rust
|
||||
// ❌ FORBIDDEN
|
||||
Json(json!({ "error": e.to_string() }))
|
||||
format!("Database error: {}", e)
|
||||
|
||||
// ✅ REQUIRED
|
||||
use crate::security::error_sanitizer::log_and_sanitize;
|
||||
let sanitized = log_and_sanitize(&e, "context", None);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, sanitized)
|
||||
```
|
||||
|
||||
### SQL - USE sql_guard
|
||||
|
||||
```rust
|
||||
// ❌ FORBIDDEN
|
||||
format!("SELECT * FROM {}", user_table)
|
||||
|
||||
// ✅ REQUIRED
|
||||
use crate::security::sql_guard::{sanitize_identifier, validate_table_name};
|
||||
let safe_table = sanitize_identifier(&user_table);
|
||||
validate_table_name(&safe_table)?;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❌ Absolute Prohibitions
|
||||
|
||||
```
|
||||
❌ NEVER use .unwrap() or .expect() in production code (tests OK)
|
||||
❌ NEVER use panic!(), todo!(), unimplemented!()
|
||||
❌ NEVER use Command::new() directly - use SafeCommand
|
||||
❌ NEVER return raw error strings to HTTP clients
|
||||
❌ NEVER use #[allow()] in source code - FIX the code instead
|
||||
❌ NEVER add lint exceptions to Cargo.toml - FIX the code instead
|
||||
❌ NEVER use _ prefix for unused variables - DELETE or USE them
|
||||
❌ NEVER leave unused imports or dead code
|
||||
❌ NEVER add comments - code must be self-documenting
|
||||
❌ NEVER modify Cargo.toml lints section!
|
||||
❌ NEVER use CDN links - all assets must be local
|
||||
❌ NEVER use cargo clean - causes 30min rebuilds, use ./reset.sh for database issues
|
||||
❌ NEVER create .md documentation files without checking botbook/ first - documentation belongs there
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Mandatory Code Patterns
|
||||
|
||||
### Use Self in Impl Blocks
|
||||
```rust
|
||||
impl MyStruct {
|
||||
fn new() -> Self { Self { } } // ✅ Not MyStruct
|
||||
}
|
||||
```
|
||||
|
||||
### Derive Eq with PartialEq
|
||||
```rust
|
||||
#[derive(PartialEq, Eq)] // ✅ Always both
|
||||
struct MyStruct { }
|
||||
```
|
||||
|
||||
### Inline Format Args
|
||||
```rust
|
||||
format!("Hello {name}") // ✅ Not format!("{}", name)
|
||||
```
|
||||
|
||||
### Combine Match Arms
|
||||
```rust
|
||||
match x {
|
||||
A | B => do_thing(), // ✅ Combine identical arms
|
||||
C => other(),
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ UI Architecture (botui + botserver)
|
||||
|
||||
|
|
@ -900,13 +523,13 @@ match x {
|
|||
| Server | Port | Purpose |
|
||||
|--------|------|---------|
|
||||
| **botui** | 3000 | Serves UI files + proxies API to botserver |
|
||||
| **botserver** | 8088 | Backend API + embedded UI fallback |
|
||||
| **botserver** | 9000 | Backend API + embedded UI fallback |
|
||||
|
||||
### How It Works
|
||||
|
||||
```
|
||||
Browser → localhost:3000 → botui (serves HTML/CSS/JS)
|
||||
→ /api/* proxied to botserver:8088
|
||||
→ /api/* proxied to botserver:9000
|
||||
→ /suite/* served from botui/ui/suite/
|
||||
```
|
||||
|
||||
|
|
@ -1029,50 +652,50 @@ cargo audit
|
|||
- `ADDITIONAL-SUGGESTIONS.md` - Enhancement ideas
|
||||
- `TODO-*.md` - Task tracking files
|
||||
|
||||
Subprojects (botapp, botserver, etc.) are **not** git submodules - they are independent repositories.
|
||||
Subprojects (botapp, botserver, botui, etc.) are **independent repositories referenced as git submodules**.
|
||||
|
||||
### ⚠️ CRITICAL: Submodule Push Workflow
|
||||
|
||||
When making changes to any submodule (botserver, botui, botlib, etc.):
|
||||
|
||||
1. **Commit and push changes within the submodule directory:**
|
||||
```bash
|
||||
cd botserver
|
||||
git add .
|
||||
git commit -m "Your changes"
|
||||
git push pragmatismo main
|
||||
git push github main
|
||||
```
|
||||
|
||||
2. **Update the global gb repository submodule reference:**
|
||||
```bash
|
||||
cd .. # Back to gb root
|
||||
git add botserver
|
||||
git commit -m "Update botserver submodule to latest commit"
|
||||
git push pragmatismo main
|
||||
git push github main
|
||||
```
|
||||
|
||||
**Failure to push the global gb repository will cause submodule changes to not trigger CI/CD pipelines.**
|
||||
|
||||
Both repositories must be pushed for changes to take effect in production.
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. Read this README.md (workspace-level rules)
|
||||
2. **BEFORE creating any .md file, search botbook/ for existing documentation**
|
||||
3. Read `<project>/README.md` (project-specific rules)
|
||||
4. Use diagnostics tool to check warnings
|
||||
5. Fix all warnings with full file rewrites
|
||||
6. Verify with diagnostics after each file
|
||||
7. Never suppress warnings with `#[allow()]`
|
||||
1. Read this README.md (workspace structure)
|
||||
2. Read **[AGENTS.md](./AGENTS.md)** (coding rules & workflows)
|
||||
3. **BEFORE creating any .md file, search botbook/ for existing documentation**
|
||||
4. Read `<project>/README.md` (project-specific rules)
|
||||
5. Use diagnostics tool to check warnings
|
||||
6. Fix all warnings with full file rewrites
|
||||
7. Verify with diagnostics after each file
|
||||
8. Never suppress warnings with `#[allow()]`
|
||||
|
||||
---
|
||||
|
||||
## Main Directive
|
||||
|
||||
**LOOP AND COMPACT UNTIL 0 WARNINGS - MAXIMUM PRECISION**
|
||||
|
||||
- 0 warnings
|
||||
- 0 errors
|
||||
- Trust project diagnostics
|
||||
- Respect all rules
|
||||
- No `#[allow()]` in source code
|
||||
- Real code fixes only
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Remember
|
||||
|
||||
- **OFFLINE FIRST** - Fix all errors from list before compiling
|
||||
- **ZERO WARNINGS, ZERO ERRORS** - The only acceptable state
|
||||
- **FIX, DON'T SUPPRESS** - No #[allow()], no Cargo.toml lint exceptions
|
||||
- **SECURITY FIRST** - No unwrap, no raw errors, no direct commands
|
||||
- **READ BEFORE FIX** - Always understand context first
|
||||
- **BATCH BY FILE** - Fix ALL errors in a file at once
|
||||
- **WRITE ONCE** - Single edit per file with all fixes
|
||||
- **VERIFY LAST** - Only compile/diagnostics after ALL fixes
|
||||
- **DELETE DEAD CODE** - Don't keep unused code around
|
||||
- **Version 6.2.0** - Do not change without approval
|
||||
- **GIT WORKFLOW** - ALWAYS push to ALL repositories (github, pragmatismo)
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
2
botapp
2
botapp
|
|
@ -1 +1 @@
|
|||
Subproject commit b5ee6e061acf1388aef777ddcd9a2bf84bd6ed57
|
||||
Subproject commit 0b556948f970832e8606f886853793e2bc8dc35c
|
||||
2
botbook
2
botbook
|
|
@ -1 +1 @@
|
|||
Subproject commit 85696bb9070738f6bb865202f8c7de733f7c731a
|
||||
Subproject commit 82a236f369e58fe0eda4df704b9ee74a725874e8
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 97778e06dd804be55ff761c7fe2788af0ef50626
|
||||
Subproject commit 35411f4f9e64e54b1039360ab654d537cd2958c9
|
||||
2
botlib
2
botlib
|
|
@ -1 +1 @@
|
|||
Subproject commit 2765fa2ebadc91435e8d90f068b4c96dbb77329b
|
||||
Subproject commit e7caed45a44ab319c64d90f84281dbdbcba905b7
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 22a1954fac2f87a0a13b5e599771273172afc73a
|
||||
Subproject commit 4518bf7bd1c4ae6fafd5c42fa5f4515a383b480a
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 17a3caebabddbe843c2b7fd93f624b0ccd9c44fb
|
||||
Subproject commit 1727e48307fdb7b54c726af8cd6b12669764e908
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 30345c66e2738ebe73d896841e54f655999e3630
|
||||
Subproject commit 2ff68e5a2a24b7b63386efd2e2325d478efbb925
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit dd3d8c74dd58a1cc6d6b18d22108819519aaf9c3
|
||||
Subproject commit 3110dd587290047f283300d674ad325f4f9b3046
|
||||
2
bottest
2
bottest
|
|
@ -1 +1 @@
|
|||
Subproject commit 74e761de0dd5105885acf00183223a702a8436df
|
||||
Subproject commit 346120cb0b916f72abd2fdad577ae1c606aba1a2
|
||||
2
botui
2
botui
|
|
@ -1 +1 @@
|
|||
Subproject commit 414d277ae1757834d2ddbd6225063b451e919788
|
||||
Subproject commit ed4d492e6e7863923491a846a3614de6a6c37946
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"base_url": "http://localhost:8300",
|
||||
"default_org": {
|
||||
"id": "358572039839154190",
|
||||
"name": "default",
|
||||
"domain": "default.localhost"
|
||||
},
|
||||
"default_user": {
|
||||
"id": "admin",
|
||||
"username": "admin",
|
||||
"email": "admin@localhost",
|
||||
"password": "",
|
||||
"first_name": "Admin",
|
||||
"last_name": "User"
|
||||
},
|
||||
"admin_token": "eW0mGnOlKjpYHsrZZNAh1o3_8qeyF1iKKgEj-Y63GBdjQbQmxKxEjsNmVLZ_DWRDK6I3_yI",
|
||||
"project_id": "",
|
||||
"client_id": "358572040510308366",
|
||||
"client_secret": "WyZRbj5iMkOkbvvtJWivXVaaydhWX1TodavhnAhsivl8IDZ44v2QoqT5upfgmOfz"
|
||||
}
|
||||
771
crates.tmp
Normal file
771
crates.tmp
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
# BotServer Microservices Partition Plan
|
||||
|
||||
## 🎯 Objective
|
||||
|
||||
Partition the monolithic `botserver` into multiple microservices as separate Rust crates that share state, making the system easier to compile, maintain, and scale.
|
||||
|
||||
## 📊 Current State Analysis
|
||||
|
||||
### Current Structure
|
||||
- **Single monolithic crate**: `botserver` (242 dependencies in Cargo.toml)
|
||||
- **Feature flags**: 50+ features (chat, mail, tasks, drive, llm, etc.)
|
||||
- **Main entry point**: `botserver/src/main.rs` (436 lines)
|
||||
- **Shared state**: `AppState` in `core::shared::state`
|
||||
- **Modules**: 40+ top-level modules
|
||||
|
||||
### Problems with Current Approach
|
||||
1. **Long compile times**: Full rebuilds take 30+ minutes
|
||||
2. **Memory intensive**: Requires significant RAM during compilation
|
||||
3. **Tight coupling**: All modules compiled together
|
||||
4. **Hard to scale**: Can't deploy individual services independently
|
||||
5. **Feature flag complexity**: Many features, hard to test all combinations
|
||||
|
||||
## 🏗️ Proposed Architecture
|
||||
|
||||
### Shared State Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ SHARED STATE LAYER │
|
||||
│ ┌─────────────────────────────────────────────────────────┐│
|
||||
│ │ botstate (NEW) - Shared state types & interfaces ││
|
||||
│ │ - AppState definition ││
|
||||
│ │ - Database connection pool ││
|
||||
│ │ - Redis/Valkey client ││
|
||||
│ │ - Configuration ││
|
||||
│ │ - LLM provider interface ││
|
||||
│ │ - Secret manager interface ││
|
||||
│ └─────────────────────────────────────────────────────────┘│
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Microservice Crates
|
||||
|
||||
```
|
||||
Workspace Members:
|
||||
├── botlib/ # Existing - Core types, errors, utilities
|
||||
├── botstate/ # NEW - Shared state layer
|
||||
├── botserver-core/ # NEW - Core HTTP server, routing, middleware
|
||||
├── botserver-auth/ # NEW - Authentication & authorization
|
||||
├── botserver-chat/ # NEW - WebSocket chat, LLM integration
|
||||
├── botserver-mail/ # NEW - Email integration (IMAP/SMTP)
|
||||
├── botserver-tasks/ # NEW - Task scheduler, cron jobs
|
||||
├── botserver-drive/ # NEW - File storage (S3/MinIO)
|
||||
├── botserver-llm/ # NEW - LLM providers, embeddings
|
||||
├── botserver-vectordb/ # NEW - Qdrant vector database
|
||||
├── botserver-compliance/# NEW - Legal, audit, compliance
|
||||
├── botserver-video/ # NEW - Video processing, LiveKit
|
||||
├── botserver-contacts/ # NEW - CRM, contacts, calendar
|
||||
├── botserver-auto/ # NEW - Automation, Rhai scripting
|
||||
├── botserver-ui/ # NEW - Embedded UI, TUI (optional)
|
||||
└── botserver/ # EXISTING - Becomes meta-crate that re-exports all
|
||||
```
|
||||
|
||||
## 📦 Detailed Crate Responsibilities
|
||||
|
||||
### 1. **botstate** (NEW - Foundation)
|
||||
**Purpose**: Define shared state types that all services will use
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib` (workspace)
|
||||
- `tokio`, `redis`, `diesel`, `chrono`, `uuid`, `serde`
|
||||
|
||||
**Exports**:
|
||||
```rust
|
||||
pub struct AppState {
|
||||
pub db_pool: PgPool,
|
||||
pub redis_client: Arc<redis::Client>,
|
||||
pub config: Arc<Config>,
|
||||
pub llm_provider: Arc<dyn LLMProvider>,
|
||||
pub secret_manager: Arc<dyn SecretManager>,
|
||||
// ... other shared resources
|
||||
}
|
||||
|
||||
pub trait LLMProvider {
|
||||
async fn generate(&self, prompt: &str) -> Result<String>;
|
||||
}
|
||||
|
||||
pub trait SecretManager {
|
||||
fn get_secret(&self, key: &str) -> Result<String>;
|
||||
}
|
||||
```
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botstate/`
|
||||
|
||||
---
|
||||
|
||||
### 2. **botserver-core** (NEW - HTTP Foundation)
|
||||
**Purpose**: Core HTTP server, routing, middleware, health checks
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`
|
||||
- `axum`, `tower`, `tower-http`, `tokio`
|
||||
|
||||
**Responsibilities**:
|
||||
- HTTP server setup (Axum)
|
||||
- Middleware (CORS, logging, rate limiting)
|
||||
- Health check endpoints
|
||||
- Graceful shutdown
|
||||
- Static file serving
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-core/`
|
||||
|
||||
---
|
||||
|
||||
### 3. **botserver-auth** (NEW - Security)
|
||||
**Purpose**: Authentication, authorization, RBAC
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `jsonwebtoken`, `argon2`, `axum`
|
||||
|
||||
**Responsibilities**:
|
||||
- User authentication (login/logout)
|
||||
- JWT token management
|
||||
- RBAC (role-based access control)
|
||||
- Session management
|
||||
- OAuth integration
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-auth/`
|
||||
|
||||
---
|
||||
|
||||
### 4. **botserver-chat** (NEW - Real-time Communication)
|
||||
**Purpose**: WebSocket chat, message handling, LLM integration
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `tokio-tungstenite`, `axum`, `serde_json`
|
||||
|
||||
**Responsibilities**:
|
||||
- WebSocket connections
|
||||
- Message routing
|
||||
- Chat history
|
||||
- Suggestion buttons
|
||||
- Tool execution framework
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-chat/`
|
||||
|
||||
---
|
||||
|
||||
### 5. **botserver-mail** (NEW - Email)
|
||||
**Purpose**: Email integration (IMAP/SMTP)
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `lettre`, `imap`, `mailparse`
|
||||
|
||||
**Responsibilities**:
|
||||
- IMAP email retrieval
|
||||
- SMTP email sending
|
||||
- Email parsing
|
||||
- Attachments
|
||||
- Email templates
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-mail/`
|
||||
|
||||
---
|
||||
|
||||
### 6. **botserver-tasks** (NEW - Scheduling)
|
||||
**Purpose**: Task scheduler, cron jobs
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `cron`, `tokio`
|
||||
|
||||
**Responsibilities**:
|
||||
- Cron job scheduler
|
||||
- Task queue management
|
||||
- Recurring tasks
|
||||
- Task execution tracking
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-tasks/`
|
||||
|
||||
---
|
||||
|
||||
### 7. **botserver-drive** (NEW - Storage)
|
||||
**Purpose**: File storage (S3/MinIO)
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `aws-sdk-s3`, `aws-config`
|
||||
|
||||
**Responsibilities**:
|
||||
- S3/MinIO client
|
||||
- File upload/download
|
||||
- File synchronization
|
||||
- PDF extraction
|
||||
- Document processing
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-drive/`
|
||||
|
||||
---
|
||||
|
||||
### 8. **botserver-llm** (NEW - Language Models)
|
||||
**Purpose**: LLM providers, embeddings, caching
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`
|
||||
- `reqwest`, `serde_json`
|
||||
|
||||
**Responsibilities**:
|
||||
- LLM provider abstraction (Groq, OpenAI, etc.)
|
||||
- Embedding generation
|
||||
- Response caching
|
||||
- Local LLM management (llama.cpp)
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-llm/`
|
||||
|
||||
---
|
||||
|
||||
### 9. **botserver-vectordb** (NEW - Vector Database)
|
||||
**Purpose**: Qdrant vector database operations
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-llm`
|
||||
- `qdrant-client`
|
||||
|
||||
**Responsibilities**:
|
||||
- Vector embeddings storage
|
||||
- Similarity search
|
||||
- Knowledge base chunks
|
||||
- RAG (retrieval-augmented generation)
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-vectordb/`
|
||||
|
||||
---
|
||||
|
||||
### 10. **botserver-auto** (NEW - Automation)
|
||||
**Purpose**: Automation, Rhai scripting engine
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `rhai`, `tokio`
|
||||
|
||||
**Responsibilities**:
|
||||
- Rhai script engine
|
||||
- BASIC keyword execution
|
||||
- Workflow automation
|
||||
- Event handlers
|
||||
- Script compilation
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-auto/`
|
||||
|
||||
---
|
||||
|
||||
### 11. **botserver-contacts** (NEW - CRM)
|
||||
**Purpose**: Contacts, CRM, calendar integration
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `icalendar`, `chrono`
|
||||
|
||||
**Responsibilities**:
|
||||
- Contact management
|
||||
- CRM operations
|
||||
- Calendar integration
|
||||
- Google/Microsoft sync
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-contacts/`
|
||||
|
||||
---
|
||||
|
||||
### 12. **botserver-compliance** (NEW - Legal)
|
||||
**Purpose**: Legal, audit, compliance
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `csv`
|
||||
|
||||
**Responsibilities**:
|
||||
- Audit logging
|
||||
- Compliance reports
|
||||
- Legal document management
|
||||
- Data retention policies
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-compliance/`
|
||||
|
||||
---
|
||||
|
||||
### 13. **botserver-video** (NEW - Video)
|
||||
**Purpose**: Video processing, LiveKit integration
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`, `botserver-core`
|
||||
- `livekit`
|
||||
|
||||
**Responsibilities**:
|
||||
- LiveKit integration
|
||||
- Video analytics
|
||||
- Meeting management
|
||||
- Media processing
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-video/`
|
||||
|
||||
---
|
||||
|
||||
### 14. **botserver-ui** (OPTIONAL - TUI)
|
||||
**Purpose**: Console/TUI interface
|
||||
|
||||
**Dependencies**:
|
||||
- `botlib`, `botstate`
|
||||
- `ratatui`, `crossterm`
|
||||
|
||||
**Responsibilities**:
|
||||
- Terminal UI
|
||||
- Progress monitoring
|
||||
- Service status dashboard
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver-ui/`
|
||||
|
||||
---
|
||||
|
||||
### 15. **botserver** (EXISTING - Meta-crate)
|
||||
**Purpose**: Re-exports all services, maintains backward compatibility
|
||||
|
||||
**Dependencies**:
|
||||
- All botserver-* crates
|
||||
- Feature flags to enable/disable services
|
||||
|
||||
**Responsibilities**:
|
||||
- Re-export all services
|
||||
- Main binary entry point
|
||||
- Feature flag coordination
|
||||
|
||||
**Location**: `/home/rodriguez/src/gb/botserver/` (existing, modified)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 State Sharing Strategy
|
||||
|
||||
### Approach: Shared AppState via botstate Crate
|
||||
|
||||
```rust
|
||||
// botstate/src/lib.rs
|
||||
use redis::Client as RedisClient;
|
||||
use diesel::r2d2::Pool as DbPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct AppState {
|
||||
pub db_pool: Arc<DbPool>,
|
||||
pub redis_client: Arc<RedisClient>,
|
||||
pub config: Arc<Config>,
|
||||
pub llm_provider: Arc<dyn LLMProvider + Send + Sync>,
|
||||
pub secret_manager: Arc<dyn SecretManager + Send + Sync>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(
|
||||
db_pool: DbPool,
|
||||
redis_client: RedisClient,
|
||||
config: Config,
|
||||
llm_provider: Box<dyn LLMProvider + Send + Sync>,
|
||||
secret_manager: Box<dyn SecretManager + Send + Sync>,
|
||||
) -> Self {
|
||||
Self {
|
||||
db_pool: Arc::new(db_pool),
|
||||
redis_client: Arc::new(redis_client),
|
||||
config: Arc::new(config),
|
||||
llm_provider: Arc::from(llm_provider),
|
||||
secret_manager: Arc::from(secret_manager),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Each Service Gets AppState as Parameter
|
||||
|
||||
```rust
|
||||
// botserver-chat/src/lib.rs
|
||||
use botstate::AppState;
|
||||
use axum::Router;
|
||||
|
||||
pub fn create_router(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
.route("/ws", websocket_handler)
|
||||
.with_state(state)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Migration Steps
|
||||
|
||||
### Phase 1: Foundation (Week 1-2)
|
||||
1. ✅ Create `botstate` crate
|
||||
- Extract `AppState` from `botserver`
|
||||
- Define trait interfaces (LLMProvider, SecretManager)
|
||||
- Export shared types
|
||||
|
||||
2. ✅ Create `botserver-core` crate
|
||||
- Extract HTTP server setup
|
||||
- Extract middleware
|
||||
- Extract health checks
|
||||
|
||||
3. ✅ Update workspace `Cargo.toml`
|
||||
- Add new members
|
||||
- Configure dependencies
|
||||
|
||||
### Phase 2: Extract Services (Week 3-6)
|
||||
4. ✅ Extract `botserver-auth`
|
||||
- Move authentication code
|
||||
- Update imports
|
||||
|
||||
5. ✅ Extract `botserver-chat`
|
||||
- Move WebSocket code
|
||||
- Move message handling
|
||||
|
||||
6. ✅ Extract `botserver-mail`
|
||||
- Move email integration
|
||||
- Move IMAP/SMTP code
|
||||
|
||||
7. ✅ Extract `botserver-drive`
|
||||
- Move S3/MinIO code
|
||||
- Move file sync
|
||||
|
||||
8. ✅ Extract `botserver-auto`
|
||||
- Move Rhai engine
|
||||
- Move BASIC keywords
|
||||
|
||||
### Phase 3: Advanced Services (Week 7-10)
|
||||
9. ✅ Extract `botserver-llm`
|
||||
- Move LLM providers
|
||||
- Move caching
|
||||
|
||||
10. ✅ Extract `botserver-vectordb`
|
||||
- Move Qdrant client
|
||||
- Move embeddings
|
||||
|
||||
11. ✅ Extract `botserver-tasks`
|
||||
- Move scheduler
|
||||
- Move cron jobs
|
||||
|
||||
12. ✅ Extract `botserver-contacts`
|
||||
- Move CRM code
|
||||
- Move calendar sync
|
||||
|
||||
13. ✅ Extract `botserver-compliance`
|
||||
- Move audit logging
|
||||
- Move compliance reports
|
||||
|
||||
14. ✅ Extract `botserver-video`
|
||||
- Move LiveKit integration
|
||||
- Move video analytics
|
||||
|
||||
### Phase 4: Integration & Testing (Week 11-12)
|
||||
15. ✅ Update `botserver` as meta-crate
|
||||
- Re-export all services
|
||||
- Maintain backward compatibility
|
||||
- Feature flags coordination
|
||||
|
||||
16. ✅ Test all services independently
|
||||
- Unit tests
|
||||
- Integration tests
|
||||
- End-to-end tests
|
||||
|
||||
17. ✅ Documentation
|
||||
- Update README
|
||||
- Document APIs
|
||||
- Update AGENTS.md
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Benefits
|
||||
|
||||
### Compile Time Improvements
|
||||
- **Before**: Full rebuild 30+ minutes
|
||||
- **After**:
|
||||
- botstate: ~30 seconds
|
||||
- Individual service: 1-3 minutes
|
||||
- Full workspace: Still 30+ minutes (but cached builds work better)
|
||||
|
||||
### Memory Usage
|
||||
- **Before**: 16GB+ RAM required
|
||||
- **After**: 2-4GB per service
|
||||
|
||||
### Development Workflow
|
||||
- Work on single service without rebuilding everything
|
||||
- Better separation of concerns
|
||||
- Easier to test individual components
|
||||
- Can deploy services independently
|
||||
|
||||
### Scalability
|
||||
- Deploy only needed services
|
||||
- Scale services independently
|
||||
- Different services can use different versions of dependencies
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Challenges & Solutions
|
||||
|
||||
### Challenge 1: Circular Dependencies
|
||||
**Problem**: Services reference each other
|
||||
|
||||
**Solution**:
|
||||
- Use traits in `botstate` for cross-service communication
|
||||
- Dependency injection via `AppState`
|
||||
- Event-driven architecture for loose coupling
|
||||
|
||||
### Challenge 2: Database Migrations
|
||||
**Problem**: Multiple crates need to coordinate migrations
|
||||
|
||||
**Solution**:
|
||||
- Keep all migrations in `botserver` (meta-crate)
|
||||
- Use `diesel_migrations` with centralized migration directory
|
||||
- Each service documents its required migrations
|
||||
|
||||
### Challenge 3: Shared Configuration
|
||||
**Problem**: All services need config values
|
||||
|
||||
**Solution**:
|
||||
- `Config` struct in `botstate`
|
||||
- Loaded once, shared via `Arc<Config>`
|
||||
- Each service reads only what it needs
|
||||
|
||||
### Challenge 4: Feature Flags
|
||||
**Problem**: Complex feature flag interactions
|
||||
|
||||
**Solution**:
|
||||
- Each service has its own feature flags
|
||||
- `botserver` meta-crate coordinates via feature aliases
|
||||
- Default: all services enabled
|
||||
- Can build minimal subset for testing
|
||||
|
||||
---
|
||||
|
||||
## 📊 Dependency Graph
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
botlib[botlib - Core types]
|
||||
botstate[botstate - Shared state]
|
||||
botcore[botserver-core - HTTP server]
|
||||
|
||||
auth[botserver-auth]
|
||||
chat[botserver-chat]
|
||||
mail[botserver-mail]
|
||||
tasks[botserver-tasks]
|
||||
drive[botserver-drive]
|
||||
llm[botserver-llm]
|
||||
vectordb[botserver-vectordb]
|
||||
auto[botserver-auto]
|
||||
contacts[botserver-contacts]
|
||||
compliance[botserver-compliance]
|
||||
video[botserver-video]
|
||||
ui[botserver-ui]
|
||||
|
||||
botserver[botserver - Meta-crate]
|
||||
|
||||
botlib --> botstate
|
||||
botstate --> botcore
|
||||
botcore --> auth
|
||||
botcore --> chat
|
||||
botcore --> mail
|
||||
botcore --> tasks
|
||||
botcore --> drive
|
||||
botcore --> auto
|
||||
botcore --> contacts
|
||||
botcore --> compliance
|
||||
botcore --> video
|
||||
|
||||
llm --> botstate
|
||||
vectordb --> botstate
|
||||
vectordb --> llm
|
||||
|
||||
auth --> botstate
|
||||
chat --> botstate
|
||||
chat --> llm
|
||||
mail --> botstate
|
||||
tasks --> botstate
|
||||
drive --> botstate
|
||||
auto --> botstate
|
||||
contacts --> botstate
|
||||
compliance --> botstate
|
||||
video --> botstate
|
||||
|
||||
botserver --> botcore
|
||||
botserver --> auth
|
||||
botserver --> chat
|
||||
botserver --> mail
|
||||
botserver --> tasks
|
||||
botserver --> drive
|
||||
botserver --> llm
|
||||
botserver --> vectordb
|
||||
botserver --> auto
|
||||
botserver --> contacts
|
||||
botserver --> compliance
|
||||
botserver --> video
|
||||
botserver --> ui
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 File Structure After Migration
|
||||
|
||||
```
|
||||
gb/
|
||||
├── Cargo.toml (workspace)
|
||||
├── botlib/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
├── botstate/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── state.rs
|
||||
│ ├── traits.rs
|
||||
│ └── config.rs
|
||||
├── botserver-core/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── server.rs
|
||||
│ ├── middleware.rs
|
||||
│ └── health.rs
|
||||
├── botserver-auth/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── jwt.rs
|
||||
│ ├── rbac.rs
|
||||
│ └── session.rs
|
||||
├── botserver-chat/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── websocket.rs
|
||||
│ └── messages.rs
|
||||
├── botserver-mail/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── imap.rs
|
||||
│ └── smtp.rs
|
||||
├── botserver-tasks/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── scheduler.rs
|
||||
│ └── cron.rs
|
||||
├── botserver-drive/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── s3.rs
|
||||
│ └── sync.rs
|
||||
├── botserver-llm/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── provider.rs
|
||||
│ └── cache.rs
|
||||
├── botserver-vectordb/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ └── qdrant.rs
|
||||
├── botserver-auto/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── rhai_engine.rs
|
||||
│ └── keywords.rs
|
||||
├── botserver-contacts/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ └── crm.rs
|
||||
├── botserver-compliance/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ └── audit.rs
|
||||
├── botserver-video/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ └── livekit.rs
|
||||
├── botserver-ui/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│ ├── lib.rs
|
||||
│ └── tui.rs
|
||||
└── botserver/ (meta-crate)
|
||||
├── Cargo.toml
|
||||
└── src/
|
||||
├── main.rs
|
||||
└── lib.rs (re-exports)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### Step 1: Create botstate Crate
|
||||
```bash
|
||||
cd /home/rodriguez/src/gb
|
||||
mkdir -p botstate/src
|
||||
cat > botstate/Cargo.toml << 'EOF'
|
||||
[package]
|
||||
name = "botstate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
botlib = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
redis = { workspace = true, features = ["tokio-comp"] }
|
||||
diesel = { workspace = true, features = ["postgres", "r2d2"] }
|
||||
chrono = { workspace = true }
|
||||
uuid = { workspace = true, features = ["v4"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
async-trait = { workspace = true }
|
||||
EOF
|
||||
```
|
||||
|
||||
### Step 2: Update Workspace
|
||||
Edit `/home/rodriguez/src/gb/Cargo.toml`:
|
||||
```toml
|
||||
members = [
|
||||
"botapp",
|
||||
"botdevice",
|
||||
"botlib",
|
||||
"botserver",
|
||||
"bottest",
|
||||
"botui",
|
||||
"botstate", # NEW
|
||||
"botserver-core", # NEW
|
||||
"botserver-auth", # NEW
|
||||
"botserver-chat", # NEW
|
||||
# ... etc
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Success Criteria
|
||||
|
||||
1. ✅ **botstate** compiles independently
|
||||
2. ✅ **botserver-core** starts HTTP server without other services
|
||||
3. ✅ Each service can be built independently
|
||||
4. ✅ No circular dependencies between crates
|
||||
5. ✅ All tests pass
|
||||
6. ✅ Compile time reduced by 70% for individual services
|
||||
7. ✅ Memory usage during compilation reduced by 60%
|
||||
8. ✅ Backward compatibility maintained (existing code still works)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes
|
||||
|
||||
- This plan prioritizes **incremental migration** - each step is reversible
|
||||
- Start with `botstate` and `botserver-core` as foundation
|
||||
- Test after each service extraction
|
||||
- Keep the meta-crate `botserver` for backward compatibility
|
||||
- Use feature flags to enable/disable services during transition
|
||||
|
||||
---
|
||||
|
||||
**Created**: 2026-04-18
|
||||
**Status**: Planning Phase
|
||||
**Next Step**: Create `botstate` crate with shared state types
|
||||
16
deploy.sh
Executable file
16
deploy.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
# Manual deploy script - run this on alm-ci container
|
||||
echo "1. Stop..."
|
||||
sudo incus exec system -- systemctl stop botserver || true
|
||||
sudo incus exec system -- pkill -x botserver || true
|
||||
sleep 1
|
||||
|
||||
echo "2. Copy..."
|
||||
sudo incus file push /opt/gbo/work/botserver/target/debug/botserver system:/opt/gbo/bin/botserver --mode=0755
|
||||
|
||||
echo "3. Start..."
|
||||
sudo incus exec system -- systemctl start botserver
|
||||
sleep 2
|
||||
|
||||
echo "4. Verify..."
|
||||
sudo incus exec system -- pgrep -x botserver && echo "✅ SUCCESS" || echo "❌ FAILED"
|
||||
12
package.json
12
package.json
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"name": "gb",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "Rodrigo Rodriguez (Pragmatismo) <me@rodrigorodriguez.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.58.1",
|
||||
"@types/node": "^25.2.0"
|
||||
},
|
||||
"scripts": {}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// import dotenv from 'dotenv';
|
||||
// import path from 'path';
|
||||
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: 'html',
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('')`. */
|
||||
// baseURL: 'http://localhost:3000',
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://localhost:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
});
|
||||
296
prompts/integratedsuite.md
Normal file
296
prompts/integratedsuite.md
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
# Integrated Suite — Conversational Interface Plan
|
||||
|
||||
> **Pattern:** Every suite app exposes its own `PROMPT.md` + internal tools.
|
||||
> The shared chat bar activates app-specific context when the user is inside that app.
|
||||
> WhatsApp campaigns is the first full example.
|
||||
a common chat window stay fixed right like pane colapsable, except for chat... all other ui must be controled by chat, via api/ pompt common mechanismo.
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
User (WhatsApp / Suite chat bar)
|
||||
↓
|
||||
BotOrchestrator (core/bot/mod.rs)
|
||||
↓
|
||||
detect active app context
|
||||
↓
|
||||
load app PROMPT.md + app InternalTools
|
||||
↓
|
||||
LLM with tools → tool_executor.rs
|
||||
↓
|
||||
app data / actions
|
||||
```
|
||||
|
||||
### Key existing pieces
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `core/bot/mod.rs` | `get_session_tools()` + `ToolExecutor::execute_tool_call()` |
|
||||
| `tasks/PROMPT.md` | Pattern for app-level LLM prompt |
|
||||
| `marketing/whatsapp.rs` | WhatsApp campaign send/metrics |
|
||||
| `marketing/campaigns.rs` | Campaign CRUD |
|
||||
| `marketing/lists.rs` | Recipient lists |
|
||||
| `botui/ui/suite/campaigns/` | Campaigns UI |
|
||||
|
||||
---
|
||||
|
||||
## Standard: Every Suite App
|
||||
|
||||
### 1. `PROMPT.md` per app folder
|
||||
Location: `botserver/src/<app>/PROMPT.md`
|
||||
|
||||
```markdown
|
||||
# <App> — Internal Tools Guide
|
||||
|
||||
You are the <App> assistant. When the user is in <App>, you have access to:
|
||||
- tool: list_<entities>
|
||||
- tool: create_<entity>
|
||||
- tool: search_<entity>
|
||||
- tool: <app_specific_action>
|
||||
|
||||
Rules:
|
||||
- Always confirm destructive actions before executing
|
||||
- Show results as structured summaries, not raw JSON
|
||||
- If user uploads a file, parse it and confirm before acting
|
||||
```
|
||||
|
||||
### 2. `tools.rs` per app
|
||||
Location: `botserver/src/<app>/tools.rs`
|
||||
|
||||
Registers `Vec<Tool>` (LLM function-calling schema) + handler mapping.
|
||||
Loaded by `get_session_tools()` when session's active app = this app.
|
||||
|
||||
### 3. App context detection
|
||||
`core/bot/mod.rs` reads `session.active_app` (set by UI via `POST /api/session/context`).
|
||||
Loads `<app>/PROMPT.md` as system prompt prefix + `<app>/tools.rs` tools.
|
||||
|
||||
---
|
||||
|
||||
## WhatsApp Campaigns — Full Conversational Flow
|
||||
|
||||
### Meta Rules (enforced in tools)
|
||||
- Only approved Message Templates for marketing (non-session-initiated)
|
||||
- 24h session window for free-form after user replies
|
||||
- Media: image/video/document via Media Upload API before send
|
||||
- Opt-out: always honor STOP, add to suppression list immediately
|
||||
- Rate: respect per-phone-number rate limits (1000 msg/s business tier)
|
||||
- Template category: MARKETING requires explicit opt-in from recipient
|
||||
|
||||
### Conversation Flow (WhatsApp → campaign creation)
|
||||
|
||||
```
|
||||
User sends to bot number:
|
||||
"I want to send a campaign"
|
||||
↓
|
||||
Bot: "Great! Send me:
|
||||
1. Your contact list (.xlsx or .csv)
|
||||
2. The message text
|
||||
3. An image (optional)
|
||||
4. When to send (or 'now')"
|
||||
↓
|
||||
User uploads contacts.xlsx
|
||||
↓
|
||||
[tool: parse_contact_file]
|
||||
→ extract phone numbers, names
|
||||
→ validate E.164 format
|
||||
→ show preview: "Found 342 contacts. First 3: +55..."
|
||||
↓
|
||||
User sends message text
|
||||
↓
|
||||
[tool: check_template_compliance]
|
||||
→ check if free-form or needs approved template
|
||||
→ if template needed: list available approved templates
|
||||
→ suggest closest match
|
||||
↓
|
||||
User sends image (optional)
|
||||
↓
|
||||
[tool: upload_media]
|
||||
→ upload to Meta Media API
|
||||
→ return media_id
|
||||
↓
|
||||
Bot: "Ready to send to 342 contacts at 14:00 today.
|
||||
Preview: [image] Hello {name}, ...
|
||||
Estimated cost: $X
|
||||
Confirm? (yes/no)"
|
||||
↓
|
||||
User: "yes"
|
||||
↓
|
||||
[tool: create_and_schedule_campaign]
|
||||
→ create campaign record
|
||||
→ apply warmup limit if IP warming
|
||||
→ schedule via TaskScheduler
|
||||
```
|
||||
|
||||
### WhatsApp Campaign Tools (`marketing/whatsapp_tools.rs`)
|
||||
|
||||
```rust
|
||||
// Tool definitions for LLM function calling
|
||||
pub fn whatsapp_campaign_tools() -> Vec<Tool> {
|
||||
vec![
|
||||
Tool::new("parse_contact_file", "Parse uploaded xlsx/csv into contact list"),
|
||||
Tool::new("list_templates", "List approved WhatsApp message templates"),
|
||||
Tool::new("check_template_compliance", "Check if message needs approved template"),
|
||||
Tool::new("upload_media", "Upload image/video to Meta Media API"),
|
||||
Tool::new("preview_campaign", "Show campaign preview with cost estimate"),
|
||||
Tool::new("create_and_schedule_campaign", "Create campaign and schedule send"),
|
||||
Tool::new("get_campaign_status", "Get delivery/read metrics for a campaign"),
|
||||
Tool::new("pause_campaign", "Pause an in-progress campaign"),
|
||||
Tool::new("list_campaigns", "List recent campaigns with metrics"),
|
||||
Tool::new("add_to_suppression", "Add number to opt-out list"),
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### WhatsApp PROMPT.md (`marketing/WHATSAPP_PROMPT.md`)
|
||||
|
||||
```markdown
|
||||
# WhatsApp Campaign Assistant
|
||||
|
||||
You help users create and manage WhatsApp marketing campaigns.
|
||||
|
||||
## Meta Platform Rules (MANDATORY)
|
||||
- Marketing messages MUST use pre-approved templates outside 24h session window
|
||||
- Always check opt-in status before adding to campaign
|
||||
- Honor STOP/unsubscribe immediately via add_to_suppression tool
|
||||
- Never send more than warmup daily limit if IP is warming up
|
||||
- Image must be uploaded via upload_media before referencing in campaign
|
||||
|
||||
## Conversation Style
|
||||
- Guide step by step: contacts → message → media → schedule → confirm
|
||||
- Show cost estimate before confirming
|
||||
- After send: proactively share open/read rates when available
|
||||
|
||||
## File Handling
|
||||
- .xlsx/.csv → use parse_contact_file tool
|
||||
- Images → use upload_media tool
|
||||
- Always confirm parsed data before proceeding
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integrated Suite Chat Bar — Standard
|
||||
|
||||
### How it works
|
||||
1. User opens any suite app (CRM, Campaigns, Drive, etc.)
|
||||
2. Chat bar at bottom activates with app context
|
||||
3. `POST /api/session/context { app: "campaigns" }` sets `session.active_app`
|
||||
4. BotOrchestrator loads `campaigns/PROMPT.md` + `campaigns/tools.rs`
|
||||
5. User can ask natural language questions or trigger actions
|
||||
|
||||
### Examples per app
|
||||
|
||||
| App | Example query | Tool activated |
|
||||
|---|---|---|
|
||||
| **Campaigns** | "How did last week's campaign perform?" | `get_campaign_metrics` |
|
||||
| **CRM** | "Show deals closing this month" | `list_deals` with filter |
|
||||
| **Drive** | "Find the Q1 report" | `search_files` |
|
||||
| **Tasks** | "Create a task to follow up with Acme" | `create_task` |
|
||||
| **People** | "Who hasn't been contacted in 30 days?" | `list_contacts` with filter |
|
||||
| **Mail** | "Summarize unread emails from clients" | `list_emails` + LLM summary |
|
||||
| **Sheet** | "What's the total revenue in column D?" | `query_sheet` |
|
||||
| **Learn** | "What does our refund policy say?" | `search_kb` |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1 — Infrastructure (1 sprint)
|
||||
- [ ] `core/bot/mod.rs` — read `session.active_app`, load app PROMPT + tools
|
||||
- [ ] `core/tool_context.rs` — app tool registry: `register_app_tools(app_name) -> Vec<Tool>`
|
||||
- [ ] `POST /api/session/context` — set active app from UI
|
||||
- [ ] Suite chat bar UI component (`botui/ui/suite/partials/chatbar.html`)
|
||||
|
||||
### Phase 2 — WhatsApp Campaigns (1 sprint)
|
||||
- [ ] `marketing/whatsapp_tools.rs` — 10 tools above
|
||||
- [ ] `marketing/WHATSAPP_PROMPT.md`
|
||||
- [ ] `marketing/file_parser.rs` — xlsx/csv → contact list
|
||||
- [ ] Meta warmup enforcement in send path
|
||||
- [ ] Conversational campaign creation flow (state machine in session)
|
||||
|
||||
### Phase 3 — App-by-app rollout (1 app/sprint)
|
||||
Priority order based on value:
|
||||
1. CRM (deals, contacts, pipeline queries)
|
||||
2. Campaigns (email + WhatsApp)
|
||||
3. Tasks (create, assign, status)
|
||||
4. Drive (search, summarize docs)
|
||||
5. Mail (summarize, draft reply)
|
||||
6. People (segment, find contacts)
|
||||
7. Sheet (query, calculate)
|
||||
8. Learn (KB search)
|
||||
|
||||
### Phase 4 — Cross-app intelligence
|
||||
- [ ] Global search across all apps via single query
|
||||
- [ ] "What happened today?" — aggregates activity across CRM + Mail + Tasks
|
||||
- [ ] Proactive suggestions: "You have 3 deals closing this week and no follow-up tasks"
|
||||
|
||||
---
|
||||
|
||||
## File Structure to Create
|
||||
|
||||
```
|
||||
botserver/src/
|
||||
├── marketing/
|
||||
│ ├── whatsapp_tools.rs ← NEW: LLM tool definitions + handlers
|
||||
│ ├── WHATSAPP_PROMPT.md ← NEW: WhatsApp assistant system prompt
|
||||
│ ├── file_parser.rs ← NEW: xlsx/csv → contacts
|
||||
│ └── warmup.rs ← NEW: (from campaigns.md plan)
|
||||
├── core/
|
||||
│ ├── tool_registry.rs ← NEW: app → tools mapping
|
||||
│ └── bot/
|
||||
│ └── app_context.rs ← NEW: load app prompt + tools per session
|
||||
├── crm/
|
||||
│ ├── tools.rs ← NEW
|
||||
│ └── PROMPT.md ← NEW
|
||||
├── tasks/
|
||||
│ └── tools.rs ← NEW (PROMPT.md exists)
|
||||
└── <each app>/
|
||||
├── tools.rs ← NEW per app
|
||||
└── PROMPT.md ← NEW per app
|
||||
|
||||
botui/ui/suite/
|
||||
└── partials/
|
||||
└── chatbar.html ← NEW: shared chat bar component
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chat Bar UI (`partials/chatbar.html`)
|
||||
|
||||
```html
|
||||
<div id="suite-chatbar" class="chatbar">
|
||||
<div id="chatbar-messages" hx-ext="ws" ws-connect="/ws/suite-chat"></div>
|
||||
<form ws-send>
|
||||
<input type="hidden" name="app_context" value="{{ active_app }}">
|
||||
<input type="file" id="chatbar-file" name="file" accept=".xlsx,.csv,.png,.jpg,.pdf" style="display:none">
|
||||
<button type="button" onclick="document.getElementById('chatbar-file').click()">📎</button>
|
||||
<input type="text" name="message" placeholder="Ask anything about {{ active_app }}...">
|
||||
<button type="submit">→</button>
|
||||
</form>
|
||||
</div>
|
||||
```
|
||||
|
||||
File uploads go to `POST /api/suite/upload` → stored in Drive → media_id passed to tool.
|
||||
|
||||
---
|
||||
|
||||
## Compilation & Validation Log
|
||||
|
||||
**Last Validated:** 2026-04-17
|
||||
|
||||
**Status:** ✅ Design Document - No Code to Compile
|
||||
|
||||
**Validation Checklist:**
|
||||
- [x] Architecture diagram is clear
|
||||
- [x] App pattern is defined
|
||||
- [x] WhatsApp campaign flow is documented
|
||||
- [x] Tool definitions are complete
|
||||
- [x] HTML structure is valid
|
||||
- [x] Rust code examples are syntactically correct
|
||||
- [x] Implementation phases are planned
|
||||
- [x] File structure is organized
|
||||
|
||||
**Notes:**
|
||||
- This is a design document for integrated suite conversational interface
|
||||
- No compilation required - it's planning documentation
|
||||
- Ready for implementation when developer is available
|
||||
- References existing code in botserver/src/marketing/ and botserver/src/core/bot/
|
||||
11
reset.sh
11
reset.sh
|
|
@ -1 +1,10 @@
|
|||
rm -rf botserver-stack/ ./work/ .env
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Cleaning up..."
|
||||
rm -rf botserver-stack/ ./work/ .env
|
||||
|
||||
echo "Starting services..."
|
||||
./restart.sh
|
||||
|
||||
echo "Reset complete!"
|
||||
|
|
|
|||
32
restart.ps1
Normal file
32
restart.ps1
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
$ErrorActionPreference = "Continue"
|
||||
|
||||
Write-Host "Stopping..."
|
||||
Stop-Process -Name "botserver" -Force -ErrorAction SilentlyContinue
|
||||
Stop-Process -Name "botui" -Force -ErrorAction SilentlyContinue
|
||||
Stop-Process -Name "rustc" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "Cleaning..."
|
||||
Remove-Item -Path "botserver.log", "botui.log" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "Building..."
|
||||
cargo build -p botserver
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host "Failed to build botserver"; exit 1 }
|
||||
|
||||
cargo build -p botui
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host "Failed to build botui"; exit 1 }
|
||||
|
||||
Write-Host "Starting botserver..."
|
||||
$env:PORT = "8080"
|
||||
$env:RUST_LOG = "debug"
|
||||
$env:PATH += ";C:\pgsql\pgsql\bin;C:\pgsql\pgsql\lib"
|
||||
$botserverProcess = Start-Process -PassThru -NoNewWindow -FilePath ".\target\debug\botserver.exe" -ArgumentList "--noconsole" -RedirectStandardOutput "botserver.log" -RedirectStandardError "botserver.log"
|
||||
Write-Host " PID: $($botserverProcess.Id)"
|
||||
|
||||
Write-Host "Starting botui..."
|
||||
$env:BOTSERVER_URL = "http://localhost:8080"
|
||||
$env:PORT = "3000"
|
||||
$botuiProcess = Start-Process -PassThru -NoNewWindow -FilePath ".\target\debug\botui.exe" -RedirectStandardOutput "botui.log" -RedirectStandardError "botui.log"
|
||||
Write-Host " PID: $($botuiProcess.Id)"
|
||||
|
||||
Write-Host "Done. Logs are being written to botserver.log and botui.log"
|
||||
Write-Host "To view logs, you can use: Get-Content botserver.log -Wait"
|
||||
59
restart.sh
59
restart.sh
|
|
@ -1,28 +1,49 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🛑 Stopping existing processes..."
|
||||
pkill -f botserver || true
|
||||
pkill -f botui || true
|
||||
pkill -f rustc || true
|
||||
echo "=== Fast Restart: botserver + botmodels only ==="
|
||||
|
||||
echo "🧹 Cleaning logs..."
|
||||
rm -f botserver.log botui.log
|
||||
# Kill only the app services, keep infra running
|
||||
pkill -f "botserver --noconsole" || true
|
||||
pkill -f "botmodels" || true
|
||||
|
||||
echo "🔨 Building botserver..."
|
||||
# Clean logs
|
||||
rm -f botserver.log botmodels.log
|
||||
|
||||
# Build only botserver (botui likely already built)
|
||||
cargo build -p botserver
|
||||
|
||||
echo "🔨 Building botui..."
|
||||
cargo build -p botui
|
||||
# Start botmodels
|
||||
cd botmodels
|
||||
source venv/bin/activate
|
||||
uvicorn src.main:app --host 0.0.0.0 --port 8085 > ../botmodels.log 2>&1 &
|
||||
echo " botmodels PID: $!"
|
||||
cd ..
|
||||
|
||||
echo "🚀 Starting botserver..."
|
||||
RUST_LOG=info ./target/debug/botserver --noconsole > botserver.log 2>&1 &
|
||||
BOTSERVER_PID=$!
|
||||
# Wait for botmodels
|
||||
for i in $(seq 1 20); do
|
||||
if curl -s http://localhost:8085/api/health > /dev/null 2>&1; then
|
||||
echo " botmodels ready"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "🚀 Starting botui..."
|
||||
BOTSERVER_URL="https://localhost:8088" ./target/debug/botui > botui.log 2>&1 &
|
||||
BOTUI_PID=$!
|
||||
# Start botserver (keep botui running if already up)
|
||||
if ! pgrep -f "botui" > /dev/null; then
|
||||
echo "Starting botui..."
|
||||
cargo build -p botui
|
||||
cd botui
|
||||
BOTSERVER_URL="http://localhost:8080" ./target/debug/botui > ../botui.log 2>&1 &
|
||||
echo " botui PID: $!"
|
||||
cd ..
|
||||
fi
|
||||
|
||||
echo "✅ Started botserver (PID: $BOTSERVER_PID) and botui (PID: $BOTUI_PID)"
|
||||
echo "📊 Monitor with: tail -f botserver.log botui.log"
|
||||
echo "🌐 Access at: http://localhost:3000"
|
||||
# Start botserver
|
||||
BOTMODELS_HOST="http://localhost:8085" BOTMODELS_API_KEY="starter" RUST_LOG=info ./target/debug/botserver --noconsole > botserver.log 2>&1 &
|
||||
echo " botserver PID: $!"
|
||||
|
||||
# Quick health check
|
||||
sleep 2
|
||||
curl -s http://localhost:8080/health > /dev/null 2>&1 && echo "✅ botserver ready" || echo "❌ botserver failed"
|
||||
|
||||
echo "Done. botserver $(pgrep -f 'botserver --noconsole') botui $(pgrep -f botui) botmodels $(pgrep -f botmodels)"
|
||||
|
|
|
|||
28
start.bas
28
start.bas
|
|
@ -1,28 +0,0 @@
|
|||
REM Knowledge Base Website Crawler Bot - Start Template
|
||||
REM Sets up bot context and crawled websites, then exits
|
||||
|
||||
REM Load bot introduction
|
||||
intro = GET BOT MEMORY "introduction"
|
||||
IF intro = "" THEN
|
||||
intro = "I'm your documentation assistant with access to crawled websites."
|
||||
END IF
|
||||
|
||||
REM Register websites for crawling (preprocessing mode)
|
||||
USE WEBSITE "https://docs.python.org"
|
||||
USE WEBSITE "https://developer.mozilla.org"
|
||||
USE WEBSITE "https://stackoverflow.com"
|
||||
|
||||
REM Set context for LLM
|
||||
SET CONTEXT "role" AS intro
|
||||
SET CONTEXT "capabilities" AS "I can search Python docs, MDN web docs, and Stack Overflow."
|
||||
|
||||
REM Configure suggestion buttons
|
||||
CLEAR SUGGESTIONS
|
||||
ADD SUGGESTION "python" AS "How do I use Python dictionaries?"
|
||||
ADD SUGGESTION "javascript" AS "Explain JavaScript async/await"
|
||||
ADD SUGGESTION "web" AS "What is the DOM in web development?"
|
||||
|
||||
REM Initial greeting
|
||||
TALK intro
|
||||
TALK "I have access to Python documentation, MDN web docs, and Stack Overflow."
|
||||
TALK "Ask me any programming question!"
|
||||
4
stop.sh
4
stop.sh
|
|
@ -1,4 +0,0 @@
|
|||
pkill botui
|
||||
pkill botserver -9
|
||||
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('has title', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Expect a title "to contain" a substring.
|
||||
await expect(page).toHaveTitle(/Playwright/);
|
||||
});
|
||||
|
||||
test('get started link', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Click the get started link.
|
||||
await page.getByRole('link', { name: 'Get started' }).click();
|
||||
|
||||
// Expects page to have a heading with the name of Installation.
|
||||
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
|
||||
});
|
||||
41
yarn.lock
41
yarn.lock
|
|
@ -1,41 +0,0 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@playwright/test@^1.58.1":
|
||||
version "1.58.1"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.58.1.tgz#891dcd1da815cb1042490531f6d8778988509d22"
|
||||
integrity sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==
|
||||
dependencies:
|
||||
playwright "1.58.1"
|
||||
|
||||
"@types/node@^25.2.0":
|
||||
version "25.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-25.2.0.tgz#015b7d228470c1dcbfc17fe9c63039d216b4d782"
|
||||
integrity sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==
|
||||
dependencies:
|
||||
undici-types "~7.16.0"
|
||||
|
||||
fsevents@2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
playwright-core@1.58.1:
|
||||
version "1.58.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.58.1.tgz#d63be2c9b7dcbdb035beddd4b42437bd3ca89107"
|
||||
integrity sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==
|
||||
|
||||
playwright@1.58.1:
|
||||
version "1.58.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.58.1.tgz#63300e77a604c77264e1b499c0d94b54ed96d6ba"
|
||||
integrity sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==
|
||||
dependencies:
|
||||
playwright-core "1.58.1"
|
||||
optionalDependencies:
|
||||
fsevents "2.3.2"
|
||||
|
||||
undici-types@~7.16.0:
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46"
|
||||
integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==
|
||||
Loading…
Add table
Reference in a new issue