Skip to the content.

Architecture

RoeStack follows the classic Model-View-Controller (MVC) design pattern. Each layer has a clear responsibility, which keeps the codebase predictable and makes it easier for several developers to work in parallel without colliding.

Directory Layout

app/
  controller/    Express route handlers; the C in MVC.
  model/         Data access layer; the M in MVC.
    classes/     Plain JavaScript classes that represent domain entities.
    middleware/  Express middleware that operates on the model layer.
    db.js        Shared MySQL connection pool and query helper.
  views/         Pug templates; the V in MVC.
    layout.pug   Shared base layout.
    pages/       Top-level pages rendered by controllers.
    partials/    Reusable fragments included by pages.
  utils.js       Helpers shared across layers.

The Three Layers

Model

The model layer is everything under app/model/. It is the only layer that talks to the database.

Controllers never write SQL directly. They ask the model layer for the data they need.

View

The view layer is everything under app/views/. Views are Pug templates, rendered server-side by Express.

Views never call into the model directly. They render whatever data the controller hands them via res.render(template, data).

Controller

The controller layer is everything under app/controller/. Controllers are Express route handlers — one file per major feature area:

A controller’s job is to read the request, call the appropriate model methods, decide which view to render, and pass the data to it. Controllers do not contain SQL and do not contain HTML.

Request Lifecycle

A typical request follows the same path through the three layers:

  1. Express receives the HTTP request and matches it against a route registered in app/controller/app.js.
  2. Middleware runs in order: session, body parsers, validators, any feature-specific middleware from app/model/middleware/.
  3. The controller handler executes. It calls one or more methods on the model classes to fetch or mutate data.
  4. The model runs the SQL via the shared pool in app/model/db.js and returns plain objects or instances of the domain classes.
  5. The controller calls res.render('pages/...', data) (or res.redirect, or returns JSON).
  6. Pug compiles the template, the layout, and any included partials into HTML.
  7. The response is sent back to the browser. Vanilla JavaScript under static/js/ provides client-side interactivity.

Static Assets

Static files (CSS, client JavaScript, images, icons, SVGs) live under static/ and are served by Express’s static-file middleware. The view templates reference them via absolute paths such as /styles/login.css or /js/sidebar.js.

Why MVC for this project

MVC was chosen because it matches how the team divided work: one person could iterate on a Pug view or CSS file without touching SQL, another could add a query in a model class without breaking the templates, and route changes lived in a single controller file. The boundary between layers also made it straightforward to add cross-cutting features (sessions, validators, file uploads) as middleware without rewriting feature code.