Files
md2vk/docs/architecture.md

84 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.