pcb-ai-engineer/refs: add self-hosted mirror section (Altium Celestial)

The original setup guide covered connecting Altium directly to the
portal SQL server. That works but has three drawbacks under RU
conditions: ~60-second Altium startup over VPN, daily VPN dependency,
single point of failure at Mark Harris's hosting.

New section 11 documents the self-hosted alternative we just built and
verified end-to-end:

- Two independent mirrors:
  - homework/altium-library: Gitea pull-mirror of issus/altium-library
    with LFS (SchLib + PcbLib + STEP, ~6 GB)
  - homework/celestial-mirror-db: MSSQL 2022 Express in Docker on
    192.168.9.147, populated weekly by a pymssql-based sync job with
    best-effort + row-count/schema fingerprint skip logic
- Results: Altium startup <1s (100x faster), VPN only needed once a
  week for the sync runner, full control over the dataset
- Full deployment sequence (Gitea migrate API → docker compose up →
  first manual full-sync → client DbLib rewrite)
- ConnectionString rewrite details (altium_reader user, LAN IP,
  Encrypt=Optional/TrustServerCertificate=Yes for self-signed cert)
- MPN-to-view lookup strategies (Shift+C in Altium; dynamic SQL that
  scans all 168 tables)
- Troubleshooting specific to the mirror stack
This commit is contained in:
creator
2026-04-18 22:32:25 +00:00
parent 73d69fa8ae
commit 9f3e7f82e7
@@ -545,8 +545,219 @@ Write-Host "`nГотово. Открывай Altium → Components panel → Fil
--- ---
## 10. Changelog этой инструкции ## 11. Self-hosted mirror (опционально, ускорение startup ×100)
Разделы 1–9 подключают Altium напрямую к портальному SQL-серверу Mark
Harris'а. Это работает, но:
- Каждый запуск Altium — 30–90 секунд на ~600 метадата-запросов через
WAN (OVH France). VPN добавляет ещё RTT.
- Требуется VPN при каждой работе с библиотекой (если RKN режет 1433 к
OVH, а он обычно режет).
- Зависимость от доступности `db.altiumlibrary.com` — если Mark
выключит сервер, всё встанет.
- Нельзя добавлять свои компоненты в общую БД — только в отдельный
custom DbLib.
Альтернатива — **self-hosted mirror**: зеркалим и git-репо (SchLib/PcbLib/STEP
через LFS), и SQL-БД (параметры компонентов). Клиенты ходят только в LAN,
VPN нужен раз в неделю для sync-job'а.
### Результат
- Startup Altium: **<1 сек** (проверено на Altium 26.4.1, январь 2026)
- Нет зависимости от WAN и от upstream'а в ежедневной работе
- Полный контроль — можно доливать свои views/компоненты
- Обновления — раз в неделю автоматически по cron
### Архитектура
```
┌──────────────────────────┐ pull mirror (Gitea, 24h) ┌─────────────────────────┐
│ github.com/issus/ │◀─────── HTTPS + LFS ─────────│ homework/altium-library │
│ altium-library │ │ (Gitea mirror, ~6 GB) │
└──────────────────────────┘ └──────────┬──────────────┘
│ git clone
┌─────────────────────────┐
│ Altium (client) │
│ SchLib/PcbLib/STEP │
│ from local clone │
└──────────┬──────────────┘
│ SQL queries
┌──────────────────────────┐ weekly sync (Gitea Actions) ┌─────────────────────────┐
│ db.altiumlibrary.com │◀───── pymssql, VPN ──────────│ homework/ │
│ :1433 (upstream SQL) │ │ celestial-mirror-db │
└──────────────────────────┘ │ + MSSQL 2022 Express │
│ on 192.168.9.147:1433 │
└─────────────────────────┘
```
### Два независимых компонента
**Git-mirror** (`homework/altium-library`):
- Gitea pull-mirror, интервал 24h, LFS включён
- Содержит SchLib, PcbLib, STEP, sample projects — всё из upstream
- Клиенты клонируют с `ssh://git@192.168.7.179:2222/homework/altium-library.git`
или HTTPS по LAN
**SQL-mirror** (`homework/celestial-mirror-db`):
- Docker-стек: MSSQL 2022 Express на 192.168.9.147:1433 (LAN only)
- Sync-скрипт `sync/celestial_sync.py`: best-effort, atomic swap через
staging+`sp_rename`, row-count+schema fingerprint skip-логика
- Gitea Actions workflow: `workflow_dispatch` + weekly cron понедельник
03:00 UTC
- Два SQL-user'а: `sync_writer` (DDL+DML для CI) и `altium_reader`
(SELECT для Altium)
### Как развернуть с нуля
Последовательность в новой инсталляции (полный setup ~2 часа на первый
раз, включая начальный sync ~40 мин):
**1. Gitea pull-mirror git-репо**
В Gitea UI: `+ → New Migration → GitHub` (или через API):
```
Clone URL: https://github.com/issus/altium-library.git
Owner: homework
Name: altium-library
Type: Mirror (pull)
Interval: 24h
LFS: ✓ enabled
```
Либо через API:
```bash
curl -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/repos/migrate" -d '{
"clone_addr": "https://github.com/issus/altium-library.git",
"repo_owner": "homework",
"repo_name": "altium-library",
"service": "git",
"mirror": true,
"mirror_interval": "24h0m0s",
"lfs": true
}'
```
Первичная миграция тянет 5–6 ГБ с GitHub, занимает 30–90 минут.
**2. Docker-стек celestial-mirror-db**
Клонировать `homework/celestial-mirror-db`, заполнить `.env` сильными
паролями (см. `.env.example`), `docker compose up -d`. Init-контейнер
создаст БД, логины, роли. Compose-файл биндит порт на 192.168.9.147:1433
(только LAN, не 0.0.0.0). Подробная инструкция — в README репо.
**3. Первый sync**
В Gitea UI: `Actions → Sync Celestial DB → Run workflow`, mode=full-sync.
Занимает 30–60 минут через VPN. На VPN должен быть маршрут до
`51.68.218.24` (OVH France) — на MikroTik это address-list с policy-based
routing через xray/AmneziaWG.
**4. Подключение клиента (Altium)**
```bash
# Клиентская машина
cd C:\Work
git clone ssh://git@192.168.7.179:2222/homework/altium-library.git
cd altium-library
git lfs pull
```
Копируем портальный DbLib рядом как `-local.DbLib`, правим `ConnectionString`:
```ini
# Было:
ConnectionString = Provider=SQLNCLI11.1; User ID=alib_xxx; Password=xxx; \
Initial Catalog=altium_library; Data Source=db.altiumlibrary.com,1433; \
Initial File Name=""; Server SPN=""
# Стало:
ConnectionString = Provider=SQLNCLI11.1; User ID=altium_reader; Password=<из .env>; \
Initial Catalog=altium_library; Data Source=192.168.9.147,1433; \
Encrypt=Optional; TrustServerCertificate=Yes; \
Initial File Name=""; Server SPN=""
```
Изменилось: `User ID`, `Password`, `Data Source`, и добавлены
`Encrypt=Optional; TrustServerCertificate=Yes` — потому что MSSQL в Docker
с self-signed сертификатом.
В Altium: `Components panel → File-based Libraries Preferences → Installed
→ Uninstall старого (портального) → Install нового (local)`. Startup
<1 секунды.
### Поиск компонента по MPN без знания категории
В DBLib-архитектуре Altium показывает компоненты в рамках одной view
(категории). Если MPN известен, а категория нет:
**Способ 1 — через Altium:** Hotkey `Shift+C` (File-based Libraries Search)
→ Search for: `*STSPIN32G4*`, Scope: `Libraries on path`, Search in:
`Components`. Выдаст список попаданий с колонкой "Library Ref".
**Способ 2 — SQL прямо в mirror:** Единичный запрос с dynamic SQL
просматривает все tables и находит категорию:
```sql
SET NOCOUNT ON;
DECLARE @needle NVARCHAR(100) = N'%STSPIN32G4%';
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql = @sql +
'IF EXISTS (SELECT 1 FROM [' + TABLE_NAME + '] WHERE [Part Number] LIKE @n) ' +
'SELECT ''' + TABLE_NAME + ''' AS [View], [Part Number], [Manufacturer], [Description] ' +
'FROM [' + TABLE_NAME + '] WHERE [Part Number] LIKE @n; '
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%__staging'
AND TABLE_NAME <> 'sync_status';
EXEC sp_executesql @sql, N'@n NVARCHAR(100)', @n=@needle;
```
Можно обернуть в shell-функцию `cfind`.
### Troubleshooting self-hosted mirror
**Sync job висит на первой view ~10 минут и фейлится с "DBPROCESS is dead":**
RKN режет TCP к `51.68.218.24:1433`. Проверяй что на VPN routing для этого
IP действительно активен с 192.168.9.147.
**`String or binary data would be truncated`:** Upstream view объявляет
NVARCHAR(N) в INFORMATION_SCHEMA, но возвращает строки длиннее. Фикс в
sync-скрипте — все строковые колонки мапятся в NVARCHAR(MAX). Если
видишь такую ошибку — `celestial_sync.py` ещё не имеет фикса, обнови
до коммита `b868b68` или новее.
**Weekly sync не стартует:** Gitea Actions требует чтобы в репо был
активный runner и на репо были включены Actions. Проверь
`Settings → Actions → General → Enabled`.
**Altium Components panel пустая:** SSH'нись в MSSQL и проверь:
```sql
SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE' AND TABLE_NAME NOT LIKE '%__staging';
-- Должно быть ~168.
SELECT TOP 1 * FROM dbo.sync_status ORDER BY id DESC;
-- status = 'ok', views_synced около 168, rows_synced ~250k.
```
### Ссылки на репозитории
- `homework/altium-library` — git mirror: <https://git.h3fq32.golive.ru/homework/altium-library>
- `homework/celestial-mirror-db` — Docker + sync: <https://git.h3fq32.golive.ru/homework/celestial-mirror-db>
---
## 12. Changelog этой инструкции
| Дата | Изменения | | Дата | Изменения |
|---|---| |---|---|
| 2026-04-18 | Первая версия. Проверено на Altium Designer 26.4.1, Windows 11, MSOLEDBSQL 19.4.1.0, SQLNCLI 11.4.x. | | 2026-04-18 | Первая версия. Проверено на Altium Designer 26.4.1, Windows 11, MSOLEDBSQL 19.4.1.0, SQLNCLI 11.4.x. |
| 2026-04-18 | Добавлен раздел 11 — self-hosted mirror с git + SQL зеркалами. Проверено end-to-end: startup <1 сек, 256 677 строк в локальной БД, weekly sync active. |