{"id":47617239,"url":"https://github.com/dizzzable/altshop","last_synced_at":"2026-04-12T12:09:47.765Z","repository":{"id":327956698,"uuid":"1112588060","full_name":"dizzzable/altshop","owner":"dizzzable","description":"Telegram bot, FastAPI backend, and React web app for selling VPN subscriptions with Remnawave integration.","archived":false,"fork":false,"pushed_at":"2026-04-09T21:49:09.000Z","size":4701,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T23:24:21.787Z","etag":null,"topics":["aiogram","docker-compose","fastapi","nginx","postgresql","react","remnawave","subscriptions","telegram-bot","valkey","vite","vpn"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dizzzable.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-08T20:44:14.000Z","updated_at":"2026-04-09T21:49:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dizzzable/altshop","commit_stats":null,"previous_names":["dizzzable/altshop"],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/dizzzable/altshop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dizzzable%2Faltshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dizzzable%2Faltshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dizzzable%2Faltshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dizzzable%2Faltshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dizzzable","download_url":"https://codeload.github.com/dizzzable/altshop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dizzzable%2Faltshop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31641493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiogram","docker-compose","fastapi","nginx","postgresql","react","remnawave","subscriptions","telegram-bot","valkey","vite","vpn"],"created_at":"2026-04-01T21:37:10.753Z","updated_at":"2026-04-10T12:05:47.137Z","avatar_url":"https://github.com/dizzzable.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003eAltShop\u003c/h1\u003e\n  \u003cp\u003e\u003cstrong\u003eTelegram bot, FastAPI API, and React web app for selling VPN subscriptions with Remnawave integration.\u003c/strong\u003e\u003c/p\u003e\n  \u003cp\u003eENGLISH | \u003ca href=\"./README.ru_RU.md\"\u003eРУССКИЙ\u003c/a\u003e\u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/dizzzable/altshop/actions/workflows/ci.yml\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/dizzzable/altshop/ci.yml?branch=main\u0026label=CI\u0026logo=githubactions\u0026logoColor=white\" alt=\"CI status\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/dizzzable/altshop/actions/workflows/release.yml\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/dizzzable/altshop/release.yml?label=Release\u0026logo=githubactions\u0026logoColor=white\" alt=\"Release status\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/dizzzable/altshop/releases/latest\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/v/release/dizzzable/altshop?display_name=tag\u0026logo=github\" alt=\"Latest release\" /\u003e\n    \u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Python-3.12-3776AB?logo=python\u0026logoColor=white\" alt=\"Python 3.12\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/FastAPI-Backend-009688?logo=fastapi\u0026logoColor=white\" alt=\"FastAPI Backend\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/React-19-149ECA?logo=react\u0026logoColor=white\" alt=\"React 19\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Docker-Compose-2496ED?logo=docker\u0026logoColor=white\" alt=\"Docker Compose\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/PostgreSQL-17-4169E1?logo=postgresql\u0026logoColor=white\" alt=\"PostgreSQL 17\" /\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/dizzzable/altshop\" alt=\"MIT License\" /\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003e [!IMPORTANT]\n\u003e The current `main` branch does not ship a standalone web admin panel in the default runtime stack.\n\u003e Administrative control lives in the Telegram dashboard and operator flows inside the bot.\n\n\u003e [!TIP]\n\u003e If you already know `snoups/remnashop`, the deployment flow here should feel familiar.\n\u003e The environment setup, Docker stack, and Nginx wiring are intentionally close in day-to-day operation.\n\n## ✨ What AltShop Is\n\nAltShop is a production-oriented stack for selling and servicing VPN subscriptions. It combines:\n\n- a Telegram bot on `aiogram`\n- a FastAPI backend with cookie-based web authentication\n- a separate React/Vite web portal\n- PostgreSQL, Valkey, Taskiq workers, and Nginx\n- Remnawave integration for subscription lifecycle and synchronization\n\nThe current project surface is documented in [`docs/README.md`](./docs/README.md).\n\n## 👥 Who Gets What\n\n| Role | What they get |\n| --- | --- |\n| Service owner | Product catalog, branding, access rules, payment gateways, referrals, partner mechanics, backups, and Remnawave sync |\n| Admin/operator | Telegram dashboard for users, plans, gateways, notifications, broadcasts, imports, partner withdrawals, and operational settings |\n| Buyer | Telegram and web purchase flows, trial access, device management, promocodes, referral rewards, partner cabinet, and account recovery |\n\n## 🛍️ What Buyers Actually Get\n\nAfter deployment, a customer can:\n\n- sign in through username/password or Telegram auth\n- see access requirements before registration\n- accept rules and pass channel gating if enabled\n- open the web cabinet and view subscriptions, transactions, and notifications\n- buy a new subscription, renew an existing one, or add another one\n- get a trial subscription if your project allows it\n- choose a plan, duration, device type, payment method, and payment asset\n- manage devices, generate connection links, and revoke old devices\n- activate promocodes and review activation history\n- link Telegram to a web account\n- verify email, reset password by code or link, and change password in profile\n- use referral links, referral QR codes, and points exchange flows\n- open the partner cabinet, inspect earnings, and request withdrawals\n\n## 🛠️ What The Admin Side Can Manage\n\nThe built-in Telegram dashboard currently covers:\n\n- access modes: `PUBLIC`, `INVITED`, `PURCHASE_BLOCKED`, `REG_BLOCKED`, `RESTRICTED`\n- rules acceptance and mandatory channel subscription gating\n- user search, recent users, blacklist, and detailed user cards\n- subscription editing and assignment changes\n- plan configuration, durations, prices, availability, and squads\n- promocode creation and reward configuration\n- payment gateway activation, credentials, webhook settings, display order, and default currency\n- referral program rules, eligible plans, reward strategy, and points exchange setup\n- partner program percentages, tax model, gateway commissions, minimum withdrawal, and withdrawal review queue\n- multi-subscription limits\n- branding texts, project name, web title, verification messages, and banners\n- user and system notification toggles\n- broadcasts and audience segmentation\n- backup creation, restore, retention, and Telegram delivery\n- Remnawave integration views and import or sync flows\n- statistics and operational snapshots\n\n## ⚙️ What You Can Configure\n\n### 🔐 Access And Product Logic\n\n- public, invited, purchase-blocked, registration-blocked, or restricted entry mode\n- required rules acceptance\n- required Telegram channel subscription\n- single-subscription or multi-subscription mode\n- locale defaults and enabled locales\n\n### 💳 Catalog And Pricing\n\n- plans and durations\n- plan ordering and availability\n- renew vs additional purchase flows\n- default settlement currency\n- per-gateway pricing behavior\n\n### 💸 Payments\n\nThe current codebase supports 14 gateway types:\n\n- Telegram Stars\n- YooKassa\n- YooMoney\n- Cryptomus\n- Heleket\n- CryptoPay\n- T-Bank\n- Robokassa\n- Stripe\n- Mulenpay\n- CloudPayments\n- Pal24\n- Wata\n- Platega\n\n`Telegram Stars` is the only gateway enabled by default. The others must be configured and activated by the operator.\n\n### 🎁 Referral And Partner Mechanics\n\n- referral reward type: points or extra days\n- reward strategy and eligible plans\n- points exchange into subscription days, gift subscriptions, discounts, and traffic\n- partner level percentages\n- gateway commission model\n- tax percent\n- minimum withdrawal amount\n\n### 🎨 Branding And Support Surface\n\n- project name and web title\n- localized verification and recovery messages\n- support username links\n- banners and localized text content\n\n### 🧱 Infrastructure\n\n- web domain and proxy trust rules\n- web auth JWT secret\n- CORS origins\n- SMTP for verify and reset flows\n- backup retention and Telegram backup delivery\n\n## 🚀 Production Setup\n\n### 1. Copy the environment template\n\n```bash\ncp .env.example .env\n```\n\n### 2. Fill required secrets\n\nAt minimum:\n\n- `APP_DOMAIN`\n- `APP_CRYPT_KEY`\n- `BOT_TOKEN`\n- `BOT_SECRET_TOKEN`\n- `BOT_DEV_ID`\n- `BOT_SUPPORT_USERNAME`\n- `WEB_APP_JWT_SECRET`\n- `REMNAWAVE_TOKEN`\n- `REMNAWAVE_WEBHOOK_SECRET`\n- `DATABASE_PASSWORD`\n- `REDIS_PASSWORD`\n\n### 3. Configure web and proxy behavior correctly\n\nFor a stable production setup:\n\n- set `APP_ORIGINS` to the real frontend origin list used by browsers\n- keep `APP_TRUSTED_PROXY_IPS` aligned with the actual reverse proxy addresses\n- set `WEB_APP_URL` if the frontend is served from a dedicated origin\n- do not set `BOT_MINI_APP=true`; use `false`, an empty value, or the exact web app URL\n\n### 4. Configure optional flows\n\nIf you want email verification and password recovery:\n\n- set `EMAIL_ENABLED=true`\n- fill `EMAIL_HOST`\n- fill `EMAIL_FROM_ADDRESS`\n- add SMTP credentials if required by your provider\n\n### 5. Issue TLS files on the VPS\n\nRecommended target paths for the pull-based VPS stack:\n\n```bash\nacme.sh --issue --standalone -d '\u003cdomain\u003e' \\\n  --key-file /opt/altshop/nginx/remnabot_privkey.key \\\n  --fullchain-file /opt/altshop/nginx/remnabot_fullchain.pem\n```\n\n### 6. Make GHCR packages public after the first release\n\nThe release workflow publishes:\n\n- `ghcr.io/dizzzable/altshop-backend`\n- `ghcr.io/dizzzable/altshop-nginx`\n\nIf GitHub creates them as private packages on the first push, switch both packages to `Public` once in the repository Packages settings. After that, the VPS can pull updates without `docker login`.\n\n### 7. Pull and start the VPS stack\n\n```bash\ndocker compose -f docker-compose.prod.yml pull\ndocker compose -f docker-compose.prod.yml up -d\n```\n\nIf the VPS was originally deployed manually and does not have `docker-compose.prod.yml` yet, bootstrap it in one command:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/dizzzable/altshop/main/scripts/bootstrap-prod-vps.sh | sh\n```\n\nOptional production overrides:\n\n- `ALTSHOP_IMAGE_TAG` to pin a backend release instead of `latest`\n- `ALTSHOP_NGINX_IMAGE_TAG` to pin an nginx/web release instead of `latest`\n- `ALTSHOP_DB_VOLUME_NAME` and `ALTSHOP_REDIS_VOLUME_NAME` if the old server uses custom named Docker volumes\n- `NGINX_SSL_FULLCHAIN_PATH` and `NGINX_SSL_PRIVKEY_PATH` if your certificates live outside `/opt/altshop/nginx`\n\n### 8. Validate the public surface\n\n- `https://\u003cAPP_DOMAIN\u003e/webapp/`\n- `https://\u003cAPP_DOMAIN\u003e/api/v1/auth/branding`\n\n### 9. Complete first operator setup in the bot\n\nRecommended first actions:\n\n1. Review access mode and channel or rules requirements.\n2. Create or verify plans, durations, and pricing.\n3. Activate and configure payment gateways.\n4. Review branding and support links.\n5. Configure referral and partner settings if you use them.\n6. Check backup settings and notification behavior.\n\n### Local/manual build fallback\n\nIf you intentionally deploy from local sources instead of GHCR, keep using the existing build-based stack:\n\n```text\nnginx/fullchain.pem\nnginx/privkey.key\n```\n\n```bash\ndocker compose up --build\n```\n\n## 🧩 Runtime Stack\n\nThe default Docker stack contains 7 services:\n\n- `webapp-build`\n- `altshop-nginx`\n- `altshop-db`\n- `altshop-redis`\n- `altshop`\n- `altshop-taskiq-worker`\n- `altshop-taskiq-scheduler`\n\nPublic surface:\n\n- `/webapp/` for the SPA\n- `/assets/` for frontend assets\n- `/api/v1/*` for the backend API\n- `/telegram` for Telegram webhook traffic\n- `/remnawave` for Remnawave webhook traffic\n- `/payments/*` for payment webhooks\n\n## 🗂️ Public Repository Layout\n\n```text\naltshop/\n|-- src/                 backend application code\n|-- web-app/             React/Vite frontend\n|-- assets/              translations and default runtime assets\n|-- nginx/               Nginx config and TLS mount paths\n|-- docs/                canonical and historical documentation\n|-- scripts/             maintenance and audit helpers\n|-- docker-compose.yml   default deployment contract\n`-- Dockerfile           backend container image\n```\n\n## 🔒 What Stays Local\n\nThis public GitHub mirror intentionally excludes internal-only QA artifacts.\n\n- `tests/` stays local and is not required for runtime deployment\n- temporary `mypy-wave*.ini` files stay local and are not part of the product\n- GitHub Actions here only validates the public frontend surface\n- Ruff configuration lives in [`pyproject.toml`](./pyproject.toml)\n- there is no separate `ruff.ini` in this repository\n\n## 🧪 Optional Local Development\n\nPublic mirror checks:\n\n```bash\nuv sync --locked --group dev\nuv run python -m ruff check src\nuv run python -m mypy src\n```\n\nFrontend:\n\n```bash\ncd web-app\nnpm ci\nnpm run lint\nnpm run type-check\nnpm run build\n```\n\nIf you work in the private internal workspace, you can additionally run the local backend `pytest` suite there.\n\n## 📚 Documentation\n\nStart here:\n\n- [`CHANGELOG.md`](./CHANGELOG.md)\n- [`docs/README.md`](./docs/README.md)\n\nCanonical documents:\n\n- [`docs/01-project-overview.md`](./docs/01-project-overview.md)\n- [`docs/05-api.md`](./docs/05-api.md)\n- [`docs/06-bot-dialogs.md`](./docs/06-bot-dialogs.md)\n- [`docs/07-payment-gateways.md`](./docs/07-payment-gateways.md)\n- [`docs/08-configuration.md`](./docs/08-configuration.md)\n- [`docs/09-deployment.md`](./docs/09-deployment.md)\n- [`docs/10-development.md`](./docs/10-development.md)\n\n## ⚖️ License\n\nMIT. See [`LICENSE`](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdizzzable%2Faltshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdizzzable%2Faltshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdizzzable%2Faltshop/lists"}