- Connections dashboard with add/remove flow and background health checks - VK OAuth connection with profile info and health monitoring - Sync configuration page with master toggle and filter summary - Catalog browser with store/group/product tables, filter management, CSV export - Alembic migrations for all new tables - run/read_config.py for shell sync script DB integration - CHANGELOG.md updated for v1.8.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.5 KiB
Sync Configuration Feature
Context
EvoSync syncs product catalogs from Evotor → VK. Currently sync runs as a shell-based cron service with a hardcoded store ID and a flat-file whitelist of group names (vk/whitelist). This doesn't support multi-user or per-user configuration.
Users need a web UI to:
- Enable/disable the whole sync process
- Configure which stores, groups, and products to sync (whitelist/blacklist)
- Explicitly confirm before sync starts
The web app will store config in DB; the shell sync service will read from DB instead of flat files.
Data Model
SyncConfig — per-user master switch
tablename: "sync_configs"
- id (Integer, PK)
- user_id (Integer, FK users.id CASCADE, unique)
- is_enabled (Boolean, default=False) # master on/off
- confirmed_at (DateTime, nullable) # NULL = never confirmed/started
- created_at (DateTime, server_default=now)
- updated_at (DateTime, server_default=now, onupdate=now)
Relationship: User.sync_config (one-to-one)
SyncFilter — stores, groups, products filter rules
tablename: "sync_filters"
- id (Integer, PK)
- sync_config_id (Integer, FK sync_configs.id CASCADE)
- entity_type (String, enum: "store", "group", "product")
- entity_id (String 255) # Evotor UUID
- entity_name (String 255) # human-readable, cached
- filter_mode (String, enum: "include", "exclude")
- parent_entity_id (String 255, nullable) # store_id for groups, group_id for products
- created_at (DateTime, server_default=now)
UniqueConstraint: (sync_config_id, entity_type, entity_id)
Relationship: SyncConfig.filters (one-to-many)
Filter Logic
The filter model uses explicit include/exclude rules with these semantics:
- No rules for an entity type = sync everything of that type (default permissive)
- Any "include" rule exists for a type = ONLY sync included entities (whitelist mode)
- Only "exclude" rules for a type = sync everything EXCEPT excluded (blacklist mode)
- Hierarchy: store filters → group filters → product filters. If a store is excluded, all its groups/products are excluded regardless of their individual rules.
Plan
1. New Models — web/models.py
Add SyncConfig and SyncFilter as described above. Add sync_config relationship to User.
2. Alembic Migration
Create sync_configs and sync_filters tables.
3. Evotor API Helper — web/evotor_api.py (new)
Async functions to fetch data from Evotor API using a user's stored access token:
async def fetch_stores(access_token: str) -> list[dict]:
"""GET https://api.evotor.ru/stores → [{"id": "uuid", "name": "..."}]"""
async def fetch_groups(access_token: str, store_id: str) -> list[dict]:
"""GET https://api.evotor.ru/stores/{store_id}/product-groups → [{"id": "uuid", "name": "..."}]"""
async def fetch_products(access_token: str, store_id: str) -> list[dict]:
"""GET https://api.evotor.ru/stores/{store_id}/products → [{"id": "uuid", "name": "...", "parent_id": "..."}]"""
Uses httpx.AsyncClient. Returns simplified dicts. Raises on auth failure.
4. Sync Config Route — web/routes/sync.py (new)
GET /sync — Main sync configuration page.
- Requires auth + active Evotor connection
- Loads
SyncConfig(creates default if missing) - Shows: master enable/disable toggle, confirm button, link to filter config
POST /sync/toggle — Enable/disable sync.
- Toggles
is_enabled. If enabling for the first time and no filters configured, stays on page with message to configure filters first.
POST /sync/confirm — Confirm and start sync.
- Sets
confirmed_at = now(). Only works ifis_enabled=Trueand at least one store is configured.
Filter management is handled by the Catalog Browser (see docs/plans/catalog-browser.md).
The /catalog page provides table views of stores, groups, and products with inline filter toggle actions. No separate /sync/stores, /sync/groups, /sync/products routes needed.
5. Templates
web/templates/sync.html — Main sync page:
- Card with master toggle (on/off switch)
- Status: "Не настроено" / "Настроено, ожидает подтверждения" / "Активна"
- Warning if Evotor not connected (link to /evotor)
- Warning if VK not connected (link to /vk)
- "Настроить фильтры" button →
/catalog(catalog browser) - "Подтвердить и запустить" button (disabled until filters configured)
- Summary of current filter rules (X stores, Y groups, Z products)
6. Navbar / Navigation
Add "Синхронизация" link to navbar (for logged-in users), or add it as a card on the /connections page since sync depends on connections.
7. Register Route — web/main.py
from web.routes import sync
app.include_router(sync.router)
8. Shell Script DB Integration
Modify the sync service to read configuration from DB instead of flat files:
- Add a Python helper script
run/read_config.pythat queriessync_configs+sync_filtersfor a given user and outputs JSON config - Shell scripts call this helper to get: enabled flag, store IDs, whitelisted/blacklisted group names, product exclusions
- The sync service only runs for users where
is_enabled=TrueANDconfirmed_at IS NOT NULL - Replaces the flat
vk/whitelistfile
Files Summary
| File | Action |
|---|---|
web/models.py |
Modify — add SyncConfig, SyncFilter + User relationship |
web/routes/sync.py |
Create — sync config routes (toggle, confirm) |
web/templates/sync.html |
Create — main sync config page |
web/templates/base.html |
Modify — add sync nav link |
web/main.py |
Modify — register sync router |
run/read_config.py |
Create — DB config reader for shell scripts |
| Alembic migration | Create — sync_configs + sync_filters tables |
Verification
- Run
alembic upgrade head - Visit
/syncwithout Evotor connection → shows warning to connect first - Connect Evotor, visit
/sync→ shows disabled state, "Настроить фильтры" button - Go to
/sync/stores→ fetches live stores from Evotor API, shows checkboxes - Select stores, save → drill into groups, select groups, save → drill into products
- Back to
/sync→ shows summary of configured filters - Enable sync toggle → confirm →
confirmed_atset - Verify
run/read_config.pyoutputs correct JSON for the user's config - Disable sync →
is_enabled=False, sync service stops processing this user