feat: Evotor + VK catalog sync, connections, and store/group filters
- Evotor catalog: background Celery task syncing stores/groups/products from Evotor API; UI pages with per-store and per-group sync toggles - VK connection: manual token + group ID entry with inline test button - Evotor connection: inline test button (calls /stores) - VK catalog: background task syncing VK Market albums and products; separate catalog UI at /vk-catalog/albums - SyncFilter extended to support entity_type=group with parent_entity_id - Migration 0004: vk_cached_albums + vk_cached_products tables - Beat schedule updated to run both refresh_catalog and refresh_vk_catalog - README updated with new schema, routes, tasks, and config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
143
README.md
143
README.md
@@ -1,6 +1,6 @@
|
||||
# EvoSync
|
||||
|
||||
Web service for syncing a product catalog from Evotor POS → VK Market. Users connect their Evotor account and a VK page; products from the cash register then appear automatically in the VK store.
|
||||
Web service for syncing a product catalog from Evotor POS → VK Market. Users connect their Evotor account and a VK community; products from the cash register then appear automatically in the VK store.
|
||||
|
||||
---
|
||||
|
||||
@@ -23,20 +23,20 @@ Web service for syncing a product catalog from Evotor POS → VK Market. Users c
|
||||
|
||||
### Services
|
||||
|
||||
| Service | Image / Dockerfile | Purpose | External port |
|
||||
|----------|---------------------|----------------------------------------------|---------------|
|
||||
| Service | Image / Dockerfile | Purpose | External port |
|
||||
|----------|---------------------|-----------------------------------------------|---------------|
|
||||
| `web` | `Dockerfile.web` | FastAPI app, runs Alembic migrations on start | 8080 → 8000 |
|
||||
| `worker` | `Dockerfile.web` | Celery worker (sync, health, notifications…) | — |
|
||||
| `beat` | `Dockerfile.web` | Celery Beat — periodic task scheduler | — |
|
||||
| `flower` | `Dockerfile.web` | Celery queue monitoring UI | 5555 |
|
||||
| `db` | `mariadb:11.4` | Primary relational database | — |
|
||||
| `redis` | `redis:7-alpine` | Celery broker and result backend | — |
|
||||
| `worker` | `Dockerfile.web` | Celery worker (sync, health, notifications…) | — |
|
||||
| `beat` | `Dockerfile.web` | Celery Beat — periodic task scheduler | — |
|
||||
| `flower` | `Dockerfile.web` | Celery queue monitoring UI | 5555 |
|
||||
| `db` | `mariadb:11.4` | Primary relational database | — |
|
||||
| `redis` | `redis:7-alpine` | Celery broker and result backend | — |
|
||||
|
||||
### Stack
|
||||
|
||||
- **Python 3.12**, FastAPI 0.115, Uvicorn
|
||||
- **SQLAlchemy 2** + Alembic, MariaDB (PyMySQL)
|
||||
- **Celery 5** + Redis
|
||||
- **Celery 5** + Redis — background tasks, periodic catalog sync
|
||||
- **Jinja2** — server-side HTML rendering (`web/templates/`)
|
||||
- **Pydantic Settings** — configuration from env vars / `.env`
|
||||
- bcrypt — password hashing
|
||||
@@ -46,25 +46,62 @@ Web service for syncing a product catalog from Evotor POS → VK Market. Users c
|
||||
|
||||
## Database Schema
|
||||
|
||||
| Table | Purpose |
|
||||
|----------------------|--------------------------------------------------------------------------------|
|
||||
| `users` | User accounts (roles: system / admin / user; statuses: pending / active / suspended) |
|
||||
| `evotor_connections` | User ↔ Evotor link (access_token, api_token returned to Evotor webhooks) |
|
||||
| `vk_connections` | User ↔ VK OAuth link |
|
||||
| `sync_configs` | Per-user sync settings |
|
||||
| `sync_filters` | Product / group inclusion/exclusion filters |
|
||||
| `cached_stores` | Cached list of Evotor stores |
|
||||
| `cached_groups` | Cached Evotor product groups |
|
||||
| `cached_products` | Cached Evotor product catalog |
|
||||
| `roles` | RBAC roles |
|
||||
| `permissions` | RBAC permissions |
|
||||
| `role_permissions` | M2M: role ↔ permission |
|
||||
| `user_roles` | M2M: user ↔ role |
|
||||
| Table | Purpose |
|
||||
|-----------------------|--------------------------------------------------------------------------------------|
|
||||
| `users` | User accounts (roles: system / admin / user; statuses: pending / active / suspended) |
|
||||
| `evotor_connections` | User ↔ Evotor link (access_token, api_token returned to Evotor webhooks) |
|
||||
| `vk_connections` | User ↔ VK link (user access token + VK community ID) |
|
||||
| `sync_configs` | Per-user sync settings |
|
||||
| `sync_filters` | Store / group inclusion filters (entity_type: store / group) |
|
||||
| `cached_stores` | Cached list of Evotor stores |
|
||||
| `cached_groups` | Cached Evotor product groups |
|
||||
| `cached_products` | Cached Evotor product catalog |
|
||||
| `vk_cached_albums` | Cached VK Market albums (product groups) |
|
||||
| `vk_cached_products` | Cached VK Market products |
|
||||
| `roles` | RBAC roles |
|
||||
| `permissions` | RBAC permissions |
|
||||
| `role_permissions` | M2M: role ↔ permission |
|
||||
| `user_roles` | M2M: user ↔ role |
|
||||
|
||||
---
|
||||
|
||||
## Background Tasks
|
||||
|
||||
Periodic tasks run via **Celery Beat** and are executed by the **worker** service.
|
||||
|
||||
| Task | Schedule | Description |
|
||||
|------|----------|-------------|
|
||||
| `web.tasks.catalog.refresh_catalog` | Every `CATALOG_REFRESH_INTERVAL_SECONDS` | Fetches stores, product groups, and products from the Evotor API for every connected user; upserts into `cached_stores`, `cached_groups`, `cached_products` |
|
||||
| `web.tasks.vk_catalog.refresh_vk_catalog` | Every `CATALOG_REFRESH_INTERVAL_SECONDS` | Fetches Market albums and products from VK API for every connected user; upserts into `vk_cached_albums`, `vk_cached_products` |
|
||||
|
||||
**Evotor sync sequence per user:**
|
||||
1. `GET /stores` → upsert `cached_stores`
|
||||
2. For each store: `GET /stores/{id}/product-groups` → upsert `cached_groups`
|
||||
3. For each store: `GET /stores/{id}/products` → upsert `cached_products`
|
||||
|
||||
**VK sync sequence per user:**
|
||||
1. `market.getAlbums` → upsert `vk_cached_albums`
|
||||
2. `market.get` (extended=1, paginated) → upsert `vk_cached_products` with album membership
|
||||
|
||||
Per-user failures are logged and skipped — one broken token does not block other users.
|
||||
Evotor stores that return `402 Payment Required` (subscription limit) are silently skipped at debug log level.
|
||||
|
||||
---
|
||||
|
||||
## Routes
|
||||
|
||||
### Connections
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|-----------------------------------|------------------------------------------|
|
||||
| GET | `/connections` | View Evotor and VK connection status |
|
||||
| POST | `/connections/evotor` | Save / update Evotor API token manually |
|
||||
| POST | `/connections/evotor/disconnect` | Remove Evotor connection |
|
||||
| POST | `/connections/evotor/test` | Test Evotor connection (JSON) |
|
||||
| POST | `/connections/vk` | Save / update VK token and group ID |
|
||||
| POST | `/connections/vk/disconnect` | Remove VK connection |
|
||||
| POST | `/connections/vk/test` | Test VK connection (JSON) |
|
||||
|
||||
### Public / Authentication
|
||||
|
||||
| Method | Path | Description |
|
||||
@@ -106,11 +143,29 @@ Web service for syncing a product catalog from Evotor POS → VK Market. Users c
|
||||
|
||||
### Evotor Webhooks (Bearer `EVOTOR_WEBHOOK_SECRET`)
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|----------------|------------------------------------------------------------------|
|
||||
| POST | `/user/create` | Evotor creates/links a user and receives an api_token |
|
||||
| POST | `/user/verify` | Evotor verifies user credentials and receives an api_token |
|
||||
| POST | `/user/token` | Evotor delivers its own access_token for a user |
|
||||
| Method | Path | Description |
|
||||
|--------|----------------|-----------------------------------------------------------|
|
||||
| POST | `/user/create` | Evotor creates/links a user; returns api_token |
|
||||
| POST | `/user/verify` | Evotor verifies user credentials; returns api_token |
|
||||
| POST | `/user/token` | Evotor delivers its own access_token for a user |
|
||||
|
||||
### Evotor Catalog (requires session)
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|---------------------------------------------------|--------------------------------------------|
|
||||
| GET | `/catalog` | Redirects to `/catalog/stores` |
|
||||
| GET | `/catalog/stores` | Evotor stores with per-store sync toggle |
|
||||
| GET | `/catalog/stores/{id}/groups` | Product groups with per-group sync toggle |
|
||||
| GET | `/catalog/stores/{id}/products` | Products (filterable by group) |
|
||||
| POST | `/catalog/stores/{id}/toggle` | Enable / disable store sync |
|
||||
| POST | `/catalog/stores/{id}/groups/{gid}/toggle` | Enable / disable group sync |
|
||||
|
||||
### VK Catalog (requires session)
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|---------------------------------------|------------------------------------|
|
||||
| GET | `/vk-catalog/albums` | VK Market albums (product groups) |
|
||||
| GET | `/vk-catalog/albums/{id}/products` | Products in a VK album |
|
||||
|
||||
### API Docs
|
||||
|
||||
@@ -125,22 +180,22 @@ Web service for syncing a product catalog from Evotor POS → VK Market. Users c
|
||||
|
||||
All settings are read from environment variables or a `.env` file:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|------------------------------------|-------------------------------------|--------------------------------------|
|
||||
| `DATABASE_URL` | `mysql+pymysql://…@db:3306/evosync` | MariaDB connection string |
|
||||
| `REDIS_URL` | `redis://redis:6379/0` | Redis connection string |
|
||||
| `SECRET_KEY` | `change-me-in-production` | Session signing key |
|
||||
| `BASE_URL` | `http://localhost:8000` | Public URL of the service |
|
||||
| `EVOTOR_APP_ID` | — | Evotor application ID |
|
||||
| `EVOTOR_WEBHOOK_SECRET` | — | Bearer secret for webhook endpoints |
|
||||
| `JIVOSITE_WIDGET_ID` | — | JivoSite widget ID |
|
||||
| `VK_DEFAULT_PHOTO_PATH` | `/app/default_product.png` | Fallback image path for VK products |
|
||||
| `VK_API_VERSION` | `5.199` | VK API version |
|
||||
| `CATALOG_REFRESH_INTERVAL_SECONDS` | `3600` | Catalog cache refresh interval |
|
||||
| `INVITE_EXPIRE_HOURS` | `48` | Invite link TTL in hours |
|
||||
| `EMAIL_PROVIDER` | `console` | Email provider (console / smtp / …) |
|
||||
| `SMS_PROVIDER` | `console` | SMS provider |
|
||||
| `FLOWER_USER` / `FLOWER_PASSWORD` | `admin` / `changeme` | Basic Auth credentials for Flower |
|
||||
| Variable | Default | Description |
|
||||
|------------------------------------|-------------------------------------|---------------------------------------|
|
||||
| `DATABASE_URL` | `mysql+pymysql://…@db:3306/evosync` | MariaDB connection string |
|
||||
| `REDIS_URL` | `redis://redis:6379/0` | Redis connection string |
|
||||
| `SECRET_KEY` | `change-me-in-production` | Session signing key |
|
||||
| `BASE_URL` | `http://localhost:8000` | Public URL of the service |
|
||||
| `EVOTOR_APP_ID` | — | Evotor application ID |
|
||||
| `EVOTOR_WEBHOOK_SECRET` | — | Bearer secret for webhook endpoints |
|
||||
| `JIVOSITE_WIDGET_ID` | — | JivoSite widget ID |
|
||||
| `VK_DEFAULT_PHOTO_PATH` | `/app/default_product.png` | Fallback image path for VK products |
|
||||
| `VK_API_VERSION` | `5.199` | VK API version |
|
||||
| `CATALOG_REFRESH_INTERVAL_SECONDS` | `3600` | Evotor + VK catalog sync interval (s) |
|
||||
| `INVITE_EXPIRE_HOURS` | `48` | Invite link TTL in hours |
|
||||
| `EMAIL_PROVIDER` | `console` | Email provider (console / smtp / …) |
|
||||
| `SMS_PROVIDER` | `console` | SMS provider |
|
||||
| `FLOWER_USER` / `FLOWER_PASSWORD` | `admin` / `changeme` | Basic Auth credentials for Flower |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user