Commit Graph

228 Commits

Author SHA1 Message Date
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
NW
83991f098b v1.2.0: disable CSRF for Tor, fix wallet type validation, add version history modal
- fix(admin/csrf): completely disable CSRF checks for Tor/onion compatibility
- fix(validators): add 'main' and 'bonus' to WALLET_TYPES for purchase flow
- feat(admin): add clickable version tag with version history modal in sidebar
- docs: add VERSION.md with changelog and update instructions
2026-07-08 21:59:16 +01:00
NW
4997ca75ab fix(admin): header logo alignment + sidebar version tag
- Move app-logo out of flex-grow-1 div to be direct child of app-header
  (matches SmartAdmin CSS expectations for .app-header .app-logo)
- Remove inline style padding-left from logo, rely on SCSS padding
- Remove data-prefix attribute that positioned version text absolutely
- Override .app-logo > svg.sa-icon min-width (was 11rem) to natural
  icon size (1.5rem) so icon and text align inline
- Add .logo-text class for proper text sizing and nowrap
- Fix conflicting responsive classes on header buttons
  (d-sm-block d-sm-none → d-none d-lg-block)
- Fix fullscreen button aria-label (was 'Toggle Dark Mode')
- Remove w-100 from header inner div that pushed buttons off-screen
- Replace wifi icon in nav-footer with tag icon + version text v1.0
2026-07-08 14:00:20 +01:00
NW
f0afada884 feat: Mercuryo gateway, crypto QR deposit, mono products, wallet auto-refresh
- Replace Quickex/Guardarian with Mercuryo (https://mercuryo.io/)
- Add crypto QR code payment option in deposit flow (qrcode package)
- Add is_mono product flag for digital/infinite products
- Mono products: no quantity buttons in bot, always available
- Admin wallet page: auto-refresh balances from blockchain APIs
- Migration 010: add is_mono column to products
- i18n updates for en/de/es
2026-07-08 12:08:13 +01:00
NW
2b30bc4a91 fix(admin): CSRF cookie sameSite=false for Tor, auth cookie fix, async handlers, validation 2026-07-08 12:08:08 +01:00
NW
046c40349d chore: sync all changes 2026-07-07 18:48:40 +01:00
NW
e84c2af650 fix(admin/dashboard): charts rendering + realistic demo data
- Move ApexCharts script to <head> in app-head-css.ejs for global availability
- Remove conflicting apexchartsWrapper.js module from app-scripts.ejs
- dashboard.ejs: wrap charts init in window.addEventListener('load') for correct DOM timing
- Add inline height styles to chart containers (350px, 300px, 250px)
- Add CSS min-height fallback for .apex-charts in layout.ejs
- seed.js: realistic demo data with 30-day date spread, 10 users, 30 purchases,
  12 audit log entries, 2 commission payments, 10 wallets with 7 coin types
- dashboard.js: add days30 and revenueData30 to chartData for 30-day chart
2026-07-06 19:59:56 +01:00
NW
1648336511 fix(admin/dashboard): restore layout BEFORE SortableJS init
- Reorder DOM elements from localStorage BEFORE initializing SortableJS
- Initialize Sortable AFTER layout restoration so it tracks correct DOM
- Add console.log for save/restore debugging
2026-07-06 19:22:22 +01:00
NW
bc48334269 feat(admin): draggable dashboard panels + business KPI redesign
- Dashboard: 16 business-focused panels (KPIs, charts, tables, feeds)
- New data queries: AOV, conversion rate, revenue by category, top spenders,
  purchase funnel, 30-day trend, geography, wallet totals
- ApexCharts: 30-day revenue line, category bar, funnel bar, geo bar,
  conversion mini-donut, revenue sparkline
- SortableJS: draggable panels within rows, layout saved to localStorage
- Theme persistence: body classes (nav-dark, header-fixed, etc.) saved to
  localStorage and restored on load, MutationObserver syncs all toggles
- Panel data-panel-id attributes for layout persistence
- All panels use existing SmartAdmin panel-icon/card styling
2026-07-06 19:13:05 +01:00
NW
2a34b40411 fix(admin): button icon visibility and text wrapping
- Add CSS for svg.sa-icon fill on all button variants
- white-space: nowrap + inline-flex + gap for icon buttons
- Quick Actions: d-grid → d-flex flex-wrap for horizontal layout
- btn-secondary → btn-dark for Settings button (icon visibility)
2026-07-06 19:00:25 +01:00