From 272a0479473992377675c985f26e85589cd749c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= <78488229+viktor138irk@users.noreply.github.com> Date: Fri, 8 May 2026 18:54:00 +0900 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D1=84=D0=B8=D0=BA=D1=81=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D0=B4=D0=B8=D0=B0=D0=B3?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D0=B8=D0=BA=D0=B0=20409=20Telegram=20p?= =?UTF-8?q?olling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .sw | 394 ++++++++++++++++-------------------------------------------- 1 file changed, 105 insertions(+), 289 deletions(-) diff --git a/.sw b/.sw index 7c8be74..396182a 100644 --- a/.sw +++ b/.sw @@ -2,153 +2,53 @@ Project: WSChat Repository: https://github.com/viktor138irk/chat -Owner: viktor138irk Default branch: main -This file is the main project memory for continuing development in a new chat/dialog. Always open this file first before continuing work. +## Mandatory rule -## Mandatory working rule +Always update this `.sw` file after meaningful code, deployment, architecture, or debugging changes. -After every meaningful code, deployment, architecture, or debugging change, update this `.sw` file in the repository. +Never store secrets in this file: no Telegram tokens, proxy passwords, API keys, SSH credentials, or similar values. Use `[REDACTED]`. -The user explicitly requested: keep writing/updating `.sw` constantly during further development. +## Product -Do not rely on chat history only. `.sw` must remain the source of truth for project state, current bugs, fixes, deployment commands, and next steps. +Self-hosted live chat similar to Jivo. Website widget sends visitor messages to Telegram operators. Operators reply in Telegram, and replies will later return to the website widget. -## Product idea - -Build a self-hosted live chat system similar to Jivo, but with Telegram as the operator interface. - -Website visitors use an embeddable widget. Messages go to selected Telegram operators. Operators reply in Telegram, and replies return to the website widget. - -Future direction: Android app support should be planned in the API, but MVP is VPS + website widget + Telegram operators. - -## Current production/test deployment - -Current tested domains: +## Deployment ```text -https://widget.stackworks.ru/ -> widget static site -https://widget.stackworks.ru/admin/ -> admin panel -https://api.stackworks.ru/health -> backend API through FastPanel reverse proxy +widget/admin: https://widget.stackworks.ru/ +admin panel: https://widget.stackworks.ru/admin/ +backend API: https://api.stackworks.ru/health +backend local: http://127.0.0.1:3000 +PM2 process: wschat-backend +source: /opt/ws-chat/source +data: /opt/ws-chat/data +SQLite: /opt/ws-chat/data/chat.sqlite +webroot: /var/www/widget_stack_usr/data/www/widget.stackworks.ru ``` -Current VPS paths: +MVP architecture is VPS-only. Raspberry Pi was removed from MVP because of Node.js/OS/DPKG instability. -```text -/opt/ws-chat/source -/opt/ws-chat/data -/opt/ws-chat/logs -/opt/ws-chat/backups -/opt/ws-chat/updates -``` +## Database and settings -Current PM2 process: - -```text -wschat-backend -``` - -Backend listens locally only: - -```text -http://127.0.0.1:3000 -``` - -FastPanel reverse proxy: - -```text -api.stackworks.ru -> http://127.0.0.1:3000 -``` - -Widget/admin webroot: - -```text -/var/www/widget_stack_usr/data/www/widget.stackworks.ru -``` - -Admin panel lives under: - -```text -/var/www/widget_stack_usr/data/www/widget.stackworks.ru/admin/ -``` - -## Architecture decision - -MVP is VPS-only. - -Raspberry Pi 3B was removed from MVP because of Node.js/OS/DPKG problems: - -- 32-bit OS: NodeSource armhf incompatibility and segfaults. -- 64-bit OS: NodeSource arm64 produced `Illegal instruction`. -- APT/DPKG corruption was observed. - -Current architecture: - -```text -Website with embed widget - -> widget.stackworks.ru static widget/admin - -> api.stackworks.ru HTTPS reverse proxy - -> Node.js Fastify backend on 127.0.0.1:3000 - -> SQLite at /opt/ws-chat/data/chat.sqlite - -> Telegram bridge via Telegraf - -> optional SOCKS5 proxy for Telegram - -> Telegram operators -``` - -## Current backend env requirements - -```env -APP_ENV=production -APP_HOST=127.0.0.1 -APP_PORT=3000 -PUBLIC_API_URL=https://api.stackworks.ru -PUBLIC_WS_URL=wss://api.stackworks.ru/ws -TRUST_PROXY=true -DATABASE_PATH=/opt/ws-chat/data/chat.sqlite -ADMIN_ORIGIN=https://widget.stackworks.ru -WIDGET_ORIGIN=https://widget.stackworks.ru -ADMIN_BASE_PATH=/admin - -TELEGRAM_BOT_TOKEN= -TELEGRAM_PROXY_ENABLED=false -TELEGRAM_PROXY_TYPE=socks5 -TELEGRAM_PROXY_HOST=127.0.0.1 -TELEGRAM_PROXY_PORT=9050 -TELEGRAM_PROXY_USERNAME= -TELEGRAM_PROXY_PASSWORD= -``` - -Important: Telegram settings are now also persisted in SQLite `settings` table and managed from admin panel. - -## Database - -SQLite DB path: +Correct DB path: ```text /opt/ws-chat/data/chat.sqlite ``` -Tables currently managed by `backend/src/db.js`: +Production fallback DB path was fixed to the same value even if `.env` is not loaded. + +`/health` now includes `dbPath`; it must show: ```text -sites -operators -site_operators -visitors -conversations -messages -settings +/opt/ws-chat/data/chat.sqlite ``` -Default site: +Settings come from SQLite table `settings`, not from frontend. -```text -site id: site_default -widget_key: site_default -``` - -Important Telegram settings keys: +Important keys: ```text telegram.bot_token @@ -160,19 +60,17 @@ telegram.proxy.username telegram.proxy.password ``` -Check saved proxy settings on VPS: +Diagnostics: ```bash sqlite3 /opt/ws-chat/data/chat.sqlite "select key, value from settings where key like 'telegram.proxy.%';" -``` - -Check token length without exposing token: - -```bash sqlite3 /opt/ws-chat/data/chat.sqlite "select key, length(value) as len from settings where key='telegram.bot_token';" +find /opt/ws-chat/source -name "chat.sqlite" ``` -## Current backend endpoints +If a DB exists inside `/opt/ws-chat/source/backend/data/`, that was a wrong fallback DB from older code. + +## Current endpoints ```text GET /health @@ -187,53 +85,35 @@ POST /api/widget/message GET /ws ``` -`/health` now should include Telegram bridge state: - -```json -{ - "ok": true, - "service": "wschat-backend", - "env": "production", - "telegram": { - "enabled": true, - "running": true, - "error": "", - "username": "...", - "proxyEnabled": true, - "startedAt": "...", - "hasBot": true - } -} -``` - -## Admin panel current state - -Admin is a React/Vite panel at: +Expected `/health` includes: ```text -https://widget.stackworks.ru/admin/ +ok=true +service=wschat-backend +env=production +dbPath=/opt/ws-chat/data/chat.sqlite +telegram.enabled=true +telegram.running=true +telegram.error= +telegram.proxyEnabled=true +telegram.hasBot=true ``` +## Admin panel + Implemented: -- dark compact dashboard UI; -- API health indicator; -- stats cards; -- recent messages list from SQLite; -- auto-refresh of dashboard data; +- dashboard stats/messages; - Telegram/SOCKS5 settings form; -- dirty-state protection so auto-refresh no longer wipes input while typing; -- token/password masks `********`; -- SOCKS5 enable/host/port/login/password fields; -- save settings button; -- test proxy button; -- reset form button. +- dirty-state protection so refresh does not wipe settings while typing; +- token/password masks; +- save/test/reset actions. -Important fix: dashboard auto-refresh must not reload Telegram/SOCKS5 form while the user is editing it. +Important: admin loads Telegram settings from `GET /api/admin/telegram/settings`, which reads SQLite. -## Telegram bridge current state +## Telegram bridge -Runtime bridge file: +Runtime file: ```text backend/src/telegram.js @@ -247,87 +127,67 @@ socks-proxy-agent node-fetch ``` -Current behavior: +Implemented: -- backend starts Telegram bridge on startup using settings from SQLite; -- `/start` registers Telegram user as active operator; -- new operator is linked to `site_default` through `site_operators`; -- `/status` replies with bridge status; -- text reply in Telegram can be saved as operator message if it is a reply to WSChat notification containing `Conversation: conv_...`; -- website visitor message is saved to SQLite and then sent to active Telegram operators; -- operator reply is saved to SQLite, but delivery back to widget via WebSocket is not finished yet. +- bridge startup from SQLite settings; +- SOCKS5 proxy support; +- `/start` registers operator; +- `/status` replies with bridge state; +- visitor messages go to active Telegram operators; +- Telegram reply can be saved as operator message when replying to WSChat notification. -Important: bridge originally used `socks5://`, but successful curl test showed Telegram must be accessed via `socks5h://` so DNS resolves through proxy. +Not finished yet: -Current fix: +- delivery of Telegram replies back to widget via WebSocket. + +Important proxy fix: ```text -backend/src/telegram.js uses socks5h:// for SocksProxyAgent +Telegram bridge must use socks5h:// so DNS resolution goes through proxy. ``` -Commit for this fix: +## Current debugging status + +Current observed Telegram error: ```text -4b46aabc8210158f97c3c6e9274b8f703f7a8aa2 +409 Conflict: terminated by other getUpdates request; make sure that only one bot instance is running ``` -## Telegram/SOCKS5 debugging history +Meaning: Telegram token/proxy are usable, but two polling instances are running for the same bot token. -Observed `/health` error before socks5h fix: +Most likely cause: a manual `node src/server.js` process was started during debugging and is still alive while PM2 also runs `wschat-backend`. -```text -request to https://api.telegram.org/bot.../getMe failed, reason: Proxy connection timed out -``` - -User confirmed SOCKS5 itself works from VPS with curl: +Fix on VPS: ```bash -curl -v --proxy 'socks5h://proxy:Adelina%402015@194.156.65.175:42673' https://api.telegram.org +pkill -f "/opt/ws-chat/source/backend/src/server.js" || true +pkill -f "node src/server.js" || true +pm2 delete wschat-backend || true +cd /opt/ws-chat/source/backend +pm2 start src/server.js --name wschat-backend --update-env +pm2 save +sleep 5 +curl -s http://127.0.0.1:3000/health | jq ``` -Result showed: +If 409 persists: + +```bash +ps aux | grep -E "node|server.js|wschat" | grep -v grep +``` + +Only one polling instance may run per Telegram bot token. + +## Important recent commits ```text -SOCKS5 request granted -HTTP/2 302 +4b46aabc8210158f97c3c6e9274b8f703f7a8aa2 - Telegram proxy changed to socks5h +6f14353cd403f351c89e4274d189808951dcf940 - production DB fallback fixed +be004fd14ab16e3b1262980fe044356d2efbe806 - health endpoint includes dbPath ``` -This proves proxy works and Telegram is reachable through it. - -Important note: the SOCKS5 password contains `@`. In curl URL it must be encoded as `%40`, but in admin panel it should be entered normally as `Adelina@2015`. Code uses `encodeURIComponent`, so the app should encode it correctly. - -Current proxy values used in testing: - -```text -Host: 194.156.65.175 -Port: 42673 -Login: proxy -Password: Adelina@2015 -SOCKS5 enabled: true -``` - -Do not expose Telegram bot token in chat or logs. - -## Important commits after original snapshot - -- `eae37d38a98026c39e4cd71e0f54f94d4785d9e9` — admin dashboard shows stats/messages. -- `b9b68d401ce0a6661f169064a1fee4e5ca441f19` — updated admin styling. -- `d601e6925718e5d8c59394682da05ff25e4581a0` — DB functions for Telegram/SOCKS5 settings. -- `966c3cf531c61d13c300bb584b3cb50453c56a7c` — backend API for Telegram/SOCKS5 settings. -- `c1169032ee0809fcc0f52f8e7d1b8cdfd4c1f375` — proxy config validation endpoint. -- `1c644e1df7ebd5fb88e92fb3f6360f86355aac04` — Telegram/SOCKS5 form in admin. -- `53fad336d3013b9f1fc1e25fdac4149956dc356b` — styles for Telegram/SOCKS5 form. -- `9999139ab5c1cf227187d6b596caea8e2c0e7f32` — fixed auto-refresh wiping SOCKS5 form. -- `760e85e342fd1c08e9a80de6eb6429fca17ec3ac` — added backend dependencies for Telegram/SOCKS5 bridge. -- `5c6da6582e9d7077c4d7fe504b9731f853058072` — operators and operator messages DB functions. -- `72edf824e0d7ebf92dfc27dfc8a956d2d927448c` — added runtime Telegram bridge file. -- `47096dd0de601448a2c7f9ba1d5ac724f3bd7b69` — connected Telegram bridge to backend runtime. -- `b22381061236a3a9568a5a906375f73dcbe16f87` — restartable Telegram bridge. -- `27e94c96533b2955325d1d7e407f53d98bd0e81b` — restart endpoint and attempted auto-restart after settings save. -- `8632c577a8b798bd7c5480998156919988affccb` — separated settings save from bridge restart to avoid timeout wiping UI state. -- `4b46aabc8210158f97c3c6e9274b8f703f7a8aa2` — changed Telegram SOCKS agent to `socks5h://`. - -## Deployment/update commands +## Deployment commands Backend update: @@ -339,21 +199,19 @@ npm install pm2 restart wschat-backend --update-env ``` -Hard reset if server is behind or files are missing: +Hard restart as single PM2 process: ```bash -cd /opt/ws-chat/source -git fetch origin main -git reset --hard origin/main -git clean -fd -cd backend +pkill -f "/opt/ws-chat/source/backend/src/server.js" || true +pkill -f "node src/server.js" || true +pm2 delete wschat-backend || true +cd /opt/ws-chat/source/backend npm install -pm2 delete wschat-backend pm2 start src/server.js --name wschat-backend --update-env pm2 save ``` -Admin/widget build and publish: +Frontend build/publish: ```bash cd /opt/ws-chat/source @@ -363,68 +221,26 @@ rsync -av --delete widget/dist/ /var/www/widget_stack_usr/data/www/widget.stackw rsync -av --delete admin-panel/dist/ /var/www/widget_stack_usr/data/www/widget.stackworks.ru/admin/ ``` -Health check: +Health/logs: ```bash curl -s http://127.0.0.1:3000/health | jq -``` - -Logs: - -```bash pm2 logs wschat-backend --lines 100 ``` ## FastPanel safety rules -Never from project scripts: - -- edit `/etc/nginx/nginx.conf`; -- overwrite FastPanel vhost configs; -- run broad `systemctl restart nginx`; -- install packages that replace FastPanel web stack; -- bind project services directly to ports 80/443; -- delete parent `/var/www` directories; -- run `rsync --delete` against `/var/www` or parent directories. - -Only copy static files into exact domain webroot directories. +Never edit global FastPanel/nginx configs from project scripts. Never bind project services directly to ports 80/443. Never run `rsync --delete` against `/var/www` or parent directories. Copy static files only into exact domain webroots. ## Current next steps -1. Pull latest code with `socks5h://` fix on VPS. -2. Restart backend with PM2. -3. Check `/health` and confirm `telegram.running: true`. -4. In Telegram, send `/start` to the bot and confirm operator registration. -5. Send a message from widget and confirm it arrives to Telegram operator. -6. Implement delivery of Telegram operator replies back to widget through WebSocket. -7. Add admin UI bridge status/restart button. -8. Add admin list of Telegram operators. +1. Kill duplicate Telegram polling process. +2. Start exactly one PM2 process `wschat-backend`. +3. Confirm `/health`: correct `dbPath` and `telegram.running=true`. +4. Send `/start` to the Telegram bot. +5. Send widget message and confirm it reaches Telegram. +6. Implement Telegram reply delivery back to widget via WebSocket. +7. Add admin bridge status/restart button. +8. Add admin operator list. 9. Add admin auth. -10. Add site CRUD and operator-site permissions. -11. Fix production widget build to emit stable `widget.js`. -12. Add origin/domain validation: `site_id + Origin` must match configured site. -13. Add updater bundle workflow. -14. Continue updating this `.sw` after each meaningful change. - -## User preferences and constraints - -- User wants practical development, not only planning. -- User wants all work in GitHub repository `viktor138irk/chat`. -- User wants to resume development in new dialogs using this `.sw` file. -- User explicitly wants `.sw` continuously updated. -- User prefers not to risk breaking FastPanel. -- User wants manual control over domains in FastPanel. -- User wants future auto-update file/bundle workflow. -- User changed architecture to VPS-only after Raspberry issues. -- VPS currently uses root user by default, so MVP installation can run as root. -- Widget and admin must live in one FastPanel site: widget at `/`, admin at `/admin/`. - -## How to continue in a new chat - -Open `.sw` first, then continue from `Current next steps`. - -Recommended immediate task: - -```text -Pull latest code on VPS, restart backend, verify Telegram bridge with socks5h proxy, then test /start. -``` +10. Fix production widget build to emit stable `widget.js`.