- added total_disabled and total_limited fields to SubscriptionStatsDto and PlanSubStatsDto - fixed is_unlimited condition: changed or_ to and_ in subscription stats query - excluded DELETED subscriptions from stats queries - fixed PlanSubStatsDto field names: total_subs/active_subs/expired_subs → total/total_active/total_expired - replaced raise ValueError with redirect to Subscription.MAIN when PlanDto missing in dialog data - replaced raise ValueError with redirect to Subscription.MAIN when plan not found on selection - fixed migration 0019: added explicit COMMIT/BEGIN, fixed invalid menu button payloads - fixed broadcast text-too-long translation: $max_limit variable reference - fixed user_name_clean: strip remaining HTML special chars - added limit=50 to get_recent_registered_users call - bumped remnapy to f442fb6 - minor import cleanups across multiple files
#TODO: add custom
Banners
The banners folder contains all banner images.
Banner configuration
You can configure how banners are displayed in the bot using an environment variable:
BOT_USE_BANNERS: Set to true to enable banners, or false to disable them.
Locale support
The banner system supports localized versions. A banner corresponding to the user's locale will be loaded for each user.
How it works:
When loading a banner, the system performs the following search steps:
- User's locale: The system first attempts to find a banner in the folder corresponding to the current user's locale (e.g.,
en). Available locales are defined by theAPP_LOCALESenvironment variable. - Default (inside user’s locale): If the specific banner is not found, the system checks for
default.{format}inside the same locale folder. - Fallback (default locale): If neither the banner nor
default.{format}exists in the user’s locale (or if the locale folder itself is missing), the system searches for the banner in the default locale specified by theAPP_DEFAULT_LOCALEenvironment variable. - Placeholder banner: If a banner is not found in either the user's locale or the default locale, a placeholder banner named
default.jpgwill be used. This file must be located directly in the rootbannersdirectory.
This ensures that even if a specific banner or locale is not found, some banner will always be displayed, preventing empty or missing images.
Supported formats
The following file formats are supported, as defined in /remnashop/src/core/enums.py as BannerFormat:
- JPG
- JPEG
- PNG
- GIF
- WEBP
Banner names
Banner filenames must correspond to the following predefined names, specified in /remnashop/src/core/enums.py as BannerName:
DEFAULT: The default banner, used when a specific banner is not found.MENU: The main menu banner.DASHBOARD: The dashboard banner.SUBSCRIPTION: The subscription banner.REFERRAL: The referral banner.
Example file structure
banners/
├── en/
│ ├── menu.jpg
│ └── dashboard.jpg
├── ru/
│ ├── menu.gif
│ └── dashboard.gif
└── default.jpg
Translations
The translations folder contains all localization text files.
Translation configuration
Supported locales are defined in environment variables:
APP_LOCALES: A list of supported locales. A full list of available locales can be found inremnashop/src/core/enums.pyasLocale.APP_DEFAULT_LOCALE: The default locale to be used if a user's language preference is not specified or not supported.
Key naming convention
All translation keys must follow a unified structure:
{category}-{scope}-{entity}-{action-or-state}
Components
| Part | Description | Example |
|---|---|---|
{category} |
Top-level type of text | btn, msg, ntf |
{scope} |
Logical group or subsystem | user, plan, broadcast, gateway, subscription, access, error, event |
{entity} |
Specific object or sub-entity | content, payment, link, node |
{action-or-state} |
Action or state, in lowercase | created, deleted, empty, invalid, failed, not-found |
Naming rules
- Use lowercase with hyphens (-) — no underscores or spaces.
- Follow the order:
category → scope → entity → action/state-
✅ ntf-broadcast-content-empty
-
✅ btn-user-create
-
✅ msg-plan-deleted-success
-
❌ ntf-content-empty-broadcast
-
❌ btn-create-user
-
❌ msg-plan-success-deleted
-
- Actions — past tense verbs (created, updated, deleted, canceled, failed).
- States — adjectives (empty, invalid, not-found, expired, not-available).
- Limit to 5 segments maximum.
Examples keys
| Purpose | Key |
|---|---|
| Notification: user expired | ntf-user-expired |
| Notification: broadcast empty content | ntf-broadcast-content-empty |
| Button: confirm deletion | btn-plan-confirm-delete |
| Message: plan created successfully | msg-plan-created-success |
| Notification: gateway test failed | ntf-gateway-test-payment-failed |
QR Code Logo
You can customize the appearance of the generated invitation QR code by adding your logo to the center of the code.
- Path:
assets/logo.png - Purpose: If this file exists, the system will use it as a logo, overlaying it in the center of the generated QR code image for branding purposes.
- Format: The logo must be a
PNGfile, preferably with a transparent background.