291 lines
6.2 KiB
Markdown
291 lines
6.2 KiB
Markdown
# Верстак — модель данных и хранилище
|
||
|
||
## 1. Vault
|
||
|
||
Пример структуры:
|
||
|
||
```text
|
||
~/VerstakVault/
|
||
.verstak/
|
||
index.db
|
||
config.yml
|
||
device.yml
|
||
sync_state.db
|
||
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,
|
||
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,
|
||
created_at TEXT NOT NULL,
|
||
updated_at TEXT NOT NULL
|
||
);
|
||
```
|
||
|
||
### activity_events
|
||
|
||
```sql
|
||
CREATE TABLE activity_events (
|
||
id TEXT PRIMARY KEY,
|
||
node_id TEXT NULL REFERENCES nodes(id),
|
||
source TEXT NOT NULL,
|
||
event_type TEXT NOT NULL,
|
||
title TEXT NULL,
|
||
path TEXT NULL,
|
||
url TEXT NULL,
|
||
app_name TEXT NULL,
|
||
process_name TEXT NULL,
|
||
started_at TEXT NOT NULL,
|
||
ended_at TEXT NULL,
|
||
duration_seconds INTEGER NULL,
|
||
metadata_json TEXT NULL,
|
||
confidence INTEGER NOT NULL DEFAULT 100,
|
||
created_at TEXT NOT NULL
|
||
);
|
||
```
|
||
|
||
### worklog_suggestions
|
||
|
||
```sql
|
||
CREATE TABLE worklog_suggestions (
|
||
id TEXT PRIMARY KEY,
|
||
node_id TEXT NOT NULL REFERENCES nodes(id),
|
||
date TEXT NOT NULL,
|
||
started_at TEXT NULL,
|
||
ended_at TEXT NULL,
|
||
suggested_minutes INTEGER NULL,
|
||
summary TEXT NOT NULL,
|
||
evidence_json TEXT NOT NULL,
|
||
status TEXT NOT NULL DEFAULT 'pending',
|
||
created_at TEXT NOT NULL,
|
||
updated_at TEXT NOT NULL
|
||
);
|
||
```
|
||
|
||
### 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
|
||
);
|
||
```
|
||
|
||
## 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.
|