feat(spaces): добавить изолированные пространства и multi-user
Docker / build (push) Failing after 20s

Полная изоляция данных по space, Share (ACL) и Assign, switcher и участники в UI.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-07-18 15:42:54 +07:00
co-authored by Cursor
parent f26b2c8777
commit e360efb885
47 changed files with 2675 additions and 237 deletions
+82 -3
View File
@@ -2,8 +2,26 @@ import { closeDb, getSqlite } from './index.js'
import { resetRuntimeMigrate } from './runtime-migrate.js'
const TEST_SCHEMA = `
CREATE TABLE IF NOT EXISTS spaces (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT NOT NULL,
kind TEXT NOT NULL DEFAULT 'personal',
ownerUserId TEXT,
createdAt TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS space_members (
spaceId TEXT NOT NULL,
userId TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'member',
createdAt TEXT NOT NULL,
UNIQUE(spaceId, userId)
);
CREATE TABLE IF NOT EXISTS providers (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
name TEXT NOT NULL,
website TEXT,
contact TEXT,
@@ -17,6 +35,7 @@ CREATE TABLE IF NOT EXISTS providers (
CREATE TABLE IF NOT EXISTS provider_accounts (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
providerId TEXT NOT NULL,
name TEXT NOT NULL,
panelUrl TEXT,
@@ -36,6 +55,7 @@ CREATE TABLE IF NOT EXISTS provider_accounts (
CREATE TABLE IF NOT EXISTS vps (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
ip TEXT,
ipv6 TEXT,
additionalIps TEXT,
@@ -76,8 +96,20 @@ CREATE TABLE IF NOT EXISTS vps (
FOREIGN KEY (providerAccountId) REFERENCES provider_accounts(id)
);
CREATE TABLE IF NOT EXISTS vps_grants (
id TEXT PRIMARY KEY,
vpsId TEXT NOT NULL,
fromSpaceId TEXT NOT NULL,
toSpaceId TEXT NOT NULL,
permission TEXT NOT NULL DEFAULT 'read',
grantedByUserId TEXT,
createdAt TEXT NOT NULL,
UNIQUE(vpsId, toSpaceId)
);
CREATE TABLE IF NOT EXISTS payments (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
type TEXT NOT NULL,
date TEXT NOT NULL,
amount REAL NOT NULL,
@@ -90,6 +122,7 @@ CREATE TABLE IF NOT EXISTS payments (
CREATE TABLE IF NOT EXISTS balance_ledger (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
type TEXT NOT NULL,
date TEXT NOT NULL,
amount REAL NOT NULL,
@@ -103,6 +136,7 @@ CREATE TABLE IF NOT EXISTS balance_ledger (
CREATE TABLE IF NOT EXISTS sync_log (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
accountId TEXT NOT NULL,
startedAt TEXT NOT NULL,
finishedAt TEXT,
@@ -116,6 +150,7 @@ CREATE TABLE IF NOT EXISTS sync_log (
CREATE TABLE IF NOT EXISTS active_tariffs (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
providerAccountId TEXT NOT NULL,
providerId TEXT NOT NULL,
externalId TEXT NOT NULL,
@@ -139,8 +174,17 @@ CREATE TABLE IF NOT EXISTS active_tariffs (
FOREIGN KEY (providerId) REFERENCES providers(id)
);
CREATE TABLE IF NOT EXISTS tariff_sync_options (
providerAccountId TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
datacenters TEXT,
periods TEXT,
syncedAt TEXT
);
CREATE TABLE IF NOT EXISTS settings (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
baseCurrency TEXT,
ratesUrl TEXT,
autoConvert INTEGER,
@@ -165,11 +209,13 @@ CREATE TABLE IF NOT EXISTS settings (
integrationToken TEXT,
integrationEnabled INTEGER,
integrationLastSyncAt TEXT,
cfdmApiUrl TEXT
cfdmApiUrl TEXT,
showQuickActions INTEGER
);
CREATE TABLE IF NOT EXISTS vps_domains (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
vpsId TEXT,
fqdn TEXT NOT NULL,
zoneName TEXT NOT NULL,
@@ -187,6 +233,7 @@ CREATE TABLE IF NOT EXISTS vps_domains (
CREATE TABLE IF NOT EXISTS notification_log (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
event TEXT NOT NULL,
channel TEXT NOT NULL,
status TEXT NOT NULL,
@@ -198,6 +245,7 @@ CREATE TABLE IF NOT EXISTS notification_log (
CREATE TABLE IF NOT EXISTS notification_state (
key TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
lastFingerprint TEXT,
lastSentAt TEXT,
lastStatus TEXT
@@ -205,12 +253,34 @@ CREATE TABLE IF NOT EXISTS notification_state (
CREATE TABLE IF NOT EXISTS server_projects (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
name TEXT NOT NULL,
color TEXT,
sortOrder INTEGER DEFAULT 0,
notes TEXT,
createdAt TEXT
);
CREATE TABLE IF NOT EXISTS audit_log (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
entity TEXT NOT NULL,
entityId TEXT NOT NULL,
action TEXT NOT NULL,
diff TEXT,
actorUserId TEXT,
createdAt TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS vps_health_checks (
id TEXT PRIMARY KEY,
spaceId TEXT NOT NULL DEFAULT 'space-main',
vpsId TEXT NOT NULL,
checkedAt TEXT NOT NULL,
status TEXT NOT NULL,
latencyMs INTEGER,
error TEXT
);
`
export function resetTestDb(): void {
@@ -219,13 +289,20 @@ export function resetTestDb(): void {
process.env.DB_PATH = ':memory:'
const sqlite = getSqlite()
sqlite.exec(TEST_SCHEMA)
const now = new Date().toISOString()
sqlite
.prepare(
`INSERT OR IGNORE INTO spaces (id, name, slug, kind, ownerUserId, createdAt)
VALUES ('space-main', 'Основное', 'main', 'main', NULL, ?)`,
)
.run(now)
}
export function seedTestProvider(id = 'prov-1'): void {
const sqlite = getSqlite()
sqlite
.prepare(
`INSERT INTO providers (id, name, apiType, apiBaseUrl) VALUES (?, 'Test Host', 'billmanager', 'https://bm.test')`,
`INSERT INTO providers (id, spaceId, name, apiType, apiBaseUrl) VALUES (?, 'space-main', 'Test Host', 'billmanager', 'https://bm.test')`,
)
.run(id)
}
@@ -233,6 +310,8 @@ export function seedTestProvider(id = 'prov-1'): void {
export function seedTestProviderAccount(id = 'acc-1', providerId = 'prov-1'): void {
const sqlite = getSqlite()
sqlite
.prepare(`INSERT INTO provider_accounts (id, providerId, name) VALUES (?, ?, 'Test Account')`)
.prepare(
`INSERT INTO provider_accounts (id, spaceId, providerId, name) VALUES (?, 'space-main', ?, 'Test Account')`,
)
.run(id, providerId)
}