xync-db 0.5.5.dev64__tar.gz → 0.5.5.dev82__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xync_db-0.5.5.dev82/.gitignore +39 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/PKG-INFO +6 -12
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/README.md +5 -11
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/enums.py +3 -1
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/i18n.py +1 -1
- xync_db-0.5.5.dev82/src/xync_db/migrations/CLAUDE.md +21 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/0001_initial.py +2 -2
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/0002_triggers.py +15 -16
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/0003_seed.py +2 -4
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_actor_seed.py +1 -1
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_bin_seed.py +1 -1
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_country_seed.py +2 -6
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/b_htx_seed.py +1 -1
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/models/CLAUDE.md +5 -19
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/models/__init__.py +7 -10
- xync_db-0.5.5.dev64/.gitignore +0 -48
- xync_db-0.5.5.dev64/src/xync_db/migrations/CLAUDE.md +0 -129
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/pyproject.toml +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/__init__.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/config.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/exceptions.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/graph.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/login_store.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/logo.png +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/__init__.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/__init__.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/__init__.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_tg_seed.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/c_net_seed.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/countries.json +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/ranges.csv +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/xync_files.sql +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/py.typed +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/shared.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/__init__.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/__init__.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/actor.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/ad.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/common.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/cred.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/order.py +0 -0
- {xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/typs/db/pm.py +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.env
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
*.log*
|
|
16
|
+
|
|
17
|
+
# uv
|
|
18
|
+
.uv-cache/
|
|
19
|
+
|
|
20
|
+
# Node
|
|
21
|
+
node_modules/
|
|
22
|
+
*.tsbuildinfo
|
|
23
|
+
|
|
24
|
+
# Env
|
|
25
|
+
.env
|
|
26
|
+
.env.local
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.vscode/
|
|
30
|
+
.idea/
|
|
31
|
+
*.swp
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
packages/xync-web
|
|
39
|
+
packages/xync-chrome-ext
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: xync-db
|
|
3
|
-
Version: 0.5.5.
|
|
3
|
+
Version: 0.5.5.dev82
|
|
4
4
|
Summary: Xync DB schema: Tortoise ORM models, enums, pydantic DTOs.
|
|
5
5
|
Author-email: Mike Artemiev <mixartemev@gmail.com>
|
|
6
6
|
License: LicenseRef-EULA
|
|
@@ -56,7 +56,7 @@ Single source of truth for data shape across the monorepo.
|
|
|
56
56
|
classDiagram
|
|
57
57
|
direction BT
|
|
58
58
|
class Actor {
|
|
59
|
-
|
|
59
|
+
uint16 exid
|
|
60
60
|
uint1 ex_id
|
|
61
61
|
varchar(63) name
|
|
62
62
|
integer person_id
|
|
@@ -335,13 +335,7 @@ user --> username : username_id->username.id
|
|
|
335
335
|
- а в `Order` соответственно через `ad_id` получаем `ad.actor.ex_id`
|
|
336
336
|
|
|
337
337
|
|
|
338
|
-
##
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
tortoise makemigrations # detect changes
|
|
343
|
-
tortoise migrate # apply
|
|
344
|
-
tortoise downgrade models 0001_initial # roll back
|
|
345
|
-
tortoise sqlmigrate models 0001_initial # preview SQL
|
|
346
|
-
```
|
|
347
|
-
Config lives in this package's `pyproject.toml` under `[tool.tortoise]`.
|
|
338
|
+
## Миграции
|
|
339
|
+
Ровно три: `0001_initial` (схема), `0002_triggers`, `0003_seed`; изменение схемы — правкой `0001`, новых миграций
|
|
340
|
+
не заводим (`src/xync_db/migrations/CLAUDE.md`). Применить: `tortoise migrate` (конфиг — `[tool.tortoise]` в
|
|
341
|
+
`pyproject.toml`).
|
|
@@ -38,7 +38,7 @@ Single source of truth for data shape across the monorepo.
|
|
|
38
38
|
classDiagram
|
|
39
39
|
direction BT
|
|
40
40
|
class Actor {
|
|
41
|
-
|
|
41
|
+
uint16 exid
|
|
42
42
|
uint1 ex_id
|
|
43
43
|
varchar(63) name
|
|
44
44
|
integer person_id
|
|
@@ -317,13 +317,7 @@ user --> username : username_id->username.id
|
|
|
317
317
|
- а в `Order` соответственно через `ad_id` получаем `ad.actor.ex_id`
|
|
318
318
|
|
|
319
319
|
|
|
320
|
-
##
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
tortoise makemigrations # detect changes
|
|
325
|
-
tortoise migrate # apply
|
|
326
|
-
tortoise downgrade models 0001_initial # roll back
|
|
327
|
-
tortoise sqlmigrate models 0001_initial # preview SQL
|
|
328
|
-
```
|
|
329
|
-
Config lives in this package's `pyproject.toml` under `[tool.tortoise]`.
|
|
320
|
+
## Миграции
|
|
321
|
+
Ровно три: `0001_initial` (схема), `0002_triggers`, `0003_seed`; изменение схемы — правкой `0001`, новых миграций
|
|
322
|
+
не заводим (`src/xync_db/migrations/CLAUDE.md`). Применить: `tortoise migrate` (конфиг — `[tool.tortoise]` в
|
|
323
|
+
`pyproject.toml`).
|
|
@@ -236,7 +236,9 @@ class CredType(
|
|
|
236
236
|
foreign = 3 # продавец просит платёж на зарубежную (не российскую) карту/номер: «перевод на зарубежную карту»
|
|
237
237
|
|
|
238
238
|
|
|
239
|
-
class GeminiModel(
|
|
239
|
+
class GeminiModel(
|
|
240
|
+
IntEnum
|
|
241
|
+
): # модель Gemini (`GeminiReq`); имя в API, порядок силы и квоты — `cond_ai.providers.gemini.MODELS`
|
|
240
242
|
lite_3_5 = 5
|
|
241
243
|
lite_3_1 = 6
|
|
242
244
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# migrations — три миграции (D-09)
|
|
2
|
+
|
|
3
|
+
Конфиг — `xync_service.config.TORTOISE_ORM`; `make migrate` / `make makemigrations` из корня.
|
|
4
|
+
|
|
5
|
+
1. **`0001_initial`** — полная финальная схема (`ops.CreateModel`). **Любое изменение схемы — правкой этого
|
|
6
|
+
файла**: `0003_seed` пишет через ORM по финальной модели, поздняя миграция с новой колонкой уронит засев.
|
|
7
|
+
Новых миграций не заводим; на прод (ledger фейковый) — DDL руками.
|
|
8
|
+
2. **`0002_triggers`** — все триггеры и функции (`CREATE OR REPLACE`): NOTIFY-каналы (`contracts/events.md`),
|
|
9
|
+
гарды (`tx_before`, `tx_no_delete`, `ad_exid_ex_uniq`, `ad_cond_side_uniq`, `cond_txt_side_uniq`), GC условий
|
|
10
|
+
(`ad_cond_gc`, `cond_new_gc`), утилиты `_user_balance`, `_tx_pack`. Идёт до засева — сид полагается на
|
|
11
|
+
`user_new`.
|
|
12
|
+
3. **`0003_seed`** — засев по зависимостям: файлы PM-логотипов → `a_actor_seed` (биржи, 56 базовых валют, монеты,
|
|
13
|
+
XyncPay, эл. кошельки, origin user id=0) → `a_tg_seed` (DC/App, `pm_rep`) → `a_country_seed` (страны+валюты
|
|
14
|
+
из `seed/countries.json`) → `a_bin_seed` (BIN/банки из `seed/ranges.csv`) → `b_htx_seed` (валюты/монеты/пары
|
|
15
|
+
HTX) → `c_net_seed` (web3-сети).
|
|
16
|
+
|
|
17
|
+
Засев, зависящий от Pm (`set_pms` с логотипами, `refine_pms`), — в `xync-script`, не здесь: миграции не
|
|
18
|
+
импортируют `pyro_client`.
|
|
19
|
+
|
|
20
|
+
Дев-БД пересобирать только с нуля (`DROP`/`CREATE` + `make migrate`); таблицы, созданные заранее
|
|
21
|
+
`generate_schemas`, ломают `0001` (DuplicateTable).
|
|
@@ -595,7 +595,7 @@ class Migration(migrations.Migration):
|
|
|
595
595
|
options={"table": "pm_group", "app": "models", "pk_attr": "id"},
|
|
596
596
|
bases=["Model"],
|
|
597
597
|
),
|
|
598
|
-
# `bank` — раньше `Bank`/`Bin`/`Card` (D-
|
|
598
|
+
# `bank` — раньше `Bank`/`Bin`/`Card` (D-17), т.к. на него ссылается `pm.bank_id`
|
|
599
599
|
ops.CreateModel(
|
|
600
600
|
name="Bank",
|
|
601
601
|
fields=[
|
|
@@ -2691,7 +2691,7 @@ class Migration(migrations.Migration):
|
|
|
2691
2691
|
options={"table": "vpn", "app": "models", "pk_attr": "id", "table_description": "VPNs"},
|
|
2692
2692
|
bases=["Model"],
|
|
2693
2693
|
),
|
|
2694
|
-
# ── Cards / BINs (D-
|
|
2694
|
+
# ── Cards / BINs (D-17; засев — `0003_seed` → a_bin_seed из binlist/data; `Bank` создан выше — на него ссылается `pm`) ──
|
|
2695
2695
|
ops.CreateModel(
|
|
2696
2696
|
name="Bin",
|
|
2697
2697
|
fields=[
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""PG triggers migration — ВСЕ триггеры БД в одном месте.
|
|
2
2
|
|
|
3
|
-
Определяют NOTIFY-триггеры, которые слушает pg-listener service-api.
|
|
4
|
-
|
|
3
|
+
Определяют NOTIFY-триггеры, которые слушает pg-listener service-api. `CREATE OR REPLACE` + порядок в
|
|
4
|
+
`operations` дают финальную форму.
|
|
5
5
|
|
|
6
6
|
Channels emitted:
|
|
7
7
|
after_orders_new -- new order, no hot_id
|
|
@@ -9,24 +9,23 @@ Channels emitted:
|
|
|
9
9
|
hot_order_upd_status -- hot order status change
|
|
10
10
|
after_orders_upd_status -- non-hot order status change
|
|
11
11
|
agents_upd_status -- agent status toggle
|
|
12
|
-
agents_upd_auth -- agent web-session (cookies/headers) changed
|
|
12
|
+
agents_upd_auth -- agent web-session (cookies/headers) changed
|
|
13
13
|
actor_person_needs_def_user -- new actor needs person assignment
|
|
14
14
|
after_users_new -- new user (also creates person + xync-actor)
|
|
15
15
|
tx_verified -- transaction reached verified
|
|
16
16
|
ads_upd / mads_upd -- ad row changed (diff payload)
|
|
17
|
-
creds_new/creds_del/creds_upd, credexs_del
|
|
18
|
-
w3addr_wanted / w3addr_filled -- web3 address handshake
|
|
17
|
+
creds_new/creds_del/creds_upd, credexs_del, credexs_orphan -- cred/credex lifecycle
|
|
18
|
+
w3addr_wanted / w3addr_filled -- web3 address handshake
|
|
19
19
|
|
|
20
20
|
Guards (RAISE, без NOTIFY): tx_before (баланс/иммутабельность/монотонность), tx_no_delete,
|
|
21
|
-
ad_exid_ex_uniq (
|
|
21
|
+
ad_exid_ex_uniq (exid уникален per-exchange), ad_cond_side_uniq/cond_txt_side_uniq (unique
|
|
22
22
|
(cond.raw_txt, ad.pair_side.is_sell)). GC: ad_cond_gc/cond_new_gc — условие без объяв удаляется (cond_gc).
|
|
23
23
|
Utility: _user_balance(uid, cid), _tx_pack(...).
|
|
24
24
|
|
|
25
25
|
`actor_new` trigger: only the `status = -1` (USER_DEF) branch — an agent person pre-created by
|
|
26
26
|
`Agent.upsert` triggers the `actor_person_needs_def_user` NOTIFY so an admin is asked whose agent it is.
|
|
27
27
|
Persons of actors are created ONLY in Python (`Ex.person_save` / `Agent.upsert`, which stamp
|
|
28
|
-
`note = "{ex_id}:{exid}"`, D-
|
|
29
|
-
`Actor.create` site passes a person). A person-less actor is a maker masked by the exchange (D-042).
|
|
28
|
+
`note = "{ex_id}:{exid}"`, D-16). A person-less actor is a maker masked by the exchange (D-16).
|
|
30
29
|
"""
|
|
31
30
|
|
|
32
31
|
from typing import ClassVar
|
|
@@ -39,8 +38,8 @@ TRIGGERS_SQL = """
|
|
|
39
38
|
-- before new Actor
|
|
40
39
|
CREATE OR REPLACE FUNCTION actor_new() returns trigger as $actor_new_trg$
|
|
41
40
|
BEGIN
|
|
42
|
-
-- персону актору заводит ТОЛЬКО Python (Ex.person_save / Agent.upsert, note = "{ex_id}:{exid}", D-
|
|
43
|
-
-- актор без person_id — замаскированный биржей мейкер (D-
|
|
41
|
+
-- персону актору заводит ТОЛЬКО Python (Ex.person_save / Agent.upsert, note = "{ex_id}:{exid}", D-16);
|
|
42
|
+
-- актор без person_id — замаскированный биржей мейкер (D-16), персону ему не выдумываем.
|
|
44
43
|
-- агентской персоне уже проставлен status=-1 (USER_DEF) в Agent.upsert → зовём админа
|
|
45
44
|
-- определить юзера (actor_person_needs_def_user).
|
|
46
45
|
IF (SELECT status FROM person WHERE id = NEW.person_id) = -1 THEN
|
|
@@ -262,12 +261,12 @@ CREATE OR REPLACE TRIGGER cred_del BEFORE DELETE ON "cred" FOR EACH ROW EXECUTE
|
|
|
262
261
|
"""
|
|
263
262
|
|
|
264
263
|
# ─────────────────────────────────────────────────────────────────────────────────────────────────
|
|
265
|
-
# Дополнительные
|
|
264
|
+
# Дополнительные триггеры. Все `CREATE OR REPLACE`,
|
|
266
265
|
# поэтому порядок в `operations` гарантирует финальную форму: `credex_del` переопределяет дефолтный
|
|
267
266
|
# `plsql("credex")` DEL, а `agent_upd` — базовый выше.
|
|
268
267
|
# ─────────────────────────────────────────────────────────────────────────────────────────────────
|
|
269
268
|
|
|
270
|
-
# Per-CredEx delete → `credexs_del
|
|
269
|
+
# Per-CredEx delete → `credexs_del`. Юзер отвязывает ОДИН кред от ОДНОЙ биржи. Дефолтный
|
|
271
270
|
# `plsql("credex")` DEL нёс лишь OLD.id — бесполезно после каскада. Шлём [person_id, ex_id, exid]
|
|
272
271
|
# (person через ещё живой родительский `cred`). ПРОПУСКАЕМ notify если родитель-cred уже удалён:
|
|
273
272
|
# это каскад Cred → BEFORE-DELETE `cred_del()` уже снял каждый credex в `creds_del` (иначе двойное
|
|
@@ -288,7 +287,7 @@ $credex_del_trg$ LANGUAGE plpgsql;
|
|
|
288
287
|
CREATE OR REPLACE TRIGGER credex_del AFTER DELETE ON "credex" FOR EACH ROW EXECUTE FUNCTION credex_del();
|
|
289
288
|
"""
|
|
290
289
|
|
|
291
|
-
# Per-CredEx exid-overwrite → `credexs_orphan
|
|
290
|
+
# Per-CredEx exid-overwrite → `credexs_orphan`. `CredEx.upsert` ключуется по (cred, ex) и
|
|
292
291
|
# перезаписывает `exid`. Перезапись РЕАЛЬНОГО (не 0) exid другим значением осиротит прежний кред на
|
|
293
292
|
# бирже (БД его больше не трекает) — не утекаем молча: BEFORE-UPDATE шлёт [person_id, ex_id, OLD.exid,
|
|
294
293
|
# OLD.cred_id], чтобы service-api спросил владельца, удалить ли устаревший (mirror `is_you`).
|
|
@@ -311,7 +310,7 @@ $credex_orphan_trg$ LANGUAGE plpgsql;
|
|
|
311
310
|
CREATE OR REPLACE TRIGGER credex_orphan BEFORE UPDATE ON "credex" FOR EACH ROW EXECUTE FUNCTION credex_orphan();
|
|
312
311
|
"""
|
|
313
312
|
|
|
314
|
-
# Agent.auth change → `agents_upd_auth
|
|
313
|
+
# Agent.auth change → `agents_upd_auth`. ПЕРЕОПРЕДЕЛЯЕТ `agent_upd` выше: второй, независимый
|
|
315
314
|
# branch шлёт `agents_upd_auth` ТОЛЬКО при реальной смене auth (`OLD.auth IS DISTINCT FROM NEW.auth`) —
|
|
316
315
|
# service-api патчит куки/хедеры в ЖИВУЮ http-сессию агента (`BaseAgentClient.reload_auth`) без рестарта.
|
|
317
316
|
# Независим от status-branch (status и auth меняются вместе или порознь).
|
|
@@ -330,7 +329,7 @@ $agent_upd_trg$ LANGUAGE plpgsql;
|
|
|
330
329
|
CREATE OR REPLACE TRIGGER agent_upd AFTER UPDATE ON "agent" FOR EACH ROW EXECUTE FUNCTION agent_upd();
|
|
331
330
|
"""
|
|
332
331
|
|
|
333
|
-
# Ad.exid uniqueness per-EXCHANGE, не per-maker
|
|
332
|
+
# Ad.exid uniqueness per-EXCHANGE, не per-maker. `unique_together(exid, maker)` не ловит РАЗНОГО
|
|
334
333
|
# maker на ТОЙ ЖЕ бирже с чужим exid (биржа выдаёт ad-id глобально по аккаунтам). Tortoise не выразит
|
|
335
334
|
# uniq через join (`maker`→`actor.ex_id` не колонка `ad`) → BEFORE INSERT/UPDATE RAISE на конфликт по
|
|
336
335
|
# (exid≠0, тот же actor.ex_id). Падает громко на записи (как fail-loud в `Ex.e2x_ad`).
|
|
@@ -451,7 +450,7 @@ CREATE CONSTRAINT TRIGGER cond_new_gc AFTER INSERT ON "cond" DEFERRABLE INITIALL
|
|
|
451
450
|
FOR EACH ROW EXECUTE FUNCTION cond_gc();
|
|
452
451
|
"""
|
|
453
452
|
|
|
454
|
-
# web3-хендшейк
|
|
453
|
+
# web3-хендшейк адресов: net_addr_ins (вставка пустого val → зовём получателя завести адрес,
|
|
455
454
|
# канал `w3addr_wanted`) и net_addr_upd (val NULL→real → сообщаем отправителям pending-W3Send, канал
|
|
456
455
|
# `w3addr_filled`). (`ALTER net_addr.val DROP NOT NULL` уехал в 0001 — теперь val создаётся nullable.)
|
|
457
456
|
NET_ADDR_TRIGGERS_SQL = """
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"""Полный засев БД одной миграцией — файлы (PM-логотипы) + справочники/сущности в нужном порядке.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
(0001), поэтому сидеры, пишущие через ORM (напр. `set_pairs` → `pair.scale`), не спотыкаются о
|
|
5
|
-
недостающие колонки (раньше `pair.scale`/`country.ccn3` добавлялись миграциями ПОСЛЕ засева).
|
|
3
|
+
Идёт ПОСЛЕ триггеров (0002) и по ПОЛНОЙ схеме (0001) — сидеры пишут через ORM по финальной модели.
|
|
6
4
|
|
|
7
5
|
Порядок (зависимости):
|
|
8
6
|
1. files — PM-логотипы из `seed/xync_files.sql` (если файлов < 100)
|
|
@@ -13,7 +11,7 @@
|
|
|
13
11
|
6. b_htx_seed — HTX-специфика: валюты (CurEx), монеты, пары
|
|
14
12
|
7. c_net_seed — web3-сети (Net) + недостающие нативные монеты
|
|
15
13
|
|
|
16
|
-
NB (D-
|
|
14
|
+
NB (D-09): PM-зависимый засев (`set_pms` + `refine_pms`) живёт в `packages/xync-script`, НЕ здесь —
|
|
17
15
|
он тянет `pyro_client` (FileClient), а миграции не должны импортировать `pyro_client`.
|
|
18
16
|
"""
|
|
19
17
|
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_actor_seed.py
RENAMED
|
@@ -285,7 +285,7 @@ async def actor_seed(db: BaseDBAsyncClient) -> str:
|
|
|
285
285
|
xyncpay, _ = await Pm.update_or_create(dict(ok=True, qr=True, fee=0, typ=PmType.emoney), id=0, norm="xyncpay")
|
|
286
286
|
|
|
287
287
|
# эл. кошельки: в p2p-условиях RUB их называют наравне с банками → свой Bank (Pm с банком попадает в список
|
|
288
|
-
# банков разбора условий, `
|
|
288
|
+
# банков разбора условий, `cond_ai.banks`) + PmCur RUB; ЦУПИС биржи не отдают — Pm заводим сами. Pyypl/Alipay
|
|
289
289
|
# не рублёвые — df_cur им не ставим (Alipay — CNY в `refine_pms`)
|
|
290
290
|
rub = await Cur.get(ticker="RUB")
|
|
291
291
|
wallets = ("yoomoney", None, rub), ("cupis", "цупис", rub), ("pyypl", None, None), ("alipay", None, None)
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_bin_seed.py
RENAMED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
bank_logo,bank_url,bank_phone,bank_city`. `iin_start` — BIN-префикс (6 ИЛИ 8 цифр), `iin_end` —
|
|
6
6
|
верх диапазона (пусто = одиночный). Диапазоны маленькие (макс. span 18), поэтому РАЗВОРАЧИВАЕМ их в
|
|
7
7
|
отдельные префиксы — модель `Bin` остаётся префиксной (`Bin.for_card` ищет 6- и 8-значный префикс,
|
|
8
|
-
`Card.from_number` режет тело по длине найденного BIN). См. D-
|
|
8
|
+
`Card.from_number` режет тело по длине найденного BIN). См. D-17.
|
|
9
9
|
|
|
10
10
|
Идём после стран, т.к. `Bin.country` линкуется на уже засеянные `Country` по alpha-2 (`short`).
|
|
11
11
|
Банки дедуплицируем по `name` (первый вариант деталей выигрывает). Идемпотентно: guard по count +
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/a_country_seed.py
RENAMED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
"""Единый сидер стран и их валют — ПЕРЕД биржевыми сидерами (`b_htx_seed`).
|
|
2
2
|
|
|
3
3
|
Данные — статический `countries.json` рядом (сгенерирован из mledoze/countries: `name.common`
|
|
4
|
-
→ name, `cca2` → short, `ccn3` → ccn3, первая из `currencies` → cur)
|
|
5
|
-
из HTX (`cl.countries()`) с ручными костылями (`cnt_codes` для пропавших short, `cur_map`,
|
|
6
|
-
`additional_countries`) и разъезжались с реальностью: у 78 стран стояла USD-заглушка (HTX
|
|
7
|
-
дефолтил `currencyId=1`), у Бенина short был `"BJ,"` с запятой. Теперь канонично:
|
|
4
|
+
→ name, `cca2` → short, `ccn3` → ccn3, первая из `currencies` → cur):
|
|
8
5
|
|
|
9
|
-
• `ccn3` — числовой ISO 3166-1
|
|
10
|
-
не читался, см. миграцию 0012);
|
|
6
|
+
• `ccn3` — числовой ISO 3166-1;
|
|
11
7
|
• `short` — чистый ISO alpha-2;
|
|
12
8
|
• `name` — каноническое common-имя;
|
|
13
9
|
• `cur` — реальная валюта страны. Валюты, которых нет среди 56 базовых (`a_actor_seed`),
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/b_htx_seed.py
RENAMED
|
@@ -14,7 +14,7 @@ async def htx_seed(db: BaseDBAsyncClient) -> str:
|
|
|
14
14
|
await cl.set_curs()
|
|
15
15
|
|
|
16
16
|
# NB: set_pms() lives in packages/xync-script now (it uploads logos via service-pyro and
|
|
17
|
-
# so must not pull pyro_client into xync-db — D-
|
|
17
|
+
# so must not pull pyro_client into xync-db — D-09). The script also re-runs the setters
|
|
18
18
|
# below when an exchange is under-seeded, so they could move there too later.
|
|
19
19
|
await cl.set_coins()
|
|
20
20
|
await cl.set_pairs()
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
1
|
+
# xync_db.models
|
|
6
2
|
|
|
7
3
|
All Tortoise ORM models (~60) are defined in `__init__.py`. Models are organized into domain groups listed below.
|
|
8
4
|
|
|
@@ -51,18 +47,8 @@ Re-exported models from `x_auth`: `Username`, `Proxy`, `Dc`, `Fcm`, `App`, `Sess
|
|
|
51
47
|
- `Addr` = crypto deposit address `(coin_id, actor_id)` unique; linked to `Net`s via `NetAddr`
|
|
52
48
|
- `Asset` = balance snapshot `(addr_id, typ)` unique; amounts `free`/`freeze`/`lock`/`target`. Owner reached via `addr → actor` (agent 1:1 actor — the old `agent_id` was redundant with `addr.actor` and was dropped)
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
А при создании актора(Actor) создается персона без user_id, но в actor.person_id = id этой персоны.
|
|
57
|
-
И когда юзер заходит в объявление одного из агентов(Agent) первый раз, создается его актор для биржи (на которой
|
|
58
|
-
размещено это объявление) и новая персона этого актора.
|
|
59
|
-
Если к персоне юзера еще не "привязано" ни одного актора, 2 персоны для юзера с одним актором избыточны, их нужно
|
|
60
|
-
смерджить: т.е старой персоне юзера назначить имя, креды(creds) и актора этой новой персоны, а новую "осиротевшую"
|
|
61
|
-
персону удалить.
|
|
62
|
-
Далее, если этот же юзер будет заходить с других акторов:
|
|
63
|
-
- других бирж, но с тем же именем: это та же персона нужно так же смерджить новую персону нового актора с существующей.
|
|
64
|
-
- с другим именем: значит это уже другая персона, и существующая персона(ы) уже "занята" существующим(и) актором(ами),
|
|
65
|
-
тогда уже не надо мержить новую персону нового актора, оставляем новую.
|
|
50
|
+
Персона актора — только из Python по ключу `note = "{ex_id}:{exid}"`, замаскированный мейкер без персоны;
|
|
51
|
+
слияние — `Person.merge` / `Actor.set_user` (D-16).
|
|
66
52
|
|
|
67
53
|
### Payment Methods
|
|
68
54
|
`PmGroup` -> `Pm` -> `PmCur` <- `Cur`, `PmEx` <- `Ex`, `PmExBank`
|
|
@@ -88,12 +74,12 @@ actor.set_user(username_id):
|
|
|
88
74
|
### Conditions (Ad parsing)
|
|
89
75
|
`Cond` -> `CondParsed`, `Synonym`, `CondSim`, `CondPrompt`
|
|
90
76
|
|
|
91
|
-
- `Cond.raw_txt` =
|
|
77
|
+
- `Cond.raw_txt` = текст условия (до 4095); условие — одной стороны, без объяв не живёт (D-18)
|
|
92
78
|
- `CondParsed` = structured parse result: `from_party` / `to_party` (`FromParty`: с чьего / на чей счёт идёт платёж
|
|
93
79
|
покупателя), `ppo`, `slip` (`Slip`) — требует/шлёт понятно из направления объявы, abuse flags, `is_intermediary`
|
|
94
80
|
(мейкер-посредник «треугол»), linked bank `Pm`s
|
|
95
81
|
— все поля nullable, дефолт `None` (= «в условии не сказано»; никаких `*.no`-заглушек). Единый writer
|
|
96
|
-
`CondParsed.upsert(cond_id, bank_ids=None, **fields)` (бот-разметка /cond и
|
|
82
|
+
`CondParsed.upsert(cond_id, bank_ids=None, **fields)` (бот-разметка /cond и разбор нейронками, D-19); ответ админа
|
|
97
83
|
на «сохранить разбор?» — эмиттер `CondParsed.answer(cond_id, remark=None)` → pg-канал `cond_ai_answer`
|
|
98
84
|
`[cond_id, remark]` (null — «да», текст — «нет» с замечанием, "" — «нет», замечание пишется, true — «🔄»: объяву
|
|
99
85
|
условия заново с биржи — реальный exid замаскированного мейкера + свежий `raw_txt`, затем вопрос заново); возвращает, слушает
|
|
@@ -404,12 +404,9 @@ class Person(Model, TsTrait):
|
|
|
404
404
|
status: PersonStatus = IntEnumField(PersonStatus, db_default=PersonStatus.DEFAULT)
|
|
405
405
|
name: str | None = CharField(127, null=True)
|
|
406
406
|
# bootstrap-персона (создана от актора) несёт note = "{ex_id}:{exid}" её актора-источника —
|
|
407
|
-
# уникальный ключ, по которому её резолвят Ex.person_save и Agent.upsert (D-
|
|
407
|
+
# уникальный ключ, по которому её резолвят Ex.person_save и Agent.upsert (D-16).
|
|
408
408
|
note: str | None = CharField(255, null=True)
|
|
409
|
-
# Уникальность
|
|
410
|
-
# UNIQUE(note) WHERE note IS NOT NULL — bootstrap-персона уникальна по своему актору;
|
|
411
|
-
# UNIQUE NULLS NOT DISTINCT (name, user_id, note) — тёзки живут лишь при разных user_id / note
|
|
412
|
-
# (двух (name, NULL, NULL) быть не может).
|
|
409
|
+
# Уникальность в БД — пока только unique(name, user, note); UNIQUE(note) — в decisions.md `## Pending`.
|
|
413
410
|
user: ForeignKeyNullableRelation[User] = ForeignKeyField("models.User", "persons", on_update=CASCADE, null=True)
|
|
414
411
|
user_id: int | None
|
|
415
412
|
creds: BackwardFKRelation[Cred]
|
|
@@ -1087,7 +1084,7 @@ class Forum(Model, TsTrait):
|
|
|
1087
1084
|
|
|
1088
1085
|
class Actor(Model):
|
|
1089
1086
|
# реальные id бирж влезают в uint8; >= MASKED — id, замаскированный биржей (Bybit userMaskId, 128 бит):
|
|
1090
|
-
# публичный листинг объяв прячет мейкера, реальный exid добудем отдельно (D-
|
|
1087
|
+
# публичный листинг объяв прячет мейкера, реальный exid добудем отдельно (D-16)
|
|
1091
1088
|
MASKED: ClassVar[int] = 1 << 64
|
|
1092
1089
|
exid: int = UInt16Field()
|
|
1093
1090
|
name: str = CharField(63)
|
|
@@ -1269,7 +1266,7 @@ class Agent(Model, TsTrait):
|
|
|
1269
1266
|
|
|
1270
1267
|
Bootstrap-персону нового актора резолвим
|
|
1271
1268
|
ПО `note` (`"{ex_id}:{exid}"`, уникальному по актору) — тем же ключом, что клиентский
|
|
1272
|
-
`Ex.person_save`, чтобы у Person был ОДИН путь создания (D-
|
|
1269
|
+
`Ex.person_save`, чтобы у Person был ОДИН путь создания (D-16). По НЕуникальному `name` НЕ
|
|
1273
1270
|
ищем: именно `get_or_none(name=rname)` ронял прод `MultipleObjectsReturned` на тёзках без юзера.
|
|
1274
1271
|
|
|
1275
1272
|
Если note не нашёлся (актор впервые) — пробуем gmail-автолинк: замаскированная биржей почта,
|
|
@@ -2128,7 +2125,7 @@ class CredEx(Model):
|
|
|
2128
2125
|
async def remove(cls, *, cred_id: int, ex_id: int) -> bool:
|
|
2129
2126
|
"""ЕДИНСТВЕННЫЙ standalone-делитор CredEx (single-writer-правило): сносит строку (cred, ex).
|
|
2130
2127
|
Снятие креда с ОДНОЙ биржи из формы — удаление на бирже реактивно: BEFORE/AFTER-DELETE триггер
|
|
2131
|
-
`credex_del` (
|
|
2128
|
+
`credex_del` (0002_triggers) положит `[person_id, ex_id, exid]` в `credexs_del` → handler вызовет
|
|
2132
2129
|
`acl.cred_del(exid)`. Каскадное удаление при сносе самого Cred идёт другим путём (`creds_del`)."""
|
|
2133
2130
|
return bool(await cls.filter(cred_id=cred_id, ex_id=ex_id).delete())
|
|
2134
2131
|
|
|
@@ -2136,7 +2133,7 @@ class CredEx(Model):
|
|
|
2136
2133
|
async def orphan_del(cls, *, person_id: int, ex_id: int, exid: int) -> None:
|
|
2137
2134
|
"""Удалить ОСИРОТЕВШИЙ exid на бирже — после согласия владельца (web-контроллер / бот-колбэк).
|
|
2138
2135
|
Перезапись exid у строки (cred, ex) на другой оставляет старый реквизит висеть на бирже дубликатом;
|
|
2139
|
-
BEFORE-UPDATE триггер `credex_orphan` (
|
|
2136
|
+
BEFORE-UPDATE триггер `credex_orphan` (0002_triggers) ловит это и шлёт `credexs_orphan` → handler
|
|
2140
2137
|
спрашивает владельца. На «да» зовут СЮДА: свой канал `credexs_orphan_del` (НЕ переиспользуем
|
|
2141
2138
|
`credexs_del`) — его handler `credex_orphan_del` делает `acl.cred_del(exid)` по (person, ex) И
|
|
2142
2139
|
возвращает владельцу результат (успех/ошибка) тем же Notify; у обычного `credex_del` отчёта нет,
|
|
@@ -2227,7 +2224,7 @@ class Bin(Model):
|
|
|
2227
2224
|
@classmethod
|
|
2228
2225
|
async def for_card(cls, digits: str) -> Bin:
|
|
2229
2226
|
"""Найти BIN для номера карты. BIN бывает 6- или 8-значным, заранее не знаем — пробуем ОБА
|
|
2230
|
-
префикса в НАШЕЙ таблице (засеяна из binlist/data, D-
|
|
2227
|
+
префикса в НАШЕЙ таблице (засеяна из binlist/data, D-17) и берём более специфичный (8 > 6).
|
|
2231
2228
|
В binlist.net ходим ТОЛЬКО если не нашли у себя (`_fetch`, префикс 8 цифр)."""
|
|
2232
2229
|
# префиксы разной длины не пересекаются как int (6-значный < 10^6 ≤ 8-значный), поэтому один
|
|
2233
2230
|
# запрос prefix__in корректен; order_by(-length) отдаёт 8-значный, если он есть.
|
xync_db-0.5.5.dev64/.gitignore
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Python
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*.egg-info/
|
|
5
|
-
.env
|
|
6
|
-
.venv/
|
|
7
|
-
venv/
|
|
8
|
-
.pytest_cache/
|
|
9
|
-
.mypy_cache/
|
|
10
|
-
.ruff_cache/
|
|
11
|
-
.coverage
|
|
12
|
-
htmlcov/
|
|
13
|
-
dist/
|
|
14
|
-
build/
|
|
15
|
-
*.log*
|
|
16
|
-
|
|
17
|
-
# uv
|
|
18
|
-
.uv-cache/
|
|
19
|
-
|
|
20
|
-
# Node
|
|
21
|
-
node_modules/
|
|
22
|
-
packages/xync-coord/dist/
|
|
23
|
-
packages/xync-coord/.vite/
|
|
24
|
-
*.tsbuildinfo
|
|
25
|
-
|
|
26
|
-
# Env
|
|
27
|
-
.env
|
|
28
|
-
.env.local
|
|
29
|
-
|
|
30
|
-
# IDE
|
|
31
|
-
.vscode/
|
|
32
|
-
.idea/
|
|
33
|
-
*.swp
|
|
34
|
-
|
|
35
|
-
# OS
|
|
36
|
-
.DS_Store
|
|
37
|
-
Thumbs.db
|
|
38
|
-
|
|
39
|
-
# Generated
|
|
40
|
-
# packages/xync-coord/src/api/schema.gen.ts is regenerated by `npm run codegen`
|
|
41
|
-
# (against the live API /schema/openapi.json), but stays tracked so `tsc -b`
|
|
42
|
-
# and CI work without a running API.
|
|
43
|
-
|
|
44
|
-
# Claude state (board) — track this in git, but ignore live edits if user prefers:
|
|
45
|
-
# .claude/state/log.md # uncomment to ignore the journal
|
|
46
|
-
|
|
47
|
-
packages/xync-web
|
|
48
|
-
packages/xync-chrome-ext
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# migrations/ — Database Migrations (Tortoise native)
|
|
2
|
-
|
|
3
|
-
Native Tortoise ORM migrations. Config: `xync_service.config.TORTOISE_ORM`
|
|
4
|
-
(referenced from `packages/xync-db/pyproject.toml`).
|
|
5
|
-
|
|
6
|
-
CLI (from `packages/xync-db/`): `uv run tortoise makemigrations` / `uv run tortoise migrate`
|
|
7
|
-
(or `make makemigrations` / `make migrate` from the repo root).
|
|
8
|
-
|
|
9
|
-
> **Консолидировано в 3 миграции (D-037).** Прежние 0001-0012 слиты в:
|
|
10
|
-
> 1. **`0001_initial`** — ФИНАЛЬНАЯ схема всех таблиц (`ops.CreateModel`), включая всё, что раньше
|
|
11
|
-
> доливали поздние миграции: `pair.scale`+`rate` INT (было 0011), `country.ccn3` (было `code`, 0012),
|
|
12
|
-
> `updatestate` перестроен (0010), `net_addr.val` nullable + таблицы `coin_net`/`w3_send` (0009).
|
|
13
|
-
> 2. **`0002_triggers`** — ВСЕ триггеры (база + credex_del/credex_orphan/agent_upd-auth/ad_exid_ex_uniq/
|
|
14
|
-
> net_addr — были 0005-0009). `CREATE OR REPLACE` + порядок в `operations` дают финальную форму.
|
|
15
|
-
> 3. **`0003_seed`** — весь засев (files + actor/tg/country/htx/net) в порядке зависимостей.
|
|
16
|
-
>
|
|
17
|
-
> **Почему:** сид (0003) пишет через ORM (`set_pairs`→`pair.scale`) и должен идти по ПОЛНОЙ схеме;
|
|
18
|
-
> когда колонку добавляла миграция ПОСЛЕ сида, fresh-migrate падал «column … does not exist». Правило:
|
|
19
|
-
> **любое изменение схемы для засеваемой таблицы — в `0001`, а не в поздней миграции.**
|
|
20
|
-
> Разделы ниже описывают ИСТОРИЧЕСКОЕ содержимое (для контекста) — оно теперь внутри этих трёх файлов.
|
|
21
|
-
|
|
22
|
-
## models/0001_initial.py — Initial Schema
|
|
23
|
-
|
|
24
|
-
Creates all ~50 tables. Key tables and their relationships:
|
|
25
|
-
|
|
26
|
-
### Core Domain
|
|
27
|
-
- **`user`** — Xync users. `username_id` → `username.id` (Telegram user). Has `pub/prv` (Ed25519 keys for XyncPay signing), `role` (bitmask: READER=4, WRITER=2, MANAGER=6, ADMIN=7), `status` (SLEEP=0, PAY=1, ACTIVE=2)
|
|
28
|
-
- **`person`** — Identity abstraction. A user has 1+ persons. `status`: VIP=2, DEFAULT=1, ANONYMOUS=0, USER_DEF=-1, BLOCKED=-2
|
|
29
|
-
- **`actor`** — Exchange account. Links `person` to `ex` (exchange). Unique per (ex_id, exid). `exid` = external user id on exchange
|
|
30
|
-
- **`agent`** — Automated trading agent. 1:1 with `actor`. Has `auth` (exchange session JSON), `expire_at` (session TTL), `status` (bitmask, bit 1 = listening)
|
|
31
|
-
|
|
32
|
-
### Trading
|
|
33
|
-
- **`ad`** — P2P advertisement. Belongs to `maker` (actor), `pair_side` (coin/cur + buy/sell direction). Price/amount stored as integers (scaled)
|
|
34
|
-
- **`my_ad`** — Our managed ad (extends `ad` with target_place, shared_at)
|
|
35
|
-
- **`order`** — P2P order. Links `ad`, `taker` (actor), `cred` (payment credential), optional `hot` (hot session). Status: created=1, paid=2, completed=3, canceled=4, appealed_by_seller=5, appealed_by_buyer=6, appeal_disputed=7
|
|
36
|
-
- **`cred`** — Payment credential (bank account/wallet). `detail` = account number, `ovr_pm_id` = override PM (0 = XyncPay hot cred). Unique per (person, pmcur, ovr_pm_id)
|
|
37
|
-
|
|
38
|
-
### XyncPay
|
|
39
|
-
- **`transaction`** — XyncPay transfers. UUID id generated by PG function from packed fields. `status`: request=0, signed=1, verified=2. `proof` = Ed25519 signature
|
|
40
|
-
- **`hot`** — Hot swap session. `status`: closed=0, opened=1. Belongs to user
|
|
41
|
-
- **`topup`** — Fiat topup to XyncPay balance via external PM
|
|
42
|
-
|
|
43
|
-
### Reference Data
|
|
44
|
-
- **`ex`** — Exchanges (Bybit=4, HTX=9, etc). `typ`: p2p=1, cex=2, main=3, dex=4, tg=5. `status`: plan=0, parted=1, full=2
|
|
45
|
-
- **`coin`** — Cryptocurrencies with `scale` (decimal places) and `rate` (to base currency)
|
|
46
|
-
- **`cur`** — Fiat currencies with `scale` and `rate`
|
|
47
|
-
- **`pm`** — Payment methods. `norm` = normalized name, `typ`: bank=0, emoney=1, cash=2, gift_card=3, card=4, IFSC=5, SBP=6, phone=7
|
|
48
|
-
- **`pair`/`pair_side`** — Trading pairs (coin+cur) and their buy/sell sides
|
|
49
|
-
- **`coinex`/`curex`/`pmex`** — Exchange-specific mappings for coins, currencies, payment methods
|
|
50
|
-
|
|
51
|
-
### Telegram Integration
|
|
52
|
-
- **`username`** — Telegram users (id = tg_id)
|
|
53
|
-
- **`session`** — Pyrogram sessions for userbot
|
|
54
|
-
- **`peer`** — Cached Telegram peers (access_hash)
|
|
55
|
-
- **`forum`** — Telegram forum groups per user
|
|
56
|
-
- **`dc`** — Telegram data centers
|
|
57
|
-
- **`app`** — Telegram API applications
|
|
58
|
-
|
|
59
|
-
### Other
|
|
60
|
-
- **`race`/`race_stat`** — Ad price competition automation
|
|
61
|
-
- **`cond`/`cond_parsed`/`synonym`** — P2P ad condition text parsing and analysis
|
|
62
|
-
- **`fiat`** — Fiat balance per credential
|
|
63
|
-
- **`asset`** — Crypto balance per addr (coin+actor) per `typ`; owner via `addr.actor` (no `agent_id`)
|
|
64
|
-
- **`transfer`** — Fiat transfer proof for orders
|
|
65
|
-
- **`msg`** — Order chat messages
|
|
66
|
-
|
|
67
|
-
## models/0002_triggers.py — PG Triggers and Functions
|
|
68
|
-
|
|
69
|
-
### Entity Triggers
|
|
70
|
-
- **`actor_new()`** BEFORE INSERT — auto-creates anonymous `person` if actor has no person_id
|
|
71
|
-
- **`user_new()`** AFTER INSERT — auto-creates `person` + `actor` (ex_id=0 = Xync) for new user, notifies `after_users_new`
|
|
72
|
-
- **`order_new()`** AFTER INSERT — routes to `hot_order_new` (if hot_id set) or `after_orders_new`
|
|
73
|
-
- **`order_upd()`** AFTER UPDATE — routes status changes to `hot_order_new` (hot_id just set), `hot_order_upd_status` (hot status change), or `after_orders_upd_status` (non-hot status change). Payload: `[row_json, old_status]`
|
|
74
|
-
- **`agent_upd()`** AFTER UPDATE — notifies `agents_upd_status` on status change. Payload: `[row_json, old_status]`
|
|
75
|
-
|
|
76
|
-
### Transaction Functions
|
|
77
|
-
- **`_user_balance(uid, cid)`** — SQL function: calculates XyncPay balance as `SUM(received) - SUM(sent)` with status checks (verified for received, signed+ for sent)
|
|
78
|
-
- **`_tx_pack(status, ts, cur_id, receiver_id, amount, sender_id)`** — Generates deterministic UUID from transaction fields: `(type << 30 | ts-epoch) || cur_id[1B] || receiver[3B] || amount[5B] || sender[3B]`
|
|
79
|
-
- **`tx_before()`** BEFORE INSERT/UPDATE:
|
|
80
|
-
- INSERT: generates id if null, checks sender balance (rejects if insufficient)
|
|
81
|
-
- UPDATE: validates that packed fields haven't changed (id must still match generated)
|
|
82
|
-
- **`tx_after()`** AFTER INSERT/UPDATE — notifies `tx_verified` when status becomes 2 (verified)
|
|
83
|
-
- **`tx_no_delete()`** BEFORE DELETE — prevents transaction deletion entirely
|
|
84
|
-
|
|
85
|
-
### Auto-generated Triggers
|
|
86
|
-
- `plsql("cred", 2)` — generates AFTER INSERT trigger for `cred` table → `creds_new` channel
|
|
87
|
-
- `plsql("msg", 2)` — generates AFTER INSERT trigger for `msg` table
|
|
88
|
-
|
|
89
|
-
## models/0003_files_seed.py — File Seed
|
|
90
|
-
|
|
91
|
-
Loads PM logo files from `seed/xync_files.sql` if < 100 files exist. These are Telegram file references stored as binary `ref` in the `file` table.
|
|
92
|
-
|
|
93
|
-
## models/0004_all_seed.py — Full Seed
|
|
94
|
-
|
|
95
|
-
Orchestrates the seed scripts in order:
|
|
96
|
-
1. `a_actor_seed` — Exchanges, currencies (56 base), coins, XyncPay PM, e-wallets yoomoney/cupis/pyypl/alipay (Bank + Pm typ=emoney + RUB pmcur), origin user (id=0)
|
|
97
|
-
2. `a_tg_seed` — Telegram DCs, app config, PM name mappings (`pm_rep`)
|
|
98
|
-
3. `a_country_seed` — **all** countries + their currencies from the bundled `seed/countries.json`
|
|
99
|
-
(generated from mledoze/countries), single source, BEFORE the exchange seeders. Sets `ccn3`
|
|
100
|
-
(ISO 3166-1 numeric — the old `code`/phone column, renamed in 0012), clean `short` (cca2),
|
|
101
|
-
canonical `name`, real `cur` (creates the ~99 non-base `Cur`); `id` baked into the file so
|
|
102
|
-
existing countries keep theirs, meta-aggregates hold 201/202. Idempotent. (D-036)
|
|
103
|
-
4. `b_htx_seed` — HTX-specific: currencies (CurEx), coins, pairs (via `xync_client.ExClient`).
|
|
104
|
-
No longer seeds countries — those moved to `a_country_seed`.
|
|
105
|
-
|
|
106
|
-
> **PM-dependent seeding left the migration (D-017).** PMs aren't populated at migrate
|
|
107
|
-
> time (they come from `set_pms`), so anything keyed off them moved to `packages/xync-script`
|
|
108
|
-
> (`python -m xync_script`, run after `migrate` with `pyro` up):
|
|
109
|
-
> - `b_htx_seed` dropped `set_pms` — it pulled `pyro_client` (FileClient) into xync-db, the
|
|
110
|
-
> import cycle (xync-db ⇄ pyro-client) we removed.
|
|
111
|
-
> - the former `c_ex_seed` (PM default-currency + bank groups) is now
|
|
112
|
-
> `xync_script.seed.refine_pms`, run only when `set_pms` actually added new `Pm` rows.
|
|
113
|
-
>
|
|
114
|
-
> **Rule:** never import `pyro_client` from a migration. (`b_htx_seed` still uses
|
|
115
|
-
> `xync_client.ExClient` for currency/coin/pair seeding — accepted for now.)
|
|
116
|
-
|
|
117
|
-
### Key Seed Data
|
|
118
|
-
- 24 exchanges defined (Xync=0, Binance=1, Bybit=4, HTX=9, OKX=14, TgWallet=20...)
|
|
119
|
-
- 53 fiat currencies with rates relative to RUB
|
|
120
|
-
- 14 coins: XYNC(0), USDT(1), BTC(2), ETH(3), USDC(4), TON(5), SOL(6)...
|
|
121
|
-
- Origin user: id=0, username=XyncPay, tg_id=7807393311
|
|
122
|
-
- PM name normalizations (`pm_rep`): maps exchange-specific names to canonical forms (e.g. "Tinkoff" → "T-Bank", "ADVCash" → "Volet.com")
|
|
123
|
-
|
|
124
|
-
## models/0005_ad_upd_full_row.py — ad_upd payload
|
|
125
|
-
|
|
126
|
-
Replaces the `ad_upd()` trigger function: payload `[NEW.id, diff]` → `[row_to_json(NEW), diff]`
|
|
127
|
-
(`diff` = `{field: [old, new]}`, channels `ads_upd`/`mads_upd`). The api handlers build the
|
|
128
|
-
exchange push from the row state **at event time** instead of re-reading the (possibly already
|
|
129
|
-
overwritten) row from the DB.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/c_net_seed.py
RENAMED
|
File without changes
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/countries.json
RENAMED
|
File without changes
|
|
File without changes
|
{xync_db-0.5.5.dev64 → xync_db-0.5.5.dev82}/src/xync_db/migrations/models/seed/xync_files.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|