chore(test): проверить хранение последних копий и частичное удаление
This commit is contained in:
1 parent
4b028be241
commit
026a358ca6
9 files changed
+276
-9
No files matched your search
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
umask 077
|
||||||
|
cd /opt/mmapp-test
|
||||||
|
mm240_db="mm_accept_166_$(date +%s%3N)"
|
||||||
|
mm240_pass="$(openssl rand -hex 24)"
|
||||||
|
mm240_role_created=false
|
||||||
|
mm240_db_created=false
|
||||||
|
cleanup240() {
|
||||||
|
docker rm mmapp-s3app240-owned >/dev/null 2>&1 || true
|
||||||
|
if $mm240_db_created; then docker exec mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1 -c "DROP DATABASE \"$mm240_db\" WITH (FORCE)"; fi
|
||||||
|
if $mm240_role_created; then docker exec mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1 -c "DROP ROLE \"$mm240_db\""; fi
|
||||||
|
remaining=$(docker exec mmapp-test-postgres psql -U mmapp -d mmapp -Atc "SELECT (SELECT count(*) FROM pg_database WHERE datname='$mm240_db')+(SELECT count(*) FROM pg_roles WHERE rolname='$mm240_db')")
|
||||||
|
[ "$remaining" = 0 ]
|
||||||
|
python3 - <<'PY'
|
||||||
|
import json,pathlib
|
||||||
|
p=pathlib.Path('/opt/mmapp-test/artifacts/s3-retention240/s3-retention240.json')
|
||||||
|
if p.exists():
|
||||||
|
r=json.loads(p.read_text());r['ownedDatabaseAndRoleRemoved']=True;p.write_text(json.dumps(r,indent=2)+'\n')
|
||||||
|
PY
|
||||||
|
printf 'OWNED_DATABASE_AND_ROLE_REMOVED\n'
|
||||||
|
unset mm240_pass
|
||||||
|
}
|
||||||
|
trap cleanup240 EXIT
|
||||||
|
[[ "$mm240_db" =~ ^mm_accept_166_[0-9]+$ ]]
|
||||||
|
existing=$(docker exec mmapp-test-postgres psql -U mmapp -d mmapp -Atc "SELECT (SELECT count(*) FROM pg_database WHERE datname='$mm240_db')+(SELECT count(*) FROM pg_roles WHERE rolname='$mm240_db')")
|
||||||
|
[ "$existing" = 0 ]
|
||||||
|
printf "CREATE ROLE \"%s\" LOGIN PASSWORD '%s' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;\n" "$mm240_db" "$mm240_pass" | docker exec -i mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1
|
||||||
|
mm240_role_created=true
|
||||||
|
docker exec mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1 -c "CREATE DATABASE \"$mm240_db\" OWNER \"$mm240_db\""
|
||||||
|
mm240_db_created=true
|
||||||
|
docker run --name mmapp-s3app240-owned --network mmapp-test_default --cap-drop ALL --security-opt no-new-privileges -e "MMAPP_ORIGIN_BASELINE=${2:-false}" --env-file /opt/mmapp-test/artifacts/s3-retention240/private.env -e NODE_ENV=test -e "DATABASE_URL=postgres://$mm240_db:$mm240_pass@postgres:5432/$mm240_db" -e "MMAPP_OWN_SQL_DB=$mm240_db" -e "DATABASE_PATH=/tmp/$mm240_db/legacy.db" -e "GEOIP_DIR=/tmp/$mm240_db/geoip" -v /opt/mmapp-test/artifacts/s3-retention240:/checks --entrypoint node "${1:-mmapp-test/backend:ux-backups237}" /checks/s3-backup-retention.mjs
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import { randomUUID, createHash } from 'node:crypto';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
const database = process.env.MMAPP_OWN_SQL_DB;
|
||||||
|
assert(/^mm_accept_166_\d+$/.test(database));
|
||||||
|
const url = new URL(process.env.DATABASE_URL); assert.equal(url.pathname, '/' + database); assert.equal(url.username, database);
|
||||||
|
fs.mkdirSync('/tmp/' + database, { recursive: true }); process.chdir('/tmp/' + database);
|
||||||
|
const require = createRequire('/app/backend/package.json'), { ListObjectVersionsCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
||||||
|
const { pool, db, closePool } = await import('/app/backend/dist/db/index.js');
|
||||||
|
const { initDatabase } = await import('/app/backend/dist/db/bootstrap.js');
|
||||||
|
const { servers } = await import('/app/backend/dist/db/schema.js');
|
||||||
|
const { databaseBackgroundWork } = await import('/app/backend/dist/services/database-background-work.js');
|
||||||
|
const { createS3ClientFromConfig, s3PutObject, s3GetObject } = await import('/app/backend/dist/services/s3-backup-client.js');
|
||||||
|
const { updateBackupStorageSettings, pruneBackupsForServer, readBackupContent, listBackups } = await import('/app/backend/dist/services/backup-service.js');
|
||||||
|
const role = (await pool.query('SELECT rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user')).rows[0];
|
||||||
|
assert(Object.values(role).every(v => v === false)); await initDatabase();
|
||||||
|
const prefix = 'mmapp-acceptance/' + randomUUID(), secret = process.env.MMAPP_TEST_S3_SECRET_KEY;
|
||||||
|
const cfg = { endpoint: process.env.MMAPP_TEST_S3_ENDPOINT, region: process.env.MMAPP_TEST_S3_REGION, bucket: process.env.MMAPP_TEST_S3_BUCKET, accessKeyId: process.env.MMAPP_TEST_S3_ACCESS_KEY, secretAccessKey: secret, forcePathStyle: false };
|
||||||
|
assert.equal(cfg.endpoint, 'https://s3.ru-1.storage.selcloud.ru'); assert.equal(cfg.bucket, 'mikrotik-test-s3'); assert(secret);
|
||||||
|
const s3 = createS3ClientFromConfig(cfg), plannedKeys = [], seededIds = [], payloads = new Map();
|
||||||
|
const report = { date: '2026-10-14', block: '12.5.240', scope: 'Owned PostgreSQL + compiled retention service + real Selectel S3; no CHR contacts', prefix, passed: false, checks: [], cleanup: {}, chrContacts: 0, bucketSettingsWrites: 0 };
|
||||||
|
const save = () => fs.writeFileSync('/checks/s3-retention240.json', JSON.stringify(report, null, 2) + '\n');
|
||||||
|
const check = (name, details = {}) => { report.checks.push({ name, ...details }); save(); };
|
||||||
|
const catalog = async () => (await pool.query('SELECT id,storage,s3_key FROM backup_entries ORDER BY id')).rows;
|
||||||
|
async function versions() {
|
||||||
|
let keyMarker, versionMarker; const all = [];
|
||||||
|
for (let n = 0; n < 10; n++) {
|
||||||
|
const r = await s3.send(new ListObjectVersionsCommand({ Bucket: cfg.bucket, Prefix: prefix + '/', KeyMarker: keyMarker, VersionIdMarker: versionMarker }));
|
||||||
|
all.push(...(r.Versions ?? []).map(v => ({ ...v, kind: 'version' })), ...(r.DeleteMarkers ?? []).map(v => ({ ...v, kind: 'delete-marker' })));
|
||||||
|
if (!r.IsTruncated) return all;
|
||||||
|
assert(r.NextKeyMarker || r.NextVersionIdMarker); keyMarker = r.NextKeyMarker; versionMarker = r.NextVersionIdMarker;
|
||||||
|
} throw Error('Own pagination limit');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
assert.equal((await versions()).length, 0);
|
||||||
|
const hosts = await db.insert(servers).values(['a', 'b', 'c'].map(s => ({ name: 'owned-retention240-' + s, host: '127.0.0.1', port: 9, useSsl: false, username: 'fixture', password: 'fixture', enabled: true, type: 'exit-node' }))).returning();
|
||||||
|
await updateBackupStorageSettings({ provider: 's3', s3Endpoint: cfg.endpoint, s3Region: cfg.region, s3Bucket: cfg.bucket, s3Prefix: prefix, s3AccessKeyId: cfg.accessKeyId, s3SecretAccessKey: secret, s3ForcePathStyle: false, keepLocalCopy: true });
|
||||||
|
fs.mkdirSync('storage/backups', { recursive: true });
|
||||||
|
const fixtures = [['a4',0,4,'both'],['a3',0,3,'s3'],['a2',0,2,'local'],['a1',0,1,'s3'],['b2',1,2,'both'],['b1',1,1,'local'],['b0',1,0,'s3'],['c0',2,0,'local']];
|
||||||
|
for (const [id, hostIndex, seconds, storage] of fixtures) {
|
||||||
|
const filename = id + '-retention240.rsc', bytes = Buffer.from('# Own retention240 ' + id + '\n'), key = storage === 'local' ? null : prefix + '/' + filename;
|
||||||
|
seededIds.push(id); payloads.set(id, bytes);
|
||||||
|
if (key) { plannedKeys.push(key); await s3PutObject(s3, cfg.bucket, key, bytes); assert.deepEqual(await s3GetObject(s3, cfg.bucket, key), bytes); }
|
||||||
|
if (storage !== 's3') fs.writeFileSync('storage/backups/' + filename, bytes);
|
||||||
|
await pool.query('INSERT INTO backup_entries(id,server_id,server_name,filename,size_bytes,kind,storage,s3_key,created_at) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9)', [id, hosts[hostIndex].id, hosts[hostIndex].name, filename, bytes.length, id.endsWith('0') ? 'manual' : 'auto', storage, key, new Date(Date.UTC(2026,9,14,0,0,seconds)).toISOString()]);
|
||||||
|
}
|
||||||
|
check('eight-fixtures-three-servers', { remoteObjects: plannedKeys.length, localFiles: fixtures.filter(f => f[3] !== 's3').length });
|
||||||
|
const untouched = (await catalog()).filter(r => !r.id.startsWith('a'));
|
||||||
|
await updateBackupStorageSettings({ s3SecretAccessKey: secret + '-invalid' });
|
||||||
|
let failure;
|
||||||
|
try { await pruneBackupsForServer(String(hosts[0].id), 2); } catch (e) { failure = e; }
|
||||||
|
assert.equal(failure?.name, 'BackupPruneError'); assert.equal(failure.pruned, 1);
|
||||||
|
let remaining = await catalog(); assert.deepEqual(remaining.filter(r => !r.id.startsWith('a')), untouched);
|
||||||
|
assert.deepEqual(remaining.filter(r => r.id.startsWith('a')).map(r => r.id), ['a1','a3','a4']);
|
||||||
|
assert(!fs.existsSync('storage/backups/a2-retention240.rsc'));
|
||||||
|
assert.deepEqual(await s3GetObject(s3, cfg.bucket, prefix + '/a1-retention240.rsc'), payloads.get('a1'));
|
||||||
|
check('partial-failure-acknowledges-one-local-deletion', { pruned: failure.pruned, failedRowRetained: true, remoteObjectRetained: true, otherServersUnchanged: true });
|
||||||
|
await updateBackupStorageSettings({ s3SecretAccessKey: secret });
|
||||||
|
assert.equal(await pruneBackupsForServer(String(hosts[0].id), 2), 1);
|
||||||
|
assert.equal(await pruneBackupsForServer(String(hosts[0].id), 2), 0);
|
||||||
|
assert.deepEqual((await catalog()).filter(r => r.id.startsWith('a')).map(r => r.id), ['a3','a4']);
|
||||||
|
check('retry-retains-latest-two-and-repeat-noop', { retryPruned: 1, repeatPruned: 0 });
|
||||||
|
assert.equal(await pruneBackupsForServer(String(hosts[1].id), 1), 2);
|
||||||
|
assert.deepEqual((await catalog()).map(r => r.id), ['a3','a4','b2','c0']);
|
||||||
|
check('second-server-retains-latest-and-unselected-manual-copy', { pruned: 2, retained: ['a3','a4','b2','c0'] });
|
||||||
|
const copies = await listBackups();
|
||||||
|
for (const copy of copies) assert.deepEqual(await readBackupContent(copy), payloads.get(copy.id));
|
||||||
|
assert.equal(copies.find(r => r.id === 'a3').localFileStatus, 'not-stored');
|
||||||
|
assert(copies.filter(r => r.id !== 'a3').every(r => r.localFileStatus === 'available'));
|
||||||
|
check('retained-content-hashes-and-local-states', { copies: copies.map(r => ({ id: r.id, localFileStatus: r.localFileStatus, sha256: createHash('sha256').update(payloads.get(r.id)).digest('hex') })) });
|
||||||
|
report.passed = true;
|
||||||
|
} catch (e) { report.failure = { name: e.name }; process.exitCode = 1; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
const existing = await versions(); assert(existing.every(v => plannedKeys.includes(v.Key) && v.VersionId));
|
||||||
|
report.cleanup = { plannedKeys, versionsBefore: existing.filter(v => v.kind === 'version').length, deleteMarkersBefore: existing.filter(v => v.kind === 'delete-marker').length, removed: 0 }; save();
|
||||||
|
for (const v of existing) { await s3.send(new DeleteObjectCommand({ Bucket: cfg.bucket, Key: v.Key, VersionId: v.VersionId })); report.cleanup.removed++; save(); }
|
||||||
|
assert.equal((await versions()).length, 0); report.cleanup.versionsAndMarkersRemaining = 0;
|
||||||
|
if (seededIds.length) await pool.query('DELETE FROM backup_entries WHERE id=ANY($1::text[])', [seededIds]);
|
||||||
|
report.cleanup.ownCatalogRemaining = Number((await pool.query('SELECT count(*) AS n FROM backup_entries')).rows[0].n); assert.equal(report.cleanup.ownCatalogRemaining, 0);
|
||||||
|
} catch (e) { report.cleanup.failure = { name: e.name }; report.passed = false; process.exitCode = 1; }
|
||||||
|
await databaseBackgroundWork.drain(); await closePool(); s3.destroy(); save(); console.log(JSON.stringify(report));
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: протокол внешней приёмки 12.5
|
# UX/UI: протокол внешней приёмки 12.5
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14:239 — Selectel S3 restore через реальный Portal/UI принят для собственного95-byte скрипта bridge-only:download SHA256 совпал,restore200/receipt и native bridge без ports/IP подтверждены,delete204. Bridge/file/catalog/S3versions очищены; исходные10 строк, storage/schedule сверены целиком и восстановлены; приватные ключи/SQL-снимок удалены. Runtime backend/frontend ux-backups237. Следующий240 — retention в изолированном собственном S3 scope. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт.
|
||||||
|
|
||||||
IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md).
|
IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md).
|
||||||
|
|
||||||
@@ -18,6 +18,18 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro
|
|||||||
|
|
||||||
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
||||||
|
|
||||||
|
## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14)
|
||||||
|
|
||||||
|
В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись.
|
||||||
|
|
||||||
|
При keepCount2 первого сервера и намеренно неправильном S3 secret local old copy удалена первой, затем remote delete отказал:BackupPruneError.pruned=1. Failed row/object сохранены, две новые копии и остальные servers неизменны. После возвращения верного secret retry удалил1, следующий prune вернул0. Второй сервер keepCount1 удалил2 старых copies, сохранилlatest both; третий unselected manual local copy не затронут. Все4 retained files прочитаны compiled service с точными исходными байтами/hash; remote-only localFileStatus=not-stored, остальныеavailable.
|
||||||
|
|
||||||
|
Пять укрупнённых SQL/S3 проверок прошли. Cleanup удалил только planned keys и их5 versions/2delete markers (итого7), final listing0, own catalog0. Wrapper удалил temporary DB/role/container и подтвердил отсутствие DB/role. Временные ключевые файлы workstation/Debian удалены; секреты в публичном JSON отсутствуют. node --check passed; runtime источники/образы не менялись, повторной полной регрессии нет.
|
||||||
|
|
||||||
|
Протокол: [retention240](ux-ui/acceptance/s3-retention240.json). Helpers:s3-backup-retention.mjs/run-s3-backup-retention.sh. Это реальное хранилище с контролируемыми SQL/file fixtures, не native scheduler production collection и не физический lost ACK; продолжительная работа, version lifecycle policy, миграция buckets и multiple backend/writers остаются отдельно. Ошибка S3 signature намеренно введена, пароли CHR не менялись.
|
||||||
|
|
||||||
|
Следующий241 проверяет1000 строк нового missing/unknown/both UX237:поиск, pagination, last-good и mobile controls. Затем уточнить доступные external jobs и границы выпуска; семь общих групп не превращать в обещание фиксированного числа проверок.
|
||||||
|
|
||||||
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
||||||
|
|
||||||
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
||||||
|
|||||||
+13
-1
@@ -1,9 +1,21 @@
|
|||||||
# План реализации UX/UI по пятичасовым окнам
|
# План реализации UX/UI по пятичасовым окнам
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14:239 — Selectel S3 restore через реальный Portal/UI принят для собственного95-byte скрипта bridge-only:download SHA256 совпал,restore200/receipt и native bridge без ports/IP подтверждены,delete204. Bridge/file/catalog/S3versions очищены; исходные10 строк, storage/schedule сверены целиком и восстановлены; приватные ключи/SQL-снимок удалены. Runtime backend/frontend ux-backups237. Следующий240 — retention в изолированном собственном S3 scope. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт.
|
||||||
|
|
||||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-14. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-14. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||||
|
|
||||||
|
## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14)
|
||||||
|
|
||||||
|
В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись.
|
||||||
|
|
||||||
|
При keepCount2 первого сервера и намеренно неправильном S3 secret local old copy удалена первой, затем remote delete отказал:BackupPruneError.pruned=1. Failed row/object сохранены, две новые копии и остальные servers неизменны. После возвращения верного secret retry удалил1, следующий prune вернул0. Второй сервер keepCount1 удалил2 старых copies, сохранилlatest both; третий unselected manual local copy не затронут. Все4 retained files прочитаны compiled service с точными исходными байтами/hash; remote-only localFileStatus=not-stored, остальныеavailable.
|
||||||
|
|
||||||
|
Пять укрупнённых SQL/S3 проверок прошли. Cleanup удалил только planned keys и их5 versions/2delete markers (итого7), final listing0, own catalog0. Wrapper удалил temporary DB/role/container и подтвердил отсутствие DB/role. Временные ключевые файлы workstation/Debian удалены; секреты в публичном JSON отсутствуют. node --check passed; runtime источники/образы не менялись, повторной полной регрессии нет.
|
||||||
|
|
||||||
|
Протокол: [retention240](ux-ui/acceptance/s3-retention240.json). Helpers:s3-backup-retention.mjs/run-s3-backup-retention.sh. Это реальное хранилище с контролируемыми SQL/file fixtures, не native scheduler production collection и не физический lost ACK; продолжительная работа, version lifecycle policy, миграция buckets и multiple backend/writers остаются отдельно. Ошибка S3 signature намеренно введена, пароли CHR не менялись.
|
||||||
|
|
||||||
|
Следующий241 проверяет1000 строк нового missing/unknown/both UX237:поиск, pagination, last-good и mobile controls. Затем уточнить доступные external jobs и границы выпуска; семь общих групп не превращать в обещание фиксированного числа проверок.
|
||||||
|
|
||||||
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
||||||
|
|
||||||
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
||||||
|
|||||||
+13
-1
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: журнал реализации
|
# UX/UI: журнал реализации
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14:239 — Selectel S3 restore через реальный Portal/UI принят для собственного95-byte скрипта bridge-only:download SHA256 совпал,restore200/receipt и native bridge без ports/IP подтверждены,delete204. Bridge/file/catalog/S3versions очищены; исходные10 строк, storage/schedule сверены целиком и восстановлены; приватные ключи/SQL-снимок удалены. Runtime backend/frontend ux-backups237. Следующий240 — retention в изолированном собственном S3 scope. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт.
|
||||||
|
|
||||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||||
|
|
||||||
@@ -38,6 +38,18 @@
|
|||||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка12.3.83 в границах журнала. Внешняя12.5: блоки1–236 завершены в записанных scopes, этап открыт. Runtime backend ux-backup234/frontend ux-routing218; backend25/UI52 и дополнительные SQL/UDP222 прошли. |
|
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка12.3.83 в границах журнала. Внешняя12.5: блоки1–236 завершены в записанных scopes, этап открыт. Runtime backend ux-backup234/frontend ux-routing218; backend25/UI52 и дополнительные SQL/UDP222 прошли. |
|
||||||
|
|
||||||
|
## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14)
|
||||||
|
|
||||||
|
В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись.
|
||||||
|
|
||||||
|
При keepCount2 первого сервера и намеренно неправильном S3 secret local old copy удалена первой, затем remote delete отказал:BackupPruneError.pruned=1. Failed row/object сохранены, две новые копии и остальные servers неизменны. После возвращения верного secret retry удалил1, следующий prune вернул0. Второй сервер keepCount1 удалил2 старых copies, сохранилlatest both; третий unselected manual local copy не затронут. Все4 retained files прочитаны compiled service с точными исходными байтами/hash; remote-only localFileStatus=not-stored, остальныеavailable.
|
||||||
|
|
||||||
|
Пять укрупнённых SQL/S3 проверок прошли. Cleanup удалил только planned keys и их5 versions/2delete markers (итого7), final listing0, own catalog0. Wrapper удалил temporary DB/role/container и подтвердил отсутствие DB/role. Временные ключевые файлы workstation/Debian удалены; секреты в публичном JSON отсутствуют. node --check passed; runtime источники/образы не менялись, повторной полной регрессии нет.
|
||||||
|
|
||||||
|
Протокол: [retention240](ux-ui/acceptance/s3-retention240.json). Helpers:s3-backup-retention.mjs/run-s3-backup-retention.sh. Это реальное хранилище с контролируемыми SQL/file fixtures, не native scheduler production collection и не физический lost ACK; продолжительная работа, version lifecycle policy, миграция buckets и multiple backend/writers остаются отдельно. Ошибка S3 signature намеренно введена, пароли CHR не менялись.
|
||||||
|
|
||||||
|
Следующий241 проверяет1000 строк нового missing/unknown/both UX237:поиск, pagination, last-good и mobile controls. Затем уточнить доступные external jobs и границы выпуска; семь общих групп не превращать в обещание фиксированного числа проверок.
|
||||||
|
|
||||||
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
||||||
|
|
||||||
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
# Оставшаяся внешняя приёмка — 2026-10-14
|
# Оставшаяся внешняя приёмка — 2026-10-14
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14:239 — Selectel S3 restore через реальный Portal/UI принят для собственного95-byte скрипта bridge-only:download SHA256 совпал,restore200/receipt и native bridge без ports/IP подтверждены,delete204. Bridge/file/catalog/S3versions очищены; исходные10 строк, storage/schedule сверены целиком и восстановлены; приватные ключи/SQL-снимок удалены. Runtime backend/frontend ux-backups237. Следующий240 — retention в изолированном собственном S3 scope. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт.
|
||||||
|
|
||||||
Это актуальная матрица после 12.5.239. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
Это актуальная матрица после 12.5.240. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||||
|
|
||||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-backups237`, frontend `ux-backups237`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-backups237`, frontend `ux-backups237`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||||
|
|
||||||
|
## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14)
|
||||||
|
|
||||||
|
В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись.
|
||||||
|
|
||||||
|
При keepCount2 первого сервера и намеренно неправильном S3 secret local old copy удалена первой, затем remote delete отказал:BackupPruneError.pruned=1. Failed row/object сохранены, две новые копии и остальные servers неизменны. После возвращения верного secret retry удалил1, следующий prune вернул0. Второй сервер keepCount1 удалил2 старых copies, сохранилlatest both; третий unselected manual local copy не затронут. Все4 retained files прочитаны compiled service с точными исходными байтами/hash; remote-only localFileStatus=not-stored, остальныеavailable.
|
||||||
|
|
||||||
|
Пять укрупнённых SQL/S3 проверок прошли. Cleanup удалил только planned keys и их5 versions/2delete markers (итого7), final listing0, own catalog0. Wrapper удалил temporary DB/role/container и подтвердил отсутствие DB/role. Временные ключевые файлы workstation/Debian удалены; секреты в публичном JSON отсутствуют. node --check passed; runtime источники/образы не менялись, повторной полной регрессии нет.
|
||||||
|
|
||||||
|
Протокол: [retention240](ux-ui/acceptance/s3-retention240.json). Helpers:s3-backup-retention.mjs/run-s3-backup-retention.sh. Это реальное хранилище с контролируемыми SQL/file fixtures, не native scheduler production collection и не физический lost ACK; продолжительная работа, version lifecycle policy, миграция buckets и multiple backend/writers остаются отдельно. Ошибка S3 signature намеренно введена, пароли CHR не менялись.
|
||||||
|
|
||||||
|
Следующий241 проверяет1000 строк нового missing/unknown/both UX237:поиск, pagination, last-good и mobile controls. Затем уточнить доступные external jobs и границы выпуска; семь общих групп не превращать в обещание фиксированного числа проверок.
|
||||||
|
|
||||||
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
||||||
|
|
||||||
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
||||||
@@ -59,7 +71,7 @@ Production backend/frontend ux-backups237 собраны и развёрнуты
|
|||||||
| REST и достоверность данных | Ошибки OSPF/BFD/BGP/GRE/WAN215–221 явные; latest API smoke222 прошёл | Correlated236:384 samples/40 diagnostics без отказов; current policies/address/load исправны.828/304 retained REST sessions и vendor inactive-session fix — гипотеза; 238:763.844s/624samples/24diagnostics все200, API records изменились без отказа; причинность401/500 и version control остаются открытыми |
|
| REST и достоверность данных | Ошибки OSPF/BFD/BGP/GRE/WAN215–221 явные; latest API smoke222 прошёл | Correlated236:384 samples/40 diagnostics без отказов; current policies/address/load исправны.828/304 retained REST sessions и vendor inactive-session fix — гипотеза; 238:763.844s/624samples/24diagnostics все200, API records изменились без отказа; причинность401/500 и version control остаются открытыми |
|
||||||
| Клиентские ОС и внешняя сеть | CHR↔CHR/Linux, private IPv4/ULA и synthetic IPv6/IPFIX; Android full-tunnel/reconnect227 подтверждены пользователем | Windows/macOS/iOS VPN, расширенная Android приёмка, независимые WAN/multi-WAN и public IPv6; public IPv6 на текущем стенде отсутствует |
|
| Клиентские ОС и внешняя сеть | CHR↔CHR/Linux, private IPv4/ULA и synthetic IPv6/IPFIX; Android full-tunnel/reconnect227 подтверждены пользователем | Windows/macOS/iOS VPN, расширенная Android приёмка, независимые WAN/multi-WAN и public IPv6; public IPv6 на текущем стенде отсутствует |
|
||||||
| Масштаб и длительная устойчивость | Контролируемые lock/dedupe/loss/recovery и короткие native проверки | Несколько backend/worker/writers, длительный rekey/REST/traffic, physical disconnect и maximum throughput |
|
| Масштаб и длительная устойчивость | Контролируемые lock/dedupe/loss/recovery и короткие native проверки | Несколько backend/worker/writers, длительный rekey/REST/traffic, physical disconnect и maximum throughput |
|
||||||
| Внешние хранилища и jobs | Локальные API/errors/RBAC/owned SQL; реальные Portal1.3.1/Telegram195–201 и Selectel S3/client/API/ownSQL228–229 | Large native exports проверены HTTP fixture; Missing local files UX237 принят; Bridge-only S3 restore через UI239 принят; миграция между buckets/multi-instance и retention; provider/container/Gitea/MaxMind jobs с соответствующими endpoints/аккаунтами; private/paid credentials не выдумывать |
|
| Внешние хранилища и jobs | Локальные API/errors/RBAC/owned SQL; реальные Portal1.3.1/Telegram195–201 и Selectel S3/client/API/ownSQL228–229 | Large native exports проверены HTTP fixture; Missing local files UX237 принят; Bridge-only S3 restore через UI239 принят; Retention240 в own scope принят; миграция между buckets/multi-instance; provider/container/Gitea/MaxMind jobs с соответствующими endpoints/аккаунтами; private/paid credentials не выдумывать |
|
||||||
| Расширенные сетевые конфигурации | GRE/WG/VXLAN/IPsec/OSPF/BFD/BGP сценарии и точные границы записаны | from-pool/EUI-64/multiple-address import/export, outer IPv6, произвольная PKI/OID/policy/path-length и длительные переходы; BFD-only gate гарантией не стал |
|
| Расширенные сетевые конфигурации | GRE/WG/VXLAN/IPsec/OSPF/BFD/BGP сценарии и точные границы записаны | from-pool/EUI-64/multiple-address import/export, outer IPv6, произвольная PKI/OID/policy/path-length и длительные переходы; BFD-only gate гарантией не стал |
|
||||||
| Общий UX, доступность и производительность | Полная UI192 исторически; latest backend25/UI52, scoped contrast/live218 и keyboard206 | Свежая UI226 принята в записанных границах; профильный performance и ручная accessibility/screen-reader приёмка; scoped axe не полный WCAG |
|
| Общий UX, доступность и производительность | Полная UI192 исторически; latest backend25/UI52, scoped contrast/live218 и keyboard206 | Свежая UI226 принята в записанных границах; профильный performance и ручная accessibility/screen-reader приёмка; scoped axe не полный WCAG |
|
||||||
| Границы выпуска | План/доказательства/датированные блоки сохранены; коммиты локальные | Определить требуемые конфигурации и принять результат в этих границах; невыполненные варианты остаются явными ограничениями |
|
| Границы выпуска | План/доказательства/датированные блоки сохранены; коммиты локальные | Определить требуемые конфигурации и принять результат в этих границах; невыполненные варианты остаются явными ограничениями |
|
||||||
@@ -86,7 +98,7 @@ Portal offline JWT действует доexp после logout/role change; э
|
|||||||
|
|
||||||
## Следующая последовательность — 2026-10-14
|
## Следующая последовательность — 2026-10-14
|
||||||
|
|
||||||
1. **240 — retention:** изолированные own SQL/S3 scope, сохранение latest copies по каждому серверу, partial cleanup и точная очистка версий. Исходный каталог приложения не использовать для pruning.
|
1. **241 — большой список:** после изменения237 проверить1000 missing/unknown/both строк, global search/pagination, сохранение last-good и mobile controls. Затем — доступные external jobs и явные границы выпуска.
|
||||||
2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания.
|
2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания.
|
||||||
3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций.
|
3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций.
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -1,6 +1,6 @@
|
|||||||
# Этап 12: итоговая приёмка UX/UI
|
# Этап 12: итоговая приёмка UX/UI
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14:239 — Selectel S3 restore через реальный Portal/UI принят для собственного95-byte скрипта bridge-only:download SHA256 совпал,restore200/receipt и native bridge без ports/IP подтверждены,delete204. Bridge/file/catalog/S3versions очищены; исходные10 строк, storage/schedule сверены целиком и восстановлены; приватные ключи/SQL-снимок удалены. Runtime backend/frontend ux-backups237. Следующий240 — retention в изолированном собственном S3 scope. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт.
|
||||||
|
|
||||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||||
|
|
||||||
@@ -4152,6 +4152,18 @@ Real Portal/browser API, provider local verified: создан один job ро
|
|||||||
Runtime backend ux-backup234/frontend ux-routing218 healthy; новое application image для volume-only fix не требовалось. Пароли CHR не менялись, S3 mutations0 в235, configs body/JWT не опубликованы, private local manifest удалён. Исходные10 missing local files не восстановлены и records не удалены. Force-recreate — не host reboot/power loss/fsync/DR приёмка. Далее236 — UX недоступных local files, затем version retention границы и оставшиеся7 группы матрицы; multi-instance guard не принимается. Этап12.5 открыт.
|
Runtime backend ux-backup234/frontend ux-routing218 healthy; новое application image для volume-only fix не требовалось. Пароли CHR не менялись, S3 mutations0 в235, configs body/JWT не опубликованы, private local manifest удалён. Исходные10 missing local files не восстановлены и records не удалены. Force-recreate — не host reboot/power loss/fsync/DR приёмка. Далее236 — UX недоступных local files, затем version retention границы и оставшиеся7 группы матрицы; multi-instance guard не принимается. Этап12.5 открыт.
|
||||||
|
|
||||||
|
|
||||||
|
## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14)
|
||||||
|
|
||||||
|
В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись.
|
||||||
|
|
||||||
|
При keepCount2 первого сервера и намеренно неправильном S3 secret local old copy удалена первой, затем remote delete отказал:BackupPruneError.pruned=1. Failed row/object сохранены, две новые копии и остальные servers неизменны. После возвращения верного secret retry удалил1, следующий prune вернул0. Второй сервер keepCount1 удалил2 старых copies, сохранилlatest both; третий unselected manual local copy не затронут. Все4 retained files прочитаны compiled service с точными исходными байтами/hash; remote-only localFileStatus=not-stored, остальныеavailable.
|
||||||
|
|
||||||
|
Пять укрупнённых SQL/S3 проверок прошли. Cleanup удалил только planned keys и их5 versions/2delete markers (итого7), final listing0, own catalog0. Wrapper удалил temporary DB/role/container и подтвердил отсутствие DB/role. Временные ключевые файлы workstation/Debian удалены; секреты в публичном JSON отсутствуют. node --check passed; runtime источники/образы не менялись, повторной полной регрессии нет.
|
||||||
|
|
||||||
|
Протокол: [retention240](ux-ui/acceptance/s3-retention240.json). Helpers:s3-backup-retention.mjs/run-s3-backup-retention.sh. Это реальное хранилище с контролируемыми SQL/file fixtures, не native scheduler production collection и не физический lost ACK; продолжительная работа, version lifecycle policy, миграция buckets и multiple backend/writers остаются отдельно. Ошибка S3 signature намеренно введена, пароли CHR не менялись.
|
||||||
|
|
||||||
|
Следующий241 проверяет1000 строк нового missing/unknown/both UX237:поиск, pagination, last-good и mobile controls. Затем уточнить доступные external jobs и границы выпуска; семь общих групп не превращать в обещание фиксированного числа проверок.
|
||||||
|
|
||||||
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
||||||
|
|
||||||
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Тестовый сервер UX/UI — 2026-10-10
|
# Тестовый сервер UX/UI — 2026-10-10
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-14:239 — Selectel S3 restore через реальный Portal/UI принят для собственного95-byte скрипта bridge-only:download SHA256 совпал,restore200/receipt и native bridge без ports/IP подтверждены,delete204. Bridge/file/catalog/S3versions очищены; исходные10 строк, storage/schedule сверены целиком и восстановлены; приватные ключи/SQL-снимок удалены. Runtime backend/frontend ux-backups237. Следующий240 — retention в изолированном собственном S3 scope. Этап12.5 открыт.
|
Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт.
|
||||||
|
|
||||||
| Параметр | Проверенное состояние |
|
| Параметр | Проверенное состояние |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -34,6 +34,18 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro
|
|||||||
|
|
||||||
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json).
|
||||||
|
|
||||||
|
## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14)
|
||||||
|
|
||||||
|
В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись.
|
||||||
|
|
||||||
|
При keepCount2 первого сервера и намеренно неправильном S3 secret local old copy удалена первой, затем remote delete отказал:BackupPruneError.pruned=1. Failed row/object сохранены, две новые копии и остальные servers неизменны. После возвращения верного secret retry удалил1, следующий prune вернул0. Второй сервер keepCount1 удалил2 старых copies, сохранилlatest both; третий unselected manual local copy не затронут. Все4 retained files прочитаны compiled service с точными исходными байтами/hash; remote-only localFileStatus=not-stored, остальныеavailable.
|
||||||
|
|
||||||
|
Пять укрупнённых SQL/S3 проверок прошли. Cleanup удалил только planned keys и их5 versions/2delete markers (итого7), final listing0, own catalog0. Wrapper удалил temporary DB/role/container и подтвердил отсутствие DB/role. Временные ключевые файлы workstation/Debian удалены; секреты в публичном JSON отсутствуют. node --check passed; runtime источники/образы не менялись, повторной полной регрессии нет.
|
||||||
|
|
||||||
|
Протокол: [retention240](ux-ui/acceptance/s3-retention240.json). Helpers:s3-backup-retention.mjs/run-s3-backup-retention.sh. Это реальное хранилище с контролируемыми SQL/file fixtures, не native scheduler production collection и не физический lost ACK; продолжительная работа, version lifecycle policy, миграция buckets и multiple backend/writers остаются отдельно. Ошибка S3 signature намеренно введена, пароли CHR не менялись.
|
||||||
|
|
||||||
|
Следующий241 проверяет1000 строк нового missing/unknown/both UX237:поиск, pagination, last-good и mobile controls. Затем уточнить доступные external jobs и границы выпуска; семь общих групп не превращать в обещание фиксированного числа проверок.
|
||||||
|
|
||||||
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
## 12.5.239 — восстановление из Selectel S3 через реальный интерфейс (2026-10-14)
|
||||||
|
|
||||||
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
Пользователь явно разрешил передачу тестовых S3 access/secret keys на Debian после отказа automatic approval review. Ключи находились только в приватных ignored/0600 файлах и временных настройках приложения. Перед изменением сохранены raw SQL storage/schedule и10 исходных backup rows приватно. Расписание временно остановлено, virtual-hosted S3 сохранён и проверен через live UI с реальным Portal1.3.1/JWT. Использован новый UUID prefix и ровно один собственный95-byte .rsc: добавление bridge mm-ui239-* с comment=mm-ui239 без портов/адресов. Это специально ограниченный скрипт, не native full export и не полное восстановление CHR.
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"date": "2026-10-14",
|
||||||
|
"block": "12.5.240",
|
||||||
|
"scope": "Owned PostgreSQL + compiled retention service + real Selectel S3; no CHR contacts",
|
||||||
|
"prefix": "mmapp-acceptance/c05507bd-c1df-4350-af8b-cb8c8c07ee9d",
|
||||||
|
"passed": true,
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"name": "eight-fixtures-three-servers",
|
||||||
|
"remoteObjects": 5,
|
||||||
|
"localFiles": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "partial-failure-acknowledges-one-local-deletion",
|
||||||
|
"pruned": 1,
|
||||||
|
"failedRowRetained": true,
|
||||||
|
"remoteObjectRetained": true,
|
||||||
|
"otherServersUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "retry-retains-latest-two-and-repeat-noop",
|
||||||
|
"retryPruned": 1,
|
||||||
|
"repeatPruned": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "second-server-retains-latest-and-unselected-manual-copy",
|
||||||
|
"pruned": 2,
|
||||||
|
"retained": [
|
||||||
|
"a3",
|
||||||
|
"a4",
|
||||||
|
"b2",
|
||||||
|
"c0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "retained-content-hashes-and-local-states",
|
||||||
|
"copies": [
|
||||||
|
{
|
||||||
|
"id": "a4",
|
||||||
|
"localFileStatus": "available",
|
||||||
|
"sha256": "9704a7906274a6e758f5f03254b38f00bb4287240ec6fa8b6e8847f6415d36bf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a3",
|
||||||
|
"localFileStatus": "not-stored",
|
||||||
|
"sha256": "6b0cf64533cbd3efd0fd040c32f357d10f93ee66b7b2fcc51bc52b01cd4fc2ec"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b2",
|
||||||
|
"localFileStatus": "available",
|
||||||
|
"sha256": "a698acf949d2a6598f00e4f9cb132b43b9864b2a5f7938fefb651c9075746c06"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c0",
|
||||||
|
"localFileStatus": "available",
|
||||||
|
"sha256": "6c11004b65701dc3228c164f1a050b6e5e52f601088e8fb125d0171797c7d565"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cleanup": {
|
||||||
|
"plannedKeys": [
|
||||||
|
"mmapp-acceptance/c05507bd-c1df-4350-af8b-cb8c8c07ee9d/a4-retention240.rsc",
|
||||||
|
"mmapp-acceptance/c05507bd-c1df-4350-af8b-cb8c8c07ee9d/a3-retention240.rsc",
|
||||||
|
"mmapp-acceptance/c05507bd-c1df-4350-af8b-cb8c8c07ee9d/a1-retention240.rsc",
|
||||||
|
"mmapp-acceptance/c05507bd-c1df-4350-af8b-cb8c8c07ee9d/b2-retention240.rsc",
|
||||||
|
"mmapp-acceptance/c05507bd-c1df-4350-af8b-cb8c8c07ee9d/b0-retention240.rsc"
|
||||||
|
],
|
||||||
|
"versionsBefore": 5,
|
||||||
|
"deleteMarkersBefore": 2,
|
||||||
|
"removed": 7,
|
||||||
|
"versionsAndMarkersRemaining": 0,
|
||||||
|
"ownCatalogRemaining": 0
|
||||||
|
},
|
||||||
|
"chrContacts": 0,
|
||||||
|
"bucketSettingsWrites": 0,
|
||||||
|
"ownedDatabaseAndRoleRemoved": true,
|
||||||
|
"privateKeyFileRemoved": true
|
||||||
|
}
|
||||||
Reference in new issue
Block a user