fog-node is "FOG 2.0" — a from-scratch Sails.js
(Node.js) rewrite of the FOG Project server, backed by MongoDB. It is not a
port of the PHP FOG 1.x codebase: it re-architects the domain (e.g. a
Workflow abstraction with no 1.x equivalent, generic :model CRUD, Sails
associations in place of 1.x's explicit association tables, "Module" as the
snapin analog). "Catching up to 1.6" therefore means reimplementation, never a
code merge.
This document tracks where the rewrite stands and the plan toward feature parity with FOG 1.6.
Runtime works. With MongoDB available and setup run, the app lifts cleanly on
both Node 22 and Node 26 (Server lifted, port 1337). The status API, local +
JWT auth, and the seeded Administrator account are functional.
Implemented today:
- 10 core models:
Host,Image,PxeMenu,Role,Setting,StorageGroup,StorageNode,Task,User,Workflow. (Groupremoved — ADR 0001;Snapin(#55/#56) andPrinter(#57) extracted to plugins.) - Generic CRUD driven by a
:modelroute param (api/controllers/general/*), plus DataTables list/columns endpoints. - Auth: passport local + JWT (cookiecombo) with a granular per-model permissions
system (
config/permissions.js,Role/Usermodels). - EJS pages for dashboard, list, create, login, hwinfo.
- Custom hooks:
fog-version,watchdog(the seed of the future task runner). - Interactive installer (
tools/setup/index.js) and a non-interactive dev setup (tools/setup/dev.js).
Gap vs. FOG 1.6 (still large). Core entity models now largely exist (see Phase 1); the remaining gaps are behavior, breadth, and views — not schema:
- Multicast, Pending Hosts / Pending MACs (host approval)
- Import/Export for every entity
- A real imaging engine (capture/deploy controllers are stubs)
- The 1.x background daemons (TaskScheduler, Image/Snapin replicators, MulticastManager, PingHosts, ImageSize, SnapinHash, FileDeleter)
- The hundreds of
FOG_*global settings 1.x seeds - Views: per-entity list views exist, but the per-entity create forms
aren't built (
views/pages/partials/create/is empty) and the list pages have no "Create new" entry point. (Thesnapinplugin is the exception — it ships its own create page.)
tools/migrate/ is a Mongo schema-revision framework, not a 1.x-MySQL →
2.0 data importer; that importer does not exist yet.
- Client / FOS compatibility — decided: mirror 1.x fields now, settle the live protocol at Phase 2. Entities are modelled on 1.x's schema (compatible- leaning); the actual capture/deploy/registration protocol is decided when imaging is built.
- Frontend direction — decided: server-rendered EJS + jQuery, on
AdminLTE 4 / Bootstrap 5 (migrated from the AdminLTE 3 / BS4 templates).
jQuery 3.7.1 is kept for DataTables /
fog.common.js/ parasails. Views are built per-entity on top of the API/model layer. Follow-ups: upgrade DataTables integration-bs4→-bs5, re-vendor Chart.js for AdminLTE 4 (dashboard charts), fixsysteminformation@5property renames (hwinfo/dashboard load), and remove the unused Vue 3 / React 19 deps.
- Fix the
watchdoghook crash (async.forevergiven an async iteratee — broke underasync@3). - One-command dev MongoDB (
docker-compose.yml). - Non-interactive dev setup (
npm run setup:dev). - Document supported Node versions + dev quickstart (README).
- Make
npm run lintrunnable again — installedeslint@10only supports flat config, but the repo ships a v4-style.eslintrc. Either migrate toeslint.config.js(and clean up the resulting warnings, since the lint script runs with--max-warnings=0) or pineslintto v8. Deferred — decide the eslint direction first. - Resolved the lockfile split — standardized on npm:
package-lock.jsonis committed; the strayyarn.lock(gitignored, never tracked) is removed and stays ignored. (README,.npmrc, and the scripts already use npm.)
Add the missing core entity models (mirroring 1.x fields). Each registered model
automatically gets full REST CRUD via the generic :model routes once it has a
stock.<identity> entry in config/permissions.js.
-
StorageGroup+StorageNode(with a bidirectional association) — mirrors 1.xnfsGroups/nfsGroupMembers. -
Snapin— extracted to thesnapinplugin (PRs #55/#56); no longer a core model. It contributes its ownsnapinmodel + permissions + list/create pages + the host "Snapins" tab (extends.host, links in the plugin's ownplugin_snapin_hostcollection). (Sidebar still labels snapins "Modules" in places — reconcile later.) -
Printer— extracted to theprinterplugin (PR #57); no longer a core model. Contributes its ownprintermodel + permissions + list/create pages + the host "Printers" tab (extends.host; host links + per-hostdefaultPrinter/level inplugin_printer_host/plugin_printer_hostcfg). Mirrors 1.xprinters. -
PxeMenu— mirrors 1.xpxeMenuOptions(the sidebar's "iPXE Menu"). The separate 1.xipxeproduct/manufacturer/MAC → boot-file mapping table is deferred until the boot/imaging flow needs it. -
Host+Imagescalar field parity with 1.x (AD, kernel, product key, pending, security tokens, etc. on Host; path/type/partition/os/format/ compress/etc. on Image). Existing fog-node fields/associations preserved. Image lookup FKs (imageType/imagePartitionType/os) kept as numeric ids for now. - Host↔Printer / Host↔Snapin assignments + per-host
defaultPrinter— now owned by theprinter/snapinplugins (links in each plugin's ownplugin_*_hostcollections viaextends.host), not core associations.Group↔*associations were removed with the Group entity (ADR 0001: groups → hosttags+ bulk list actions). Remaining core association: StorageGroup↔StorageNode (bidirectional). Follow-up: assigning core collection members through the API needs controller support — the genericupdatedoesn't set collections and the blueprint nested/:model/:id/:assoc/:fkroutes are shadowed by the custom:modelroutes (return 404). Add explicit add/remove endpoints (mirroringrole/assign). -
Taskfield parity (gated partly by the client/FOS decision). - Lookup models to replace numeric FKs: ImageType, PartitionType, OS.
- Seed the
FOG_*settings 1.x expects. - Page controllers/views for the new entities (EJS + jQuery, per the frontend
decision); reconcile the sidebar (
config/globals.js) labels/routes with the model identities (e.g. "Modules" → snapin, plural view routes). - Remove the unused Vue 3 / React 19 dependencies (frontend decision).
Storage-node integration, real capture/deploy (image-lock helpers already exist),
iPXE menu generation, host registration from FOS, progress over sockets via
Task/Workflow.
Port the 1.x daemons as Sails hooks/services (the watchdog hook is the seed):
task scheduler, image/snapin replication, multicast manager, ping hosts, image
size, snapin hash, file deleter.
Snapins/modules, printers, WOL, power management, inventory, reports, import/export, Active Directory, plugins — then auth/settings-UI/i18n polish and a 1.x → 2.0 data migration path.