verstak/docs/03_Data_Model_Storage.md

294 lines
6.3 KiB
Markdown
Raw 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.

# Верстак — модель данных и хранилище
## 1. Vault
Пример структуры:
```text
~/VerstakVault/
.verstak/
index.db
config.yml
device_token.json
blobs/
plugins/
trash/
history/
originals/
thumbnails/
spaces/
clients/
romashka/
case.yml
overview.md
notes/
nginx.md
mysql-cleanup.md
access.secret.md.enc
documents/
dogovor-2026.docx
sluzhebka.pdf
screenshots/
error-form.png
scripts/
backup-site.sh
cleanup.sql
actions/
open-admin.yml
worklog/
2026-05.md
```
## 2. SQLite schema MVP
### nodes
```sql
CREATE TABLE nodes (
id TEXT PRIMARY KEY,
parent_id TEXT NULL REFERENCES nodes(id),
type TEXT NOT NULL,
title TEXT NOT NULL,
slug TEXT NOT NULL,
path TEXT NULL,
section TEXT NULL,
template_id TEXT NOT NULL DEFAULT '',
fs_path TEXT NOT NULL DEFAULT '',
archived INTEGER NOT NULL DEFAULT 0,
sort_order INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
deleted_at TEXT NULL,
revision INTEGER NOT NULL DEFAULT 1,
device_id TEXT NULL
);
```
### node_meta
```sql
CREATE TABLE node_meta (
node_id TEXT NOT NULL REFERENCES nodes(id),
key TEXT NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (node_id, key)
);
```
### files
```sql
CREATE TABLE files (
id TEXT PRIMARY KEY,
node_id TEXT NOT NULL REFERENCES nodes(id),
filename TEXT NOT NULL,
path TEXT NOT NULL,
storage_mode TEXT NOT NULL, -- vault | external
size INTEGER NOT NULL DEFAULT 0,
sha256 TEXT NULL,
mime TEXT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
last_seen_at TEXT NULL,
missing INTEGER NOT NULL DEFAULT 0
);
```
### notes
```sql
CREATE TABLE notes (
node_id TEXT PRIMARY KEY REFERENCES nodes(id),
file_id TEXT NOT NULL REFERENCES files(id),
format TEXT NOT NULL DEFAULT 'markdown',
original_format TEXT NULL,
encrypted INTEGER NOT NULL DEFAULT 0
);
```
### actions
```sql
CREATE TABLE actions (
id TEXT PRIMARY KEY,
node_id TEXT NOT NULL REFERENCES nodes(id),
title TEXT NOT NULL,
kind TEXT NOT NULL,
command TEXT NULL,
args_json TEXT NULL,
working_dir TEXT NULL,
url TEXT NULL,
confirm_required INTEGER NOT NULL DEFAULT 0,
capture_output INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
```
### worklog_entries
```sql
CREATE TABLE worklog_entries (
id TEXT PRIMARY KEY,
node_id TEXT NOT NULL REFERENCES nodes(id),
started_at TEXT NULL,
ended_at TEXT NULL,
date TEXT NOT NULL,
minutes INTEGER NULL,
approximate INTEGER NOT NULL DEFAULT 1,
billable INTEGER NOT NULL DEFAULT 0,
summary TEXT NOT NULL,
details TEXT NULL,
source TEXT NOT NULL DEFAULT 'unknown',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
```
### activity_events
```sql
CREATE TABLE activity_events (
id TEXT PRIMARY KEY,
node_id TEXT NOT NULL,
parent_id TEXT,
event_type TEXT NOT NULL,
target_type TEXT,
target_id TEXT,
target_path TEXT,
title TEXT NOT NULL DEFAULT '',
metadata TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
```
### worklog_entry_events
```sql
CREATE TABLE worklog_entry_events (
entry_id TEXT NOT NULL REFERENCES worklog_entries(id) ON DELETE CASCADE,
event_id TEXT NOT NULL,
PRIMARY KEY (entry_id, event_id)
);
```
### search_index
```sql
CREATE VIRTUAL TABLE search_index USING fts5(
node_id UNINDEXED,
title,
content,
path,
tags,
type
);
```
### sync_ops
```sql
CREATE TABLE sync_ops (
id TEXT PRIMARY KEY,
op_id TEXT NOT NULL UNIQUE,
device_id TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
op_type TEXT NOT NULL,
payload_json TEXT NOT NULL,
created_at TEXT NOT NULL,
pushed_at TEXT NULL,
applied_at TEXT NULL
);
CREATE TABLE sync_state (
device_id TEXT PRIMARY KEY,
server_url TEXT NOT NULL DEFAULT '',
api_key TEXT NOT NULL DEFAULT '',
last_push_rev INTEGER NOT NULL DEFAULT 0,
last_pull_rev INTEGER NOT NULL DEFAULT 0,
last_sync_at TEXT,
last_pull_seq INTEGER NOT NULL DEFAULT 0
);
```
## 3. Правила хранения
### Заметки
- physical `.md` file;
- metadata in SQLite;
- backup old version before overwrite.
### Документы
- physical file;
- open with system app;
- metadata in SQLite.
### Secret notes
- encrypted file, e.g. `access.secret.md.enc`;
- no FTS indexing;
- no logs with plaintext;
- master password later.
### Удаление
- soft delete node;
- file to `.verstak/trash`;
- sync tombstone;
- physical cleanup only after retention.
## 4. Sync operations
Каждое изменение должно создавать operation:
- node_create;
- node_update;
- node_move;
- node_delete;
- file_add;
- file_update;
- file_delete;
- note_update;
- action_update;
- worklog_create;
- worklog_update.
Даже если sync ещё не реализован, operation log лучше заложить рано.
## 5. Индексация
Индексировать:
- node titles;
- note content;
- filenames;
- paths;
- worklog summaries/details;
- action titles;
- links.
Не индексировать:
- secret notes;
- private keys;
- token-like values;
- binary content in MVP.
## 6. Расширяемость через плагины
Базовая схема фиксирована и поддерживает плагины:
- Новые типы нод регистрируются плагинами через Lua API
(`verstak.node.register_type()`) — схема таблицы `nodes` не меняется,
`type` принимает любое строковое значение.
- Мета-поля (`node_meta`) хранят произвольные key-value пары,
зарегистрированные плагинами.
- Плагины могут создавать собственные таблицы через SQL-миграции
в своей директории `.verstak/plugins/<name>/migrations/`.
- `device_id` на уровне nodes позволяет плагинам синхронизировать
свои данные через sync_ops.