CODEX revised with following function: 1. GDS building, 2. different user group with different authority.

This commit is contained in:
2026-05-28 20:35:49 +08:00
parent e6e9e13cf2
commit 1215bf978a
25 changed files with 439 additions and 196 deletions
+46
View File
@@ -0,0 +1,46 @@
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const root = path.resolve(__dirname, '..');
const backend = path.join(root, 'backend');
const databasePy = fs.readFileSync(path.join(backend, 'database.py'), 'utf8');
const serverPy = fs.readFileSync(path.join(backend, 'server.py'), 'utf8');
const dashboardHtml = fs.readFileSync(path.join(root, 'frontend', 'dashboard.html'), 'utf8');
assert(
databasePy.includes('user_group'),
'database migration should add users.user_group'
);
assert(
databasePy.includes("'admin'") && databasePy.includes("'manager'"),
'admin should be migrated/seeded as manager'
);
assert(
databasePy.includes("'engineer'") && databasePy.includes("'developers'"),
'engineer should be migrated/seeded as developers'
);
assert(
serverPy.includes("session['user_group']") || serverPy.includes('session["user_group"]'),
'login should store user_group in the session'
);
assert(
serverPy.includes('"user_group"'),
'/api/profile should return user_group'
);
assert(
fs.existsSync(path.join(backend, 'pdk_access.py')),
'backend/pdk_access.py should resolve role-based PDK roots'
);
assert(
serverPy.includes('pdk_root_for_session'),
'server should resolve PDK root per logged-in user group'
);
assert(
dashboardHtml.includes('profile-group'),
'dashboard should show read-only profile group information'
);
assert(
!dashboardHtml.includes('profile-group"></select'),
'profile group must not be editable'
);
+32
View File
@@ -0,0 +1,32 @@
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const root = path.resolve(__dirname, '..');
const serverPy = fs.readFileSync(path.join(root, 'backend', 'server.py'), 'utf8');
const canvasHtml = fs.readFileSync(path.join(root, 'frontend', 'canvas.html'), 'utf8');
assert(
serverPy.includes('EXPORT_ROOT'),
'server should build GDS exports into a temporary export root'
);
assert(
serverPy.includes("@app.route('/api/exports/<export_id>/<filename>'"),
'server should expose an authenticated export download route'
);
assert(
serverPy.includes('download_url'),
'Build GDS response should include download_url'
);
assert(
serverPy.includes('cleanup_expired_exports'),
'server should clean exports older than the retention period'
);
assert(
canvasHtml.includes('download_url'),
'frontend should read download_url from Build GDS response'
);
assert(
canvasHtml.includes('document.createElement') && canvasHtml.includes('.download'),
'frontend should trigger a browser download for generated GDS'
);
+14
View File
@@ -18,10 +18,18 @@ assert(
fs.existsSync(path.join(backendDir, 'gds_builder.py')),
'backend/gds_builder.py should build hierarchical GDS from saved project YAML'
);
assert(
fs.existsSync(path.join(backendDir, 'routed_layout_preview.py')),
'backend/routed_layout_preview.py should create routed SVG previews through mxpic_router'
);
assert(
serverPy.includes('create_layout_svg_from_gds'),
'save-layout route should create a GDS-derived layout SVG preview'
);
assert(
serverPy.includes('create_routed_layout_svg'),
'save-layout route should use routed preview generation when links exist'
);
assert(
serverPy.includes('svg_url'),
'save-layout response should include an svg_url for the new layout tab'
@@ -64,3 +72,9 @@ assert(
layoutPreviewPy.includes('_BB.gds') || layoutPreviewPy.includes('gds_path'),
'layout_preview.py should resolve public GDS assets for placed components'
);
const gdsBuilderPy = fs.readFileSync(path.join(backendDir, 'gds_builder.py'), 'utf8');
assert(
gdsBuilderPy.includes('_cells_have_links') && gdsBuilderPy.includes('Routed Build GDS requires mxpic_router'),
'Build GDS should not silently fall back to unrouted gdstk when links are present'
);