Build EdrawMax

KINDAback to the verdict

0%0 of 16 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A browser diagram editor whose hard problems are never being the only copy of your own document, connectors that stay attached to shapes through every move, and an undo stack that is provably complete rather than mostly complete.

estimated effort multi-daythe files for this build are in the project pack

RuntimeReact with TypeScript on Vite, no server at allCanvasSVG for the document, with hit testing kept off the render pathPersistenceFiles the user chose, with an indexed database used only as a working cacheHistoryA command stack where every mutation carries its inverseExportSVG carrying the source document as metadata, plus raster at a chosen scale

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the development server, the build and the test suite.

    Get it nodejs.org or your version manager. open ↗

    Verify node --version prints v22 or higher

  2. have readyfree

    Why The persistence design exists because these behave differently, and testing in only one of them guarantees you ship the fallback untested.

    Get it Any two current browsers from different engine families.

    Verify Save and reopen work in both, by the intended path in each

  3. decidefree

    Why This is the decision the whole build hangs on, and making it implicitly means making it wrong.

    Get it Write down that the cache covers unsaved changes since the last file write and nothing else. open ↗

    Verify The statement appears in the README and a test clears storage and loses nothing saved

  4. have readyfree

    Why Connector routing and text sizing only misbehave on real content, and a demo of four boxes will never show you the problem.

    Get it Rebuild an architecture or process diagram you actually use.

    Verify It renders, exports and reopens with labels intact

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- the document file: format_version, pages, shapes, connectors, styles · one JSON object, readable without the editor
- pages(id, name, ordinal, width, height, grid) · a document is pages, and a single page is a document with one
- shapes(id, page_id, kind, x, y, w, h, rotation, style_ref, text, ports_json) · ports are named points, because connectors attach to names rather than coordinates
- connectors(id, page_id, from_shape, from_port, to_shape, to_port, waypoints_json, routing, style_ref) · never two absolute points
- styles(id, name, declarations_json) · named, so changing the look of every process box is one edit
- file_state(handle_ref, last_written_at, last_written_hash, dirty) · surfaced in the interface rather than living in a variable
- commands: an in-memory stack of do and undo pairs; nothing in the application mutates a document outside one.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
CACHE_DB_NAMErequireddiagram-cacheThe indexed database used for crash recovery only. Evictable by design.
SAVE_PROMPT_SECONDSrequired120How long a new document may go without a file before the editor insists.
STALE_SAVE_WARN_MINUTESrequired10After this long without a file write, the indicator changes state visibly.
TARGET_SHAPE_COUNTrequired500The size the performance test generates and the README promises.
EXPORT_SCALE_DEFAULTrequired2Default raster scale. The dialogue shows resulting pixel dimensions.

The build, in order

  1. A file on disk within the first minute

    Every document has somewhere real to live and the interface says when it last got there.

    1. One of them can be evicted and it is not the file.

      Files src/persist/file.tssrc/persist/cache.ts

    2. The number that tells you whether your work exists.

      Files src/ui/SaveState.tsx

    3. Never resolve somebody else's conflict for them.

      Files src/persist/reconcile.tstests/reconcile.test.ts

    done when · tick each as it passes
    watch out
    • Treating the indexed database as the document store gives you a fast first version and a support request in six weeks from somebody whose month-old diagram is gone, because script-writable storage is evictable under published rules and the user did nothing wrong. Write to a file the user chose, keep the cache for crash recovery only, and make the last-written-to-file time something on screen rather than something in a console log.
    • When the cache and the file disagree after a crash, silently preferring one of them loses the other, and whichever you pick will be the wrong one for somebody. Store a hash of what you last wrote, detect the divergence on open, and offer both copies with their times rather than resolving it for the user.
  2. Connectors that stay attached

    Moving a box moves everything joined to it, and manual bends survive.

    1. The identifier survives the move; the coordinate does not.

      Files src/model/connectors.tstests/connectors.test.ts

    2. So a small move does not erase somebody's work.

      Files src/routing/waypoints.ts

    3. Run it in the suite after every mutating operation.

      Files src/model/validate.tstests/validate.test.ts

    done when · tick each as it passes
    watch out
    • Storing a connector as two absolute points takes five minutes and detaches the first time anybody moves a box, which is the single thing that makes a diagram tool feel broken; re-routing from scratch on every move instead throws away the bends somebody spent ten minutes placing. Anchor to shape and port, keep waypoints relative to the anchors, and drop a waypoint only when it has become impossible, saying so rather than silently straightening the line.
  3. Undo that is provably complete

    Any sequence of operations, fully undone, returns the document exactly as it was.

    1. And assert in a test that none is missing one.

      Files src/history/commands.tstests/inverses.test.ts

    2. It is the cheapest way to find the operation you forgot.

      Files tests/undo-property.test.ts

    3. Undo that loses your selection makes you check what happened.

      Files src/history/stack.ts

    done when · tick each as it passes
    watch out
    • Undo by snapshotting the whole document is correct and becomes unusable on a large diagram because every keystroke copies it, while undo written per operation is fast and is wrong in exactly the one operation somebody forgot to cover, which you will find after a user has lost an hour. Make every mutation go through a command with an inverse, assert in a test that every registered command type has one, and let a property test over random sequences find the gap instead of a user.
  4. An export you can reopen

    The SVG that goes to a colleague carries the document that made it.

    1. The picture and the document should be one file.

      Files src/export/svg.tstests/export-roundtrip.test.ts

    2. Both consequences, in words, at the moment of choosing.

      Files src/ui/ExportDialog.tsx

    3. Nobody wants to guess what scale four means.

      Files src/export/raster.ts

    done when · tick each as it passes
    watch out
    • An SVG whose text elements name a font renders with overlapping labels on any machine that lacks it, and converting text to outlines fixes the picture while making the words unselectable and the file much larger. This is a trade-off rather than a bug, so put it in the export dialogue with both consequences written out, and embed the source document so the editable version travels with whichever picture was chosen.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more diagrams.