Storage Configuration Guide (Data Storage)
📖 Complete guide to creating and configuring data storage for flexible management of settings, limits, features, and user data.
📑 Table of Contents
🎯 Purpose
Storage — flexible key-value data storage system that allows:
- Store tenant settings (limits, parameters, configurations)
- Manage tenant features and capabilities
- Store user data and settings
- Flexibly add new attributes without DB schema changes
- Automatically synchronize data from configuration to DB
Advantages:
- ✅ Flexibility — can add new attributes without DB migrations
- ✅ Organization — data grouped by logical files (Tenant Storage) or by users (User Storage)
- ✅ Simplicity — simple data types (strings, numbers, bool, arrays, objects)
- ✅ Automatic type conversion on read
- ✅ Data isolation — user data isolated by tenants
🔀 Storage Types
System supports two storage types:
Tenant Storage
- Purpose: Store tenant settings and configurations
- Structure: Grouping by
group_key(settings, limits, features, etc.) - Data source: YAML files in
storage/folder of tenant configuration - Synchronization: Automatic synchronization from configuration to DB
- Key:
(tenant_id, group_key, key)
User Storage
- Purpose: Store user data and settings
- Structure: Flat structure without groups (
{key: value}) - Data source: Set programmatically via scenario actions
- Synchronization: Not synchronized with configuration, managed only via actions
- Key:
(tenant_id, user_id, key)
Differences:
| Characteristic | Tenant Storage | User Storage |
|---|---|---|
| Grouping | By group_key | Without groups |
| Data source | YAML files | Scenario actions |
| Synchronization | Automatic from configuration | Manual management |
| Usage scope | Tenant settings | User data |
| Structure | {group_key: {key: value}} | {key: value} |
🏢 Tenant Storage
Storage Structure
Location
Tenant Storage located in storage/ folder inside tenant configuration:
tenant_101/
├── tg_bot.yaml
├── storage/ # Storage folder
│ ├── settings.yaml # Settings group
│ ├── limits.yaml # Limits group
│ └── features.yaml # Features group
└── scenarios/
└── ...File Structure
Each file in storage/ folder contains attribute groups. File name doesn't affect grouping — it's just way to logically organize configuration.
Example:
# storage/config.yaml - file name doesn't matter
settings:
max_users: 100
max_storage: 500
default_language: "en"
limits:
daily_requests: 1000
max_file_size: 10485760All files from storage/ folder combined during configuration synchronization.
Database Synchronization
Synchronization Mechanism
During Tenant Storage configuration synchronization system performs following actions:
- Get groups from DB — system gets list of all existing groups in database
- Determine groups for synchronization — compares groups from configuration with groups in DB
- Delete synchronized groups — deletes only groups present in configuration
- Load data from config — all groups from configuration loaded to database
Important Features
- Groups from configuration — fully synchronized (old data deleted, new loaded)
- Groups absent in config — remain untouched in database (not deleted automatically)
- New groups — automatically created during synchronization
- Full config match — synchronized groups fully match configuration
Example:
If DB has groups: settings, limits, features, old_group
And config has only: settings, limits, features
Then during synchronization:
- ✅
settings,limits,features— will be deleted and reloaded from config - ✅
old_group— will remain untouched in DB (won't be deleted)
To delete group from DB use delete_storage action in scenario or manually delete all group records.
File Organization
Organization Principles
- Files for logical grouping — can create any number of files for convenient configuration organization
- File combining — all files from
storage/folder combined during synchronization - Attribute groups — inside file use
{group_key: {key: value}}structure to group related attributes - Key uniqueness — keys must be unique within group (
group_key)
Structure Example
storage/
├── config.yaml # Arbitrary file name
│ settings:
│ max_users: 100
│ default_language: "en"
│ limits:
│ daily_requests: 1000
│ max_file_size: 10485760
│
└── additional.yaml # Another file for additional settings
features:
enable_premium: true
enable_api: falseUsage Example
File: storage/config.yaml (file name can be any)
# Basic settings
settings:
max_users: 100 # Integer
max_storage: 500 # Integer
default_language: "en" # String
allowed_languages: ["ru", "en", "de"] # String array
enable_notifications: true # Boolean
maintenance_mode: false # Boolean
# Limits and restrictions
limits:
daily_requests: 1000 # Integer
max_file_size: 10485760 # Integer (10 MB in bytes)
rate_limit_per_minute: 30 # Integer
discount_percentage: 10.5 # Float
price_tiers: [9.99, 19.99, 29.99] # Float array
# Features and capabilities
features:
enable_premium: true # Boolean
enable_api: false # Boolean
enable_webhooks: false # Boolean
supported_regions: ["eu", "us", "asia"] # String array
# Tariffs and prices
pricing:
base_price: 9.99 # Float
premium_price: 29.99 # Float
trial_days: 14 # Integer👤 User Storage
Purpose
User Storage — user data storage that allows:
- Store user settings and preferences
- Save user state between sessions
- Manage personal user data
- Isolate user data by tenants
Structure
User Storage has flat structure without groups:
{key: value}Example:
language: "en"
theme: "dark"
messages_sent: 150
favorite_colors: ["red", "blue", "green"]
user_preferences:
language: "en"
theme: "dark"
notifications: trueFeatures
- Tenant isolation: User data tied to
tenant_idanduser_id - Flat structure: No grouping by
group_key, onlykey: value - Programmatic management: Data set and changed only via scenario actions
- Automatic context:
tenant_idanduser_idautomatically available from event context
Usage Example
Setting values via scenario:
set_user_preferences:
description: "Set user preferences"
trigger:
- event_type: "callback"
callback_data: "set_preferences"
step:
- action: "set_user_storage"
params:
key: "language"
value: "en"
- action: "set_user_storage"
params:
key: "theme"
value: "dark"
- action: "set_user_storage"
params:
key: "user_preferences"
value:
language: "en"
theme: "dark"
notifications: true
- action: "send_message"
params:
text: "✅ Settings saved!"Getting values:
show_user_preferences:
description: "Show user preferences"
trigger:
- event_type: "callback"
callback_data: "show_preferences"
step:
# Get all values in one request
- action: "get_user_storage"
- action: "send_message"
params:
text: |
👤 <b>Your settings</b>
Language: <code>{_cache.user_storage_values.language|fallback:not set}</code>
Theme: <code>{_cache.user_storage_values.theme|fallback:not set}</code>Note: When requesting specific key (key specified) returns direct value available via {_cache.user_storage_values}. When requesting all values (without key) returns full structure {key: value} available via {_cache.user_storage_values.key}
🔢 Value Types
Supported Types
In both Storage types can use following data types:
- ✅ Strings — text values
- ✅ Integers — integer numbers
- ✅ Floats — floating point numbers
- ✅ Booleans — true/false
- ✅ Arrays — value lists (support simple types and complex structures)
- ✅ JSON objects (dictionaries) — nested data structures
- ✅ Nested structures — dictionary arrays, dictionaries with arrays, nested dictionaries
How to Specify Values
In YAML files (for Tenant Storage) and when setting values (for User Storage) can write values in their natural form — system automatically determines type:
settings:
max_users: 100 # Integer
price: 9.99 # Float
enable_feature: true # Boolean
default_language: "en" # String
allowed_languages: ["ru", "en", "de"] # String array
price_tiers: [9.99, 19.99, 29.99] # Float array
# JSON objects (dictionaries)
admin_config:
id: 1133574222
name: "Admin"
role: "admin"
permissions: ["read", "write"]
# Dictionary arrays (structure arrays)
users:
- id: 1
name: "User 1"
role: "user"
- id: 2
name: "User 2"
role: "admin"
# Nested structures
nested_data:
level1:
level2:
value: "deep nested"
items: [1, 2, 3]Boolean values:
true,false(boolean values in YAML)"true","false"(strings - will be converted to boolean values)
Arrays:
- Can contain simple types: strings, numbers, float, bool
- Can contain complex structures: dictionaries, nested arrays
- Array elements automatically converted to appropriate types on read
- Access to elements via placeholders:
{_cache.storage_values.settings.allowed_languages[0]}
Dictionaries (JSON objects):
- Can contain any supported value types
- Support nesting up to 10 levels deep
- Access to fields via dot notation:
{_cache.storage_values.settings.admin_config.name} - Combination with arrays:
{_cache.storage_values.settings.users[0].name}
🎬 Usage in Scenarios
Available Actions
Tenant Storage
In scenarios following actions available for working with Tenant Storage:
get_storage— get tenant storage values (one value, group or all values). Supports parametersgroup_key,key,group_key_pattern,key_patternfor flexible searchget_storage_groups— get list of unique group keys for tenantset_storage— set values in tenant storage. Supports mixed approach: full structure viavaluesor partial viagroup_key/key/valuedelete_storage— delete values or groups from tenant storage. Supports deleting specific value, group or by patterns
User Storage
In scenarios following actions available for working with User Storage:
get_user_storage— get user storage values (one value or all values). Supports parameterskeyandkey_patternfor flexible searchset_user_storage— set values in user storage. Supports mixed approach: full structure viavaluesor partial viakey/valuedelete_user_storage— delete values from user storage. Supports deleting specific value, all values or by pattern
Important:
- Parameters
tenant_idanduser_idautomatically available from event context and don't require explicit specification in scenarios - Data from action
response_dataautomatically saved to_cache(flat caching by default) - Access to data via placeholders:
{_cache.storage_values}for Tenant Storage and{_cache.user_storage_values}for User Storage - For Tenant Storage when requesting only group (
group_keyspecified,keynot specified): returns group structure{key: value}(without group_key nesting), available via{_cache.storage_values.{key}} - For Tenant Storage when requesting specific key (
group_keyandkeyspecified): returns direct value available via{_cache.storage_values} - For Tenant Storage when requesting all values (nothing specified): returns full structure
{group_key: {key: value}}available via{_cache.storage_values.{group_key}.{key}} - For User Storage when requesting all values:
{_cache.user_storage_values.{key}} - For User Storage when requesting specific key:
{_cache.user_storage_values}(direct value)
Example 1: Getting and Displaying Value
Simple example — getting one value:
show_settings:
description: "Show tenant settings"
trigger:
- event_type: "message"
event_text: "/settings"
step:
# Get value from storage
- action: "get_storage"
params:
group_key: "settings"
key: "max_users"
# Use obtained value in message
- action: "send_message"
params:
text: |
📊 <b>Settings</b>
Max users: <code>{_cache.storage_values}</code>Value access:
- When requesting specific key (
group_keyandkeyspecified) returns direct value (primitive or object as is) available via{_cache.storage_values} - In example above:
{_cache.storage_values}returns value100(or othermax_usersvalue) - When requesting only group (
group_keyspecified,keynot specified) returns group structure{key: value}available via{_cache.storage_values.{key}}
Example 2: Getting Group Values
Getting all group values in one request:
show_all_settings:
description: "Show all settings"
trigger:
- event_type: "callback"
callback_data: "show_settings"
step:
# Get entire settings group in one request
- action: "get_storage"
params:
group_key: "settings"
# Use all group values
- action: "send_message"
params:
text: |
⚙️ <b>All settings</b>
Max users: <code>{_cache.storage_values.max_users}</code>
Max storage: <code>{_cache.storage_values.max_storage}</code>
Default language: <code>{_cache.storage_values.default_language}</code>
Notifications: {_cache.storage_values.enable_notifications|true|value:✅|fallback:❌}Advantages:
- One request instead of multiple separate requests
- All group values loaded at once
- More efficient for displaying group of related settings
- When requesting only
group_keyreturns group structure{key: value}(without group_key nesting) available via{_cache.storage_values.{key}}
Example 3: Working with User Storage
Getting and setting user data:
# Setting user preferences
set_user_settings:
description: "Set user preferences"
trigger:
- event_type: "callback"
callback_data: "set_settings"
step:
- action: "set_user_storage"
params:
key: "language"
value: "en"
- action: "set_user_storage"
params:
key: "theme"
value: "dark"
- action: "set_user_storage"
params:
key: "messages_sent"
value: 0
- action: "send_message"
params:
text: "✅ Settings saved!"
# Getting all user data
show_user_data:
description: "Show all user data"
trigger:
- event_type: "callback"
callback_data: "show_data"
step:
- action: "get_user_storage"
- action: "send_message"
params:
text: |
👤 <b>Your data</b>
Language: <code>{_cache.user_storage_values.language|fallback:not set}</code>
Theme: <code>{_cache.user_storage_values.theme|fallback:not set}</code>
Messages sent: <code>{_cache.user_storage_values.messages_sent|fallback:0}</code>
# Deleting user data
delete_user_data:
description: "Delete user data"
trigger:
- event_type: "callback"
callback_data: "delete_data"
step:
- action: "delete_user_storage"
params:
key: "language"
- action: "send_message"
params:
text: "🗑️ Data deleted!"User Storage features:
tenant_idanduser_idautomatically available from event context- Data isolated by tenants and users
- No grouping — flat structure
{key: value} - Data set only via scenario actions
Example 4: YAML Formatting
Displaying data in readable YAML format:
show_formatted_storage:
description: "Show storage in YAML format"
trigger:
- event_type: "callback"
callback_data: "show_formatted"
step:
# Getting group with formatting
- action: "get_storage"
params:
group_key: "settings"
format: true
- action: "send_message"
params:
text: |
⚙️ <b>Settings (YAML format)</b>
<pre>{_cache.formatted_text}</pre>format parameter:
- Available for all data getting actions (
get_storage,get_user_storage) - When
format: truefieldformatted_textadded toresponse_datawith data in YAML format - Access to formatted text via
{_cache.formatted_text} - Convenient for displaying complex data structures to users