feat(web/server): seed a ready-to-open demo project on migrate
A freshly cloned + migrated install had no projects, so there was nothing to click on. Add seedDemoProject() (run from db:migrate after seedDefaultOwner, idempotent) that creates a "demo" project and loads three committed fixtures from web/apps/server/seed-data/ — covering one openable file per editor: demo.kicad_sch -> eeschema (Schematic Editor) demo.kicad_pcb -> pcbnew (PCB Editor) demo.kicad_wks -> pl_editor (Drawing Sheet Editor) The sch/pcb are the self-contained ecc83 push-pull demo (version-compatible with this build); the wks is a minimal hand-written drawing sheet. Bytes are committed so seeding needs no submodule checkout at runtime. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8341573c5c
commit
0157741660
5 changed files with 9762 additions and 2 deletions
6156
web/apps/server/seed-data/demo.kicad_pcb
Normal file
6156
web/apps/server/seed-data/demo.kicad_pcb
Normal file
File diff suppressed because it is too large
Load diff
3545
web/apps/server/seed-data/demo.kicad_sch
Normal file
3545
web/apps/server/seed-data/demo.kicad_sch
Normal file
File diff suppressed because it is too large
Load diff
9
web/apps/server/seed-data/demo.kicad_wks
Normal file
9
web/apps/server/seed-data/demo.kicad_wks
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
(page_layout
|
||||||
|
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
|
||||||
|
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
|
||||||
|
(rect (name border:Rect) (start 0 0 ltcorner) (end 0 0 rbcorner) (comment "page border"))
|
||||||
|
(rect (name titleblock:Rect) (start 110 34) (end 2 2) (comment "title block frame"))
|
||||||
|
(tbtext "KiCad WASM — Dummy Test Drawing Sheet" (name title) (pos 100 22) (font (size 2.5 2.5) (bold)))
|
||||||
|
(tbtext "pl_editor web smoke test" (name subtitle) (pos 100 14) (font (size 1.5 1.5)))
|
||||||
|
(tbtext "Sheet: %S / %N" (name sheetnum) (pos 100 6) (font (size 1.3 1.3)))
|
||||||
|
)
|
||||||
|
|
@ -2,7 +2,7 @@ import * as path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||||
import { db, pool } from "./index.js";
|
import { db, pool } from "./index.js";
|
||||||
import { seedDefaultOwner } from "./seed.js";
|
import { seedDefaultOwner, seedDemoProject } from "./seed.js";
|
||||||
|
|
||||||
const here = path.dirname(fileURLToPath(import.meta.url));
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
|
@ -12,6 +12,8 @@ async function main() {
|
||||||
});
|
});
|
||||||
const ownerId = await seedDefaultOwner();
|
const ownerId = await seedDefaultOwner();
|
||||||
console.log(`migrations applied; default owner: ${ownerId}`);
|
console.log(`migrations applied; default owner: ${ownerId}`);
|
||||||
|
// Give a fresh install a ready-to-open demo project (idempotent).
|
||||||
|
await seedDemoProject();
|
||||||
await pool.end();
|
await pool.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
|
import * as fs from "node:fs/promises";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { env } from "../env.js";
|
import { env } from "../env.js";
|
||||||
import { db, pool } from "./index.js";
|
import { db, pool } from "./index.js";
|
||||||
import { owners } from "./schema.js";
|
import { owners } from "./schema.js";
|
||||||
|
import {
|
||||||
|
createProject,
|
||||||
|
getProjectRowBySlug,
|
||||||
|
writeProjectFile,
|
||||||
|
} from "../services/projects.js";
|
||||||
|
|
||||||
/** Ensure the default owner namespace exists (no-auth iteration). */
|
/** Ensure the default owner namespace exists (no-auth iteration). */
|
||||||
export async function seedDefaultOwner(): Promise<string> {
|
export async function seedDefaultOwner(): Promise<string> {
|
||||||
|
|
@ -29,11 +36,52 @@ export async function seedDefaultOwner(): Promise<string> {
|
||||||
return row[0].id;
|
return row[0].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demo project bytes committed at <server>/seed-data/. Resolved relative to this
|
||||||
|
* module so it works both under tsx (src/db/) and compiled (dist/db/) — both are
|
||||||
|
* two levels below the package root, where seed-data lives.
|
||||||
|
*/
|
||||||
|
const SEED_DATA_DIR = new URL("../../seed-data/", import.meta.url);
|
||||||
|
|
||||||
|
const DEMO_SLUG = "demo";
|
||||||
|
const DEMO_NAME = "Demo Project";
|
||||||
|
/** Committed files → project-relative paths. One per openable tool. */
|
||||||
|
const DEMO_FILES = [
|
||||||
|
"demo.kicad_sch", // eeschema (Schematic Editor)
|
||||||
|
"demo.kicad_pcb", // pcbnew (PCB Editor)
|
||||||
|
"demo.kicad_wks", // pl_editor (Drawing Sheet Editor)
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seed a ready-to-open demo project so a freshly cloned + migrated install has
|
||||||
|
* something to click on (and to exercise the tool wiring). Idempotent: skips if
|
||||||
|
* the "demo" project already exists. Reads bytes from the committed seed-data/
|
||||||
|
* dir, so it needs no submodule checkout at runtime.
|
||||||
|
*/
|
||||||
|
export async function seedDemoProject(): Promise<void> {
|
||||||
|
if (await getProjectRowBySlug(DEMO_SLUG)) {
|
||||||
|
console.log(`demo project "${DEMO_SLUG}" already exists — skipping`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = await createProject(DEMO_NAME, DEMO_SLUG);
|
||||||
|
const row = await getProjectRowBySlug(DEMO_SLUG);
|
||||||
|
if (!row) throw new Error("demo project vanished right after creation");
|
||||||
|
|
||||||
|
for (const name of DEMO_FILES) {
|
||||||
|
const data = await fs.readFile(fileURLToPath(new URL(name, SEED_DATA_DIR)));
|
||||||
|
await writeProjectFile({ project: row, rawPath: name, data });
|
||||||
|
console.log(` seeded ${DEMO_SLUG}/${name} (${data.length} bytes)`);
|
||||||
|
}
|
||||||
|
console.log(`seeded demo project "${project.slug}" with ${DEMO_FILES.length} files`);
|
||||||
|
}
|
||||||
|
|
||||||
// Allow running standalone: `pnpm db:seed`.
|
// Allow running standalone: `pnpm db:seed`.
|
||||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||||
seedDefaultOwner()
|
seedDefaultOwner()
|
||||||
.then((id) => {
|
.then(async (id) => {
|
||||||
console.log(`seeded default owner: ${id}`);
|
console.log(`seeded default owner: ${id}`);
|
||||||
|
await seedDemoProject();
|
||||||
return pool.end();
|
return pool.end();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue