mirror of
https://gitverse.ru/kpa39l/md2vk.git
synced 2026-09-29 09:55:04 +00:00
Baseline md2vk: docs, audit log, docker 8420, openspec, deploy
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user