Commit Graph

237 Commits

Author SHA1 Message Date
NW
2744cdf6de ci: fix release checkout — dispatch uses branch ref (main/dev), version input only for image tags
Some checks failed
Release: multi-arch Docker images / build-push (push) Failing after 24s
2026-08-11 10:44:31 +01:00
NW
5c7bc242c5 ci: registry-based releases — multi-arch images built in CI, servers only pull
- release workflow: buildx multi-arch (amd64+arm64) build+push of bot and admin images to Gitea Container Registry (git.softuniq.eu/telegram-market/telegram-shop[-admin])
- docker-compose: bot/admin use registry images (IMAGE_TAG for pinning); tor-proxy stays local alpine build
- install.sh: pull from registry instead of local docker build (no native compilation on weak hardware); interactive .env setup preserved
- new buildx runner gitea-host-buildx (label buildx) on x86_64 host
- REGISTRY_TOKEN replaced with package-scoped token (write:package)
- README/VERSION/.env.example updated
2026-08-11 10:37:09 +01:00
NW
33ec420fc0 feat(admin): issue #148 — button lock + loaders on all Catalog Tree ops (double-click protection)
- busyAction global mutex guard on toggle/sort/rename/delete/add/clone
- Per-op states: togglingId, sortingId, deleting, adding, cloningId
- Switch/sort arrows/Pencil/Trash/Add/Clone disabled during ops + Loader2 spinners
- Delete dialog: Delete disabled + 'Deleting...'
- tsc clean
2026-08-10 13:24:56 +01:00
NW
cef8fbbee4 fix(admin): catalog tree — typeToPath mapping (categorys->categories, subcategorys->subcategories)
- handleToggleActive/handleDelete/handleRename/handleSort used ${type}s which produced 'categorys'/'subcategorys' -> 404
- Added typeToPath helper: category->categories, subcategory->subcategories, location->locations, product->products
2026-08-10 12:27:26 +01:00
NW
9ac7afa36e fix(admin): issue #147 — Catalog Tree city edit/delete, sort order, subcategory ops
- handleRename: city rename via /api/locations/rename-city (all rows), district via PUT /api/locations/{id}
- City-level delete: DELETE /api/locations/by-city (blocks on dependencies, 400 with counts)
- Sort order: idempotent ensureSortOrderColumns (ALTER TABLE try/catch) + PATCH /api/{type}s/{id}/sort + up/down arrows on district/category/subcategory
- Tree queries order by sort_order asc, then name
- Subcategory rename/delete verified
- tsc clean
2026-08-10 10:55:12 +01:00
NW
1b7050002e fix(admin): bulk APIs — include->select for _count (Prisma 6.19 select+include conflict) 2026-08-10 10:22:02 +01:00
NW
301763f428 feat(admin): issue #146 — photo upload with sharp crop/optimization (restore old behavior)
- POST /api/upload: FormData, 10MB limit, sharp resize 800px inside + webp@80, saves to /app/uploads, returns /uploads/url
- GET /uploads/[...path]: serves files with Content-Type, path traversal protected
- compose: ./uploads mounted in tg_shop_admin
- Dockerfile: /app/uploads created + chown nextjs
- catalog-page: file input + thumbnail preview + remove for photoUrl/hiddenPhotoUrl
- Bot resolvePhotoSource already supports /uploads/ paths — no bot changes
2026-08-10 09:38:31 +01:00
NW
792efc07ce feat(admin): issue #145 — delete-blocked hint + Deactivate/Edit alternative
- categories dialog: red hint with count + Deactivate button when products>0
- locations dialog: red hint + Deactivate button when categories/products>0
- catalog dialog: deleteError shown on 400/409; Deactivate for category/subcategory/location, Edit for product
- Deactivate calls existing PATCH toggle, closes dialog, reloads
- tsc clean
2026-08-10 08:44:12 +01:00
NW
3b8e6416c4 feat(admin): Bot Configuration — eye toggle to reveal masked values (token, secrets)
- compose: pass bot env (BOT_TOKEN, SUPPORT_LINK, ADMIN_IDS, SUPER_ADMIN_IDS, WG_*, ADMIN_*, GITEA_API_URL) to tg_shop_admin
- settings API: reads real env values; POST /api/settings reveals secret value by key (auth required)
- settings-page: eye/eye-off button on masked fields, shows real value on click (BOT_TOKEN, ADMIN_IDS, etc.)
2026-08-09 15:27:48 +01:00
NW
7ba17f2de6 fix(admin): super admin always has full seed access (commission informational only) 2026-08-09 13:56:08 +01:00
NW
d7bbb9ec6b feat(admin): issue #144 — seed phrases for regular admin, commission-gated + Mercuryo payment
- overview: commissionWallets (env) + mercuryoUrl in response
- seeds API: getAuth (regular admin), locked=true + no mnemonics when commissionDue>0, full when 0
- export-seeds: 403 when commissionDue>0
- UI: seed tab for all admins; payment block (past payments, difference, commission wallet selector, Mercuryo card button, I've paid -> record-payment); full table + CSV when unlocked
- super_admin: full access regardless (informational warning)
2026-08-09 13:44:28 +01:00
NW
d827a18ee9 feat(admin): decrypt mnemonics + balance column in seed phrases
- lib/mnemonic.ts: decryptMnemonic (same AES-256-CBC+HKDF algo as bot, uses ENCRYPTION_KEY)
- wallets/seeds API: decrypts mnemonic per user, adds balance field
- wallets/export-seeds (CSV): decrypts mnemonic, adds Balance column
- wallets-page: Balance column added to seed phrases table
- compose: ENCRYPTION_KEY passed to tg_shop_admin (same key as bot)
2026-08-09 01:23:34 +01:00
NW
d1ce76a14c fix(admin): seed phrases 500 — Prisma 6.19 rejects select+include together
- wallets/seeds: move user relation into nested select (was select+include -> PrismaClientValidationError 500)
- wallets/export-seeds: same fix (CSV export)
- Verified no other top-level select+include conflicts in api routes
- tsc clean
2026-08-09 01:05:43 +01:00
NW
d7680357af chore: repo cleanup + docs for admin API and DB schema (v1.2.8)
- remove stale docs/admin-frontend-spec.md (old Express/EJS admin), unused templates/ (SmartAdmin copy), dead scripts/sync-agents.cjs, committed dev.pid
- add docs/API.md (admin REST API reference) and docs/DATABASE.md (DB schema)
- refresh .env.example: drop stale ADMIN_PORT/SHOP_CONTAINER, add ADMIN_URL, HEALTH_PORT, DEFAULT_LANGUAGE, CHATBOT_API_*
- add npm run lint so Gitea workflows pass
- rebrand web-testing suite from APAW to telegram-shop
2026-08-09 00:22:22 +01:00
NW
338a700b3a fix(bot): issue #143 — sleep mode safety guards + super-admin seed access
- sleepGuard.js: assertShopOpen/redirectIfPaused — blocks write-flows on shop pause, redirects to AI dialog, fallback to sleep message
- Blocked: buy/pay/quantity/top-up/deposit/wallet-create when paused
- Soft redirect: catalog navigation (country/city/district/category/product) to AI on pause
- Read-only flows untouched (purchase history, balance, tx history)
- Tests: 10 sleepGuard tests (T1-T6 + alias + fallback), 42 total pass
- fix(admin): super-admin seed phrases not blocked by commission (informational only)
- wallet test mock updated for sleepGuard
2026-08-08 23:46:56 +01:00
NW
3b9aa5d541 fix(bot): issue #142 — language selection on first contact (Products/message in sleep mode)
- keyboard.products in sleep mode: language_set=0 -> language keyboard first, then AI in chosen language
- message handler in sleep mode: same language_set check before AI
- AI context verified: chat_sessions history (max 20) + LANGUAGE_INSTRUCTIONS[lang] in system prompt
- 30 tests pass
2026-08-08 21:07:33 +01:00
NW
c17e5f4099 fix(admin): Translations table — add Section header column (was shifted 1 cell left)
- Table had 4 headers (Key + 3 langs) but 5 data cells (Section rowSpan + Key + 3 langs)
- Headers were misaligned relative to data; added Section column header
2026-08-08 17:48:32 +01:00
NW
bfa21fc156 fix(ai): issue #141 — custom OpenAI-compatible providers work + language selection on first start in sleep mode
- callOllama: reasoning_effort only for provider=ollama (others returned 400 -> stub reply)
- endpoint normalization: base URL (Groq /openai/v1) -> /chat/completions appended
- reasoning block stripping: <thinking>/<think> tags + thinking/response markers (Groq qwen)
- handleStart: sleep mode + language_set=0 -> show language selection keyboard first
- handleSetLanguage: sleep mode -> AI dialog in chosen language after selection
2026-08-08 15:31:19 +01:00
NW
b352d1434c feat(admin): load LLM models from provider /models endpoint (OpenAI-compatible)
- New API /api/chatbot/models: fetches model list from configured endpoint (/models, OpenAI/Ollama format)
- Uses saved site_settings endpoint+key, or accepts endpoint/apiKey query params (unsaved custom provider)
- UI: 'Загрузить модели' button in Provider tab — loads models into select
- Manual model input always available for Custom providers
- No more hardcoded Ollama-only model list
2026-08-08 14:01:29 +01:00
NW
9bc0bffac7 fix(db): migration 014 — add users.notes column (Next.js admin Prisma requires it)
- prod DB was missing users.notes → /api/users/bulk 500 (Prisma P2022)
- Applied to prod; users + lead relations now load correctly
2026-08-08 13:26:52 +01:00
NW
c7a4463ac4 fix(admin): login redirect — full location.href=/ instead of hash, session check on mount
- window.location.href='/' after login (was window.location.hash='/' which stayed on /login#/)
- checkSession on mount: already-authenticated users skip login form
2026-08-08 13:12:52 +01:00
NW
9aa3e41c3f docs: README — remove old Express admin references, health-server port 3001, super secret 2026-08-08 12:41:34 +01:00
NW
01d75fc7b7 refactor(bot): remove old Express/EJS admin panel, add standalone health server (v1.2.7)
- Delete src/admin/ (1012 files: routes, views, public, auth) — old admin replaced by Next.js admin-next/
- Add src/healthServer.js: minimal HTTP /health on port 3001 for Docker healthcheck
- src/index.js uses startHealthServer instead of startAdminPanel
- Remove admin-dependent test (adminDeleteFeedback.test.js); 30 tests pass
- Remove ejs/express-ejs-layouts/express/cookie-parser/multer from deps
- admin-next: prisma binaryTargets for linux-arm64-openssl (arm64 prod)
- VERSION.md v1.2.7
- Bot adminHandlers (Telegram commands) kept — data preserved in shared SQLite
2026-08-08 12:22:15 +01:00
NW
b1844b1acc fix(compose): tor-proxy hardcodes tg_shop_admin:3000 — onion always serves new Next.js admin
- Old .env had ADMIN_PORT=3001/SHOP_CONTAINER=telegram_shop_prod overriding compose defaults
- Tor onion was proxying to old Express admin; now hardcoded to new Next.js admin
2026-08-08 12:05:46 +01:00
NW
a71012680a docs: README — new Next.js admin panel (admin-next/), tor schema update, project structure 2026-08-08 11:55:52 +01:00
NW
9226871eb4 fix(bot): lead race condition — INSERT OR IGNORE + reselect on UNIQUE conflict
- getOrCreateLead: INSERT OR IGNORE prevents UNIQUE constraint race (parallel messages creating same telegram_id lead)
- On changes=0, reselect existing lead instead of failing
2026-08-08 11:51:18 +01:00
NW
e202b357dc chore: ignore admin-next/.env (secrets kept on server) 2026-08-08 04:52:19 +01:00
NW
d78c7aa502 fix(admin): add openssl+curl for Prisma SQLite and healthcheck in runner stage 2026-08-08 01:39:38 +01:00
NW
a4a5fd449d feat(admin): integrate Next.js admin panel (admin-next/) from feat/nextjs-admin
- Add admin-next/: full Next.js + Prisma + shadcn admin panel (45 API routes, 76 components)
- docker-compose: tg_shop_admin service (port 3000, shared db/shop.db, prisma), bot talks to it via ADMIN_CHAT_URL=http://tg_shop_admin:3000/api/chat
- tor-proxy now proxies onion admin to tg_shop_admin:3000 (new panel)
- chatbotService: ADMIN_CHAT_URL default = http://tg_shop_admin:3000/api/chat (removed localhost:3100 anachronism)
- .env admin secrets gitignored (admin-next/.env)
2026-08-08 01:31:45 +01:00
NW
62534dbe85 feat(bot): AI-chat integration — leads, chatbot service, sleep mode + migration 013
- chatbotService: bridge to Next.js admin chat API (localhost:3100) — sleep mode, welcome, LLM replies
- leadService: lead sync from every user message, interaction logging to audit_log
- index.js: unhandled messages route to AI when chatbot_enabled; lead sync on every message
- userHandler/routes: lead capture on /start and catalog; sleep mode redirects to AI dialog
- Migration 013: leads, site_settings, chat_sessions tables (idempotent, chatbot_enabled/sleep_mode default 0)
- messageRouter.dispatch returns boolean (handled/not) for AI fallback
- gitignore db backups
2026-08-08 01:12:10 +01:00
NW
a5ea99b39b fix(admin): issue #131 — dead callback buttons prod_district_/admin_users + no-op placeholders
- prod_district_: pipe-delimited format (multi-word names safe) + handleDistrictBack shows categories (admin sees disabled locations via getLocationsByCountryAndCityAdmin)
- admin_users: handleUserListBack (viewUserPage(0) edit)
- current_page/current_quantity/no_action: no-op exact routes (no 'No handler' warns)
- Audit: all 78 generated callbacks cross-checked — no overlaps, none missing
- 48 tests pass; bump v1.2.6
2026-08-05 12:46:37 +01:00
NW
61c7a90aeb fix(bot): issue #130 — crypto deposit photo-edit 400, chat cleanup via lastInlineMessageId
- depositHandler: handleDepositInstruction + handleDepositSelectWallet use editOrSendCallback (photo-safe fallback) — fixes 'no text in the message to edit' 400
- resetUserContext deletes lastInlineMessageId (stale inline menus cleaned on Reply Keyboard nav)
- showProducts/showProfile/showBalance/showPurchases store lastInlineMessageId on sendMessage
- answerCallbackQuery verified before dispatch (v1.2.4)
- 48 tests pass; bump v1.2.5
2026-08-05 12:20:16 +01:00
NW
f90af4c78e docs(admin): frontend spec for admin panel + endpoint architecture (issue #131) 2026-08-05 12:07:56 +01:00
NW
7a97d561a5 fix(bot): issue #129 — missing shop_district_/shop_subcategory_ handlers, answerCallbackQuery timing, state.location pipe format
- Register shop_district_ (handleDistrictBack) + shop_subcategory_ (handleSubcategorySelection) in routes.js — Back button in empty categories now works
- state.location pipe-delimited with encodeURIComponent — multi-word names (Saint Petersburg) no longer break nav
- answerCallbackQuery moved to start of callback handling — no stuck spinner
- Empty city fallback (district_unknown) in Select district
- Guard against stale underscore-format state.location
- 48 tests pass; bump v1.2.4
2026-08-05 10:52:18 +01:00
NW
12c4cefc4c chore: ignore Kilo agent config files (kept on disk, system unaffected)
- Add .kilo/, kilo-meta.json, kilo.jsonc, AGENTS.md to .gitignore
- git rm --cached: files remain on disk, only removed from version control
- Agent pipeline (orchestrator, agents, capability-index) keeps working locally
2026-08-04 22:57:03 +01:00
NW
04c358eb30 chore(agents): sync agent configs — model updates to nemotron-3-super
- Update agent model assignments (nemotron-3-ultra -> nemotron-3-super) across .kilo/agents, kilo-meta.json, kilo.jsonc, capability-index.yaml
- Sync agent descriptions in KILO_SPEC.md
2026-08-04 22:55:17 +01:00
NW
b58087f37b fix(bot): issue #128 — empty category menus, duplicate country lists, DB typo+desync migration
- getCategoriesWithProductsByLocationId: filter districts to categories with real in-stock/mono products; empty → no_categories message + back button + answerCallbackQuery
- Main-menu debounce (1200ms) in routes.js for products/profile/wallets/purchases — no duplicate Select-your-country on rapid taps
- Migration 012: fix typos (Centr→Center, Chiken→Chicken, Brusel→Brussels, Sever→North) + re-enable locations that have in-stock products (desync fix)
- Tests updated (48 pass); bump v1.2.3
2026-08-04 20:53:34 +01:00
NW
5c6760b180 ci: install docker-cli in alpine job container for build/push/save steps
All checks were successful
Release: ARM64 Docker Image / build-arm64 (push) Successful in 3m14s
v1.2.2
2026-08-04 19:21:04 +01:00
NW
eac2a0cd6c ci: use sh shell in release workflow (node:22-alpine has no bash)
Some checks failed
Release: ARM64 Docker Image / build-arm64 (push) Failing after 1m40s
2026-08-04 19:17:33 +01:00
NW
4186ebeab6 ci: fix checkout step - git in alpine + pass REGISTRY_TOKEN via env
Some checks failed
Release: ARM64 Docker Image / build-arm64 (push) Failing after 12s
2026-08-04 18:33:50 +01:00
NW
49d3f41686 ci: release workflow without GitHub actions (network blocked) - pure run steps
Some checks failed
Release: ARM64 Docker Image / build-arm64 (push) Failing after 12s
- GitHub unreachable on prod network; actions/checkout@v4 etc fail to download
- Rewrite release.yaml using only run: steps (git clone from Gitea, docker build/push)
- Clone uses REGISTRY_TOKEN (oauth2) from Gitea secrets
- Registry push is best-effort; always saves image tarball artifact
2026-08-04 18:30:35 +01:00
NW
9eca348d57 ci: ARM64 release workflow (Gitea Actions, native arm64 runner on Orange Pi)
Some checks failed
Release: ARM64 Docker Image / build-arm64 (push) Failing after 3s
- Runs on tag push (v*) on arm64 runner (orange-pi-arm64, label: arm64)
- Native ARM64 docker build (no QEMU), consistent with prod Orange Pi Zero 2
- Best-effort push to Gitea Container Registry (git.softuniq.eu/telegram-market/telegram-shop)
- Falls back to saving image tarball if registry auth unavailable
2026-08-04 18:04:05 +01:00
NW
88a15acb29 fix(admin): delete feedback alerts + informative block errors (issue #127)
- locations/categories GET pass req.query.error/success to views
- locations/categories EJS render dismissible error/success alerts (modeled on catalog.ejs)
- Delete errors include blocking counts + 'Remove X first' hints
- 🔒 lock hint on rows with linked categories/products/subcategories
- 18 new tests (adminDeleteFeedback.test.js); 48 total pass
2026-08-04 17:05:06 +01:00
NW
bd3391c111 fix(bot): issue #127 — active-state sync, disabled-entity handling, double-tap lock, state reset
- BUG-01: getActiveLocationById + product availability checks (loc_active/cat_active) — disabled locations/categories filtered from bot menus
- BUG-02: graceful redirect to main menu (location_disabled notice) when entity disabled mid-flow, no crash in handleDistrictSelection/handleProductSelection/handleBuyProduct/handlePay
- BUG-03: per-user callback lock (LOCK_MS 1500ms debounce) in utils/callbackLock.js — duplicate taps dropped
- BUG-04: resetUserContext clears tracked photo/product messages + userStates on main-menu navigation and /start
- fix: handlePay uses validated numeric quantity (was raw string) for price/stock/purchase writes
- tests: 7 new (botBugFixes.test.js), updated userProductHandler tests — 30 total pass
- bump v1.2.2
2026-08-04 15:21:55 +01:00
NW
29ab8f9d34 chore(agents): sync agent configs, models, capability index; cleanup junk
- Update agent model assignments (minimax/glm -> nemotron-3-ultra, kimi-k2.7-code, qwen3.5:397b) in .kilo/agents, kilo-meta.json, kilo.jsonc, capability-index.yaml
- Update orchestrator/agent prompts (complexity fast-path, verification tests, close-loop audit)
- Add .kilo/KILO_SPEC.md (Kilo Code specification reference)
- AGENTS.md: consolidate smartadmin agent rows
- Remove screenshot-dash.cjs (unused, contained hardcoded admin token); gitignore it
- Remove empty .kilo/milestones/
2026-08-04 14:16:41 +01:00
NW
47c698aa42 fix(admin): make catalog CRUD management visible
- Add management toolbar on /catalog with links to /locations and /categories
- Expand catalog tree by default (all levels visible, no collapsed accordion)
- Add Back to Catalog link on /locations and /categories pages
- Edit/toggle/delete buttons for locations/categories/subcategories now immediately accessible
2026-07-25 13:12:12 +01:00
NW
ca2ddefd7a feat(admin): full CRUD + enable/disable for locations, categories, subcategories
- Migration 011: add is_active INTEGER NOT NULL DEFAULT 1 to locations, categories, subcategories (idempotent)
- Admin routes: locations edit + toggle, categories toggle, subcategories edit + toggle (parallel endpoints on /catalog)
- Bot-side services: filter is_active=1 on locationService/categoryService read methods (getLocationById/getCategoryById left unfiltered for purchase display)
- Views: edit forms, toggle buttons, Active/Disabled badges, disabled row styling in locations.ejs, categories.ejs, catalog tree
- Add Categories nav item in sidebar (folder icon)
- Tests: 14 new tests for migration idempotency + service is_active filtering (23 total pass)
2026-07-19 23:22:21 +01:00
NW
776d0e8552 fix(bot): remove redundant deposit amount step, add Visa/MC label, Mercuryo auth note, enforce product completeness
- Remove deposit amount-selection step; deposit_wallet_<TYPE> now routes directly to instruction
- Add VISA / Mastercard text to Mercuryo card button (i18n en/es/de)
- Add deposit_important5: Mercuryo 1-payment-without-auth + top-up-reserve warning
- Admin validation: description + photo required on product create/update (products.js, catalogProducts.js)
- Cleanup orphan uploaded files on validation failure (catalogProducts.js)
- Bot guards: fallback to products.no_description / products.no_photo for incomplete products
- Add vitest + 7 purchase edge-case tests (src/__tests__/userProductHandler.test.js)
- Bump version to v1.2.1
2026-07-18 14:28:26 +01:00
NW
b6eb42ccfc fix: seed phrase modal, USDT address bug, CSV balance column, remove CSRF
- Fix seed phrase reveal modal: use classList instead of style.display
  to properly toggle d-none/d-flex on Bootstrap elements
- Fix USDT/USDC wallet creation bug: was using ETH address (index 0)
  instead of correct derivation path address (index 1/2)
- Add Balance column to CSV seed export
- Remove CSRF tokens from wallets.ejs (incompatible with Tor/onion)
- Super admin CSV export: no commission check required
- Audit logging for CSV seed exports
- Use window.addEventListener('load') for seed modal JS to ensure
  Bootstrap is loaded before initializing bootstrap.Modal
2026-07-14 14:50:24 +01:00
NW
d03c8419e5 feat(admin): super admin role, seed phrase viewer with QR code, CSRF disabled for Tor
- Add super admin role system (SUPER_ADMIN_SECRET env var)
  - requireSuperAuth middleware for sensitive routes
  - isSuperAdminWeb() helper for template access
  - Role badge in header (Super Admin / Admin)
  - Seed Viewer nav item visible only to super admins

- Add seed phrase viewer with QR code generation
  - GET /wallets/seed/:walletId — JSON seed phrase (super admin only)
  - GET /wallets/seed-qr/:walletId — QR PNG image (super admin only)
  - Modal UI with reveal-on-click, 60s auto-hide countdown
  - Copy-to-clipboard and download QR as PNG
  - Audit logging for every seed phrase access

- Disable CSRF completely for Tor/onion compatibility
  - csrfMiddleware no longer sets _csrf cookie
  - validateCsrf and validateCsrfFromBody are no-ops
  - res.locals.csrfToken set to empty string (prevents template errors)

- .env.example: document SUPER_ADMIN_SECRET variable
2026-07-09 16:40:15 +01:00