Files
md2vk/docs/architecture.md
T

5.3 KiB
Raw Blame History

md2vk — Архитектура

Обзор

FastAPI-сервис, публикует Markdown на стену VK через wall.post с format_data. Полный стек: Python 3.12, FastAPI, SQLAlchemy 2.0 async, SQLite, httpx, cryptography (Fernet), Docker.

Компоненты

┌─────────────────────────────── /opt/md2vk (bigbox) ───────────────────────────────┐
│                                                                                   │
│  docker (контейнер md2vk, порт 127.0.0.1:8420)                                    │
│  ┌────────────────────────────────────────────────────────────────────┐           │
│  │ app/main.py            FastAPI entrypoint, lifespan → init_db     │           │
│  │ app/config.py          Settings из env (pydantic-settings)        │           │
│  │ app/database.py        async engine (aiosqlite), get_db           │           │
│  │ app/models.py          ORM: User, VkAccount, Publication          │           │
│  │ app/security.py        Fernet encrypt/decrypt, API-key gen/verify │           │
│  │ app/vk_client.py       httpx-клиент: wall.post, users.get         │           │
│  │ app/converters/markdown_to_vk.py  MD → VK format_data + чанки     │           │
│  │ app/api/v1.py          эндпоинты /api/v1/*                        │           │
│  │ app/api/deps.py        auth по API-ключу (Bearer / тело)          │           │
│  └────────────────────────────────────────────────────────────────────┘           │
│                                                                                   │
│  /data (volume)  → SQLite /data/md2vk.db                                          │
│  /logs  → access.{date}.log  (JSONL аудит)                                        │
│  /run/secrets/token_encryption_key  (Docker secret)                               │
└───────────────────────────────────────────────────────────────────────────────────┘

Поток публикации

  1. Клиент (Hermes/skill) POST /api/v1/publish c api_key, vk_account_id, message_md
  2. Auth: hash api_key → User.is_active
  3. Load VkAccount → decrypt_token (Fernet, только в памяти)
  4. markdown_to_vk(message_md) → chunks (VK-лимит ~4096 симв., режет по абзацам; @ = 2 симв.)
  5. Publication (status=draft|scheduled)
  6. Если publish_date задан → status=scheduled (планировщик — TODO)
  7. Иначе vk.wall_post(message, owner_id, from_group, ..., format_data=items)
  8. Ответ: post_id, owner_id, url https://vk.com/wall{owner}_{post}; ошибки → status=error + error_message

Порт/интерфейсы

Интерфейс Адрес Назначение
Локальный 127.0.0.1:8420 внутренний (Caddy на vps02 → 10.8.0.2:8420)
VK API https://api.vk.com/method исходящий (wall.post, users.get)
Swagger /docs openapi, за basic auth

База данных (SQLite)

Таблица Ключевые поля
users id, name, email, api_key_hash, api_key_prefix, is_active, created_at, updated_at
vk_accounts id, user_id→users, vk_user_id (owner_id, - = сообщество), display_name, access_token_enc (Fernet), token_type (user|group), is_active, expires_at, last_used_at
publications id, vk_account_id→vk_accounts, status (draft|scheduled|published|error), markdown_original, vk_text, vk_format_data, vk_post_id, vk_owner_id, attachments, scheduled_at, published_at, error_message

Отложенные посты

Модель поддерживает scheduled_at, /publish с publish_date создаёт запись scheduled. Планировщика нет — открытая задача (worker-процесс/cron, выбирающий status=scheduled AND scheduled_at<=now).

Ошибки VK API

Код Смысл
VkApiError обёртка: error_code + error_msg из ответа VK; пишется в publications.error_message

Конвертер Markdown

Markdown VK format
**bold**, __bold__ bold
*italic*, _italic_ italic
***bold italic*** bold + italic
`code` inline_code
[text](url) link (+url)
# H1..H6 bold (uppercase)
> quote italic
```code code (без format)
--- ───

Длинный текст режется на чанки по \n\n (абзацы), запас 10% от лимита 4096.