refactor: isolate playback and upload use cases
ci / module boundaries / boundaries (push) Successful in 6s
ci / api / api (push) Successful in 47s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m2s
ci / db / db (push) Successful in 1m4s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m30s
ci / ts / ts (packages + web) (push) Successful in 2m54s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m14s

This commit is contained in:
mrleo1nid committed 2026-10-22 13:52:16 +03:00
1 parent c84f90e2cc
commit e158558da3
56 files changed
+3337 -2196

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
import { readdirSync, readFileSync } from 'node:fs';
import { resolve, relative } from 'node:path';
import { fileURLToPath } from 'node:url';
const root = fileURLToPath(new URL('../', import.meta.url));
function sources(dir, extension) {
return readdirSync(resolve(root, dir), { withFileTypes: true }).flatMap((entry) => {
const path = `${dir}/${entry.name}`;
return entry.isDirectory() ? sources(path, extension) : path.endsWith(extension) ? [path] : [];
});
}
// Check the boundaries introduced by the refactor. Existing query projections and
// composition roots are deliberately outside these use-case-specific rules.
const rules = [
{
files: sources('packages/core/src', '.ts'),
forbidden: /(?:from\s*|import\s*)['"](?:[^'"]*apps\/|(?:@react-native[^'"]*|react(?:-native)?(?:[-\/]|['"]))|expo(?:[-\/]|['"])|\.\.[^'"]*(?:web|mobile|desktop)\/)/,
message: 'core must not import platform/UI implementations',
},
{
files: ['service.go', 'worker.go', 'placement.go', 'batch.go'].map((p) => `services/api/internal/uploads/${p}`),
forbidden: /github\.com\/jackc\/pgx|\.store\.pool\b|\b(?:tx|pool)\.(?:Exec|Query|QueryRow)\(/,
message: 'upload SQL and pgx belong in store/persistence adapters',
},
{
files: sources('apps/web/src/features/uploads', '.tsx').filter((p) => !p.endsWith('/common.tsx')),
forbidden: /\b(?:session|client)\.(?:GET|POST|PUT|PATCH|DELETE)\(/,
message: 'upload views must use feature API/queries',
},
];
const errors = [];
for (const rule of rules) {
for (const path of rule.files) {
const text = readFileSync(resolve(root, path), 'utf8');
text.split(/\r?\n/).forEach((line, i) => {
if (rule.forbidden.test(line)) errors.push(`${relative(root, resolve(root, path))}:${i + 1}: ${rule.message}`);
});
}
}
if (errors.length) {
console.error(errors.join('\n'));
process.exitCode = 1;
} else {
console.log('Module boundary checks passed.');
}