Noderyx Framework

Noderyx Framework: start with the project structure

A guided tour of the folders, routes, controllers, views, and services behind this site, and how one request travels through them.

Nov 6, 2026 · By Administrator
Noderyx Framework: start with the project structure

The quickest way to feel at home in a Noderyx project is to learn where things live. This site was generated with npm create noderyxcrm, and every folder has one clear job. In this tour we walk through the layout, then follow a real request through it.

The folders at a glance

Path What it holds server.js Boots the app, registers services, middleware, and routes noderyx.config.js App, database, cache, mail, and security settings from .env routes/ web.js for public URLs, cms.js for the /nodecms admin app/Controllers/ Request handlers such as CmsController and AdminController app/Services/ CmsStore, ThemeManager, PluginManager, BackupManager resources/views/ Noderframe templates for the site, admin, and error pages public/ Stylesheets, browser scripts, and installed theme assets storage/ cms.json content, uploaded themes, and generated build output database/ Migrations, seeders, and maintenance scripts packages/ Local plugins that load automatically at startup

server.js: where everything is wired together

The entry point loads .env, reads noderyx.config.js, and creates the application with noderyx(). It then registers shared services with app.provide, so any controller can ask for them by name.

const app = noderyx({ views, public: publicDir, security }); const cms = await CmsStore.create(config); app.provide("cms", cms); app.provide("themes", new ThemeManager()); app.use(requireCmsAuthentication); registerWebRoutes(app); registerCmsRoutes(app);

The order matters. Services are provided first. The authentication middleware runs before any route, and only then are routes registered. Local plugins under packages/ load last, so they can add routes or services of their own.

Routes map URLs to controller actions

routes/web.js is short enough to read in one sitting. Each line pairs an HTTP method and path with a controller action:

app.get("/", CmsController.handle("home")); app.get("/post/:slug", CmsController.handle("post")); app.post("/post/:slug/comments", CmsController.handle("addComment")); app.get("/category/:slug", CmsController.handle("category"));

Named segments such as :slug arrive in the controller as this.params.slug. The admin routes in routes/cms.js all live under one CMS_PATH constant, /nodecms, which makes the namespace easy to protect in one place.

A laptop showing a code editor beside a stack of books

Controllers decide what happens

A controller extends the framework's Controller class. Its actions read the request through this.params, this.query, and this.body. They fetch services with this.service(), and they respond with this.render(), this.json(), or this.abort().

export class CmsController extends Controller { store() { return this.service("cms"); } async post() { const post = await this.store().findPublished(this.params.slug, "post"); if (!post) return this.abort(404); return this.render("site/post", { post }); } }

Services hold the real logic

Controllers stay thin because services do the work. CmsStore reads and writes all content. ThemeManager decides which template and stylesheet the active theme uses. PluginManager tracks which local packages are enabled. Because services are plain classes, the test suite can exercise them directly, without starting a server.

Views are Noderframe templates

Templates in resources/views use indentation instead of closing tags. A line starts with an element and its classes, then attributes, then quoted text. Control flow uses if, else, and for.

article.article-wrap h1 "{{post.title}}" p.article-lead "{{post.excerpt}}" if post.featuredImage img.article-image src="{{post.featuredImage}}" alt="{{post.title}}" for item in navigation a href="{{item.url}}" "{{item.label}}"

Values inside {{ }} are escaped on output. This means text from the CMS cannot inject markup into the page.

Follow one request

  • A reader opens /post/noderyx-project-structure.
  • requireCmsAuthentication sees a public path and calls next().
  • routes/web.js matches /post/:slug and calls CmsController.post.
  • The action asks CmsStore for the published post with that slug.
  • ThemeManager returns the active theme's post template, site/post.
  • The template renders the post's blocks and comments into HTML.

The scripts you will use every day

Command What it does npm run dev Serve with file watching while you work npm run build Compile views into storage/generated npm test Run the node:test suite in tests/ npm run seed Create the admin user from CMS_ADMIN_EMAIL and CMS_ADMIN_PASSWORD npm run migrate Apply database migrations
Try it

Open routes/web.js, pick one route, and trace it to its controller action and template. Ten minutes of tracing teaches more than an hour of reading folder names.

Comments

Leave a comment