Skip to content

[Bug] Build records persist to flat files instead of the BuildRecord table #5

Description

@sjohnston1972

Part of the "SQLite migration is half-done" parent issue.

Background

Sandbox builds are meant to live in the SQLite builds table (BuildRecord in backend/app/db/models.py:110). The legacy_import.py script already knows how to write that table.

Problem / Goal

The runtime build code still uses flat files:

  • backend/app/agents/build.py:120 save_build writes data/builds/<id>.json.
  • build.py:129 get_build, build.py:137 delete_build, build.py:151 list_builds all read/scan that directory.

So the builds table is empty during normal use, and the orphan-nulling logic in runs.py:99 / customers.py:92 never has anything to act on.

Goal: move build persistence to the BuildRecord table, keeping the record JSON shape identical.

Where to look

  • backend/app/agents/build.py:87-188_builds_dir, save_build, get_build, delete_build, list_builds.
  • backend/app/db/models.py:110-124BuildRecord columns: id (12-char hex), section_design_id, model, record (JSON), saved_at, gns3_project_id.
  • backend/app/db/legacy_import.py:144-191import_builds maps a flat-file build onto BuildRecord; mirror that field-for-field.
  • backend/app/api/build.py — callers: /list, /{id}, delete, deploy-gns3 (which re-saves the record with a gns3 block via save_build, see api/build.py:529-543).

Suggested approach

  1. Rewrite save_build to upsert a BuildRecord row: keep the 12-char hex id, put the full dict in record, and denormalize model, saved_at, gns3_project_id, and section_design_id into their columns.
  2. Rewrite get_build/delete_build/list_builds to query the table. list_builds currently derives node/link counts and kinds from record["topology"] — preserve that summary shape so the Sandbox page is unchanged.
  3. Make sure the GNS3 deploy path (api/build.py:_do_deploy) still round-trips: it calls get_build → mutates rec["gns3"]save_build(rec). That must now update the row's record and gns3_project_id.

Acceptance criteria

  • Creating a build inserts a row into builds; no data/builds/*.json is written at runtime.
  • GET /api/build/list and GET /api/build/{id} return the same JSON shape as before, sourced from SQLite.
  • Deleting a build removes its row; deploy-to-GNS3 updates the row's gns3 block and gns3_project_id.
  • After deleting a run/customer, builds built from its sections have section_design_id nulled (the existing orphan logic now works).

Testing

Local backend. Build a sandbox (see parent Testing), then:

  • sqlite3 data/netbud.sqlite "select id, model, gns3_project_id from builds;" shows the row.
  • GET /api/build/list returns it with correct node_count/link_count/kinds.
  • Deploy to GNS3 (if configured) and confirm gns3_project_id populates.
    Add a unit test covering save → get → list → delete against an in-memory SQLite engine.

Out of scope

  • The build journal table (separate sub-issue).
  • Design lookup for building (separate sub-issue 1a).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions