Build a Crash-Safe Collaborative Editor with Journaling

Computer Science

Build a Crash-Safe Collaborative Editor with Journaling

JavaScriptNode.jsNode.js built-in HTTP module

Build a Crash-Safe Collaborative Editor with Journaling

Build a small browser editor that records incremental changes in a durable journal, periodically saves full checkpoints, and restores unsaved work after a simulated crash. Along the way, you will make the tradeoff between frequent journal writes and larger checkpoint writes visible in a runnable project.

3 modules10 lessonsComputer ScienceJavaScriptNode.jsNode.js built-in HTTP moduleHTMLCSSBrowser DOM APIsJSON files for local persistence

What you learn by building this

  • Represent editor changes as ordered, incremental operations
  • Persist journal entries and full checkpoints using a simple local storage layer
  • Recover the latest editor state by replaying journal entries after a checkpoint
  • Simulate a crash and verify that unsaved changes are restored
  • Explain why incremental writes complement rather than replace full checkpoints
  • Expose recovery behavior through a small browser-based editor

Learning Journey

1

Make the Editor Work Before Persistence

3 lessons

Create the smallest usable editor and establish the document-change model that later lessons will persist. This module stands alone so the learner can run and demonstrate the project immediately.

2

Add Journaling and Full Checkpoints

3 lessons

Introduce the two complementary persistence paths: frequent incremental journal entries and less frequent full checkpoints. The learner will make sequence numbers and recovery metadata observable before simulating failure.

3

Recover After a Simulated Crash

4 lessons

Use the project’s checkpoint and journal data to reconstruct the latest document state after in-memory state disappears. The finished project will provide a repeatable crash-and-recovery demonstration.

Public lesson

Create a Runnable Browser Editor

Predict

What will happen?

Make the browser editor respond to editing

The editor will be more useful if it reports what is happening as you type. Before changing anything, predict what you expect:

If the document starts with some text and you type three characters, should the status panel update only after a refresh, or immediately?

The browser can observe each edit through the input event. The Node.js server’s job is to deliver the page; after the page loads, the browser handles the interaction.

Tasks

1. Add the document area and status panel

Open the existing server entry file and find the HTML that it sends for the main page. Inside its <body>, make the document and status elements explicit:

<main>
  <h1>Browser Editor</h1>

  <div
    id="document"
    contenteditable="true"
    role="textbox"
    aria-label="Document"
  >
    Start writing here.
  </div>

  <p id="status" aria-live="polite">TODO: initial status</p>
</main>

Adapt the surrounding markup rather than replacing unrelated code. The important relationship is:

  • #document is where the learner edits.
  • #status is where the page reports the current document state.
  • contenteditable="true" makes an ordinary element editable without adding a framework.

Run the project using its documented command and open the local address it prints. Click the document area and type. At this point, the text should be editable, but the status will not react yet. That failed check is useful: it shows that making something editable and observing it are separate jobs.

Tasks

2. Connect edits to the status panel

Add a script near the end of the page, after the two elements above:

<script>
  const documentArea = document.querySelector("#document");
  const status = document.querySelector("#status");

  function updateStatus() {
    // Choose the text property that should represent the visible document.
    // Then replace the placeholder status message.
  }

  // Register the event that fires when the user changes the document.
  // Call updateStatus from the event handler.

  updateStatus();
</script>

Complete the two comments yourself. Your status should show the number of characters in the document, ignoring leading and trailing whitespace. One expression that helps is:

documentArea.innerText.trim().length

For example, the body of updateStatus could be shaped like this, but adapt the wording to your editor:

const characterCount = /* calculate the trimmed character count */;
status.textContent = /* make a readable status message */;

The event listener should listen for "input":

documentArea.addEventListener("input", () => {
  // update the status here
});

The separate updateStatus() call matters because the document already contains initial text when the page loads. Without it, the status would remain wrong until the first keystroke.

Tasks

3. Check the behavior in the browser

Reload the page, then check these cases:

  1. The status is correct before you type.
  2. Add one character. The status changes immediately.
  3. Select all the document text and replace it. The status changes again.
  4. Delete all the text or enter only spaces. The trimmed count becomes zero.
  5. Refresh the page. The initial document and its initial status return.

Find the bug

Something's wrong — can you spot it?

If the text changes but the status does not, inspect the browser’s developer console. The most useful questions are:

  • Does querySelector("#document") find the same element whose id you wrote?
  • Does the status element really have id="status"?
  • Is the script running after those elements exist?
  • Did the server send the newest version, or does the browser need a hard refresh?

What this small change demonstrates

There are two different moments in this app:

Node.js server
    └── sends the HTML page
            └── browser loads it
                    ├── user edits #document
                    └── input event updates #status

The server does not need to handle every keystroke for this first editor. It only serves the page. The browser owns the immediate interaction, so the feedback feels instant and the server remains simple.

This distinction will matter if the editor later needs saved documents or multiple users: local editing can stay responsive, while a separate server feature can decide when and how changes are stored or shared. For now, the visible check is deliberately modest: edit text in the browser and watch the status panel prove that the page noticed.

Course Outline

3 modules · 10 lessons

Make the Editor Work Before Persistence

Add Journaling and Full Checkpoints

Recover After a Simulated Crash

Learn by building your own version.

Remix this public project to open the workspace, follow the guided build, and let the AI mentor teach you through the work instead of doing it for you.