A website where editing a content Means Editing a Document — no developer, no deployment, no code.
Most small business websites have the same annoying flaw: the moment someone wants to fix a typo, update a price, or publish a blog post, they need a developer. The text is baked into the code. Every small change becomes a support ticket.
Ecom Edge removes that dependency. An admin logs into a private dashboard, opens any page of the live website in a rich text editor — the same kind of editor used in Word or Google Docs — edits the wording, swaps a photo, adjusts a section, hits save, and the public site updates immediately. No code, no rebuild, no waiting on a developer.
The reason this works: every page's HTML lives in the database, not in the codebase. The public website simply asks the database "what does this page look like right now?" on every single request.
Ecom Edge is three independent applications that work together as one product:
| App | Role | Built with |
|---|---|---|
/website |
The public site visitors actually browse | Next.js, React |
/admin |
The private dashboard where admins manage everything | React, Vite, TinyMCE |
/server |
The API that both talk to — the only thing allowed to touch the database | Express.js, MongoDB (Mongoose), Cloudinary |
Each one is deployed and configured independently, but they're designed to work as a single seamless product.
- An admin opens a page (say, "About Us") in the dashboard. Its full HTML — layout, styling, images, text — loads live from MongoDB into a TinyMCE rich text editor.
- The admin edits it visually — no raw code touched.
- On save, the updated HTML is written back to the MongoDB document tied to that page's URL slug (e.g.
/about-us). - On the public site, a single catch-all route —
website/app/[...slug]/page.js— handles every URL on the site. Whatever path a visitor requests, it asks the API for whatever page is stored under that slug and renders the HTML directly. - That route intentionally disables caching (
force-dynamic,revalidate: 0), so the page is fetched fresh on every request — an edit in the admin panel is live within seconds, with zero rebuild or redeploy.
This trades a bit of raw performance for total editorial freedom — a deliberate call, since the whole point of the product is that a non-technical person can change content instantly, at any time.
There's no separate blog engine. When an admin creates a blog post, the server does two things in one step: it saves the blog's metadata (title, author, category, cover image, SEO) in a blogs collection, and it auto-generates a matching pages document with a pre-built HTML template at /blogs/{slug}. That generated page is then finished off in the same rich text editor used for every other page. If a blog's title or slug changes later, the server keeps both records in sync automatically.
Uploads go through a dedicated media module: files are streamed to Cloudinary (which handles resizing and fast global delivery), and a lightweight record — name, size, type, URL — is kept in MongoDB so the library can be searched, filtered by type, and paginated. The rich text editor is custom-extended so "Insert Image" opens this library in a modal instead of a generic file picker, and admins can right-click any placed image to replace it in-place from the library.
Every page and blog post carries a full SEO block — meta title/description, keywords, Open Graph tags, Twitter card data, canonical URLs, robots directives. The Next.js site reads this live from the database on every request and generates the right <meta> tags automatically, so an admin can improve a page's search ranking or social preview the same way they edit its text.
- Admin login issues a JWT stored in an
httpOnlycookie, so it can't be read by malicious JavaScript. - Every protected route is guarded by middleware that verifies the token and checks for an admin role.
- Passwords are hashed with bcrypt.
- CORS is locked to an explicit allow-list read from environment variables.
- On first run, if no admin account exists, the server automatically provisions one — a fresh deployment is never left inaccessible.
The appointment/consultation booking page draws a deliberate line: the booking form, hero section, and consultant profile card are hard-coded in React because they involve interactive logic a rich-text field can't safely express. The policies section underneath (terms, privacy, refund policy) is still pulled from the database and editable like everything else. Not everything gets forced into "editable via CMS" just because the pattern exists elsewhere in the app.
Because admins can change any page at any moment, directly patching the database from a local copy or from memory risks silently erasing their latest edit. This project treats that as a hard rule: any direct database change first fetches the current live document, applies only the intended surgical edit, and writes that back — never reconstructing content from scratch. The repo backs this up with real evidence: a server/restore/ folder of recovery scripts, JSON database backups in Database Backup/, and narrowly-scoped one-off patch scripts rather than full-document rewrites.
- Node.js (v18+ recommended)
- A MongoDB database (e.g. MongoDB Atlas)
- A Cloudinary account (for media storage)
- A TinyMCE API key (free tier available)
git clone https://github.com/ahmadnadeemx/Ecom-Edge.git
cd Ecom-EdgeEach app has its own dependencies, installed separately:
cd server && npm install
cd ../admin && npm install
cd ../website && npm installEach app needs its own .env file.
server/.env
PORT=5000
NODE_ENV=development
MONGODB_URI=
CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
JWT_SECRET=
JWT_EXPIRES_IN=7d
ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000
admin/.env
VITE_API_BASE_URL=http://localhost:5000
VITE_TINYMCE_API_KEY=
VITE_NODE_ENV=development
website/.env
NEXT_PUBLIC_API_URL=http://localhost:5000/api
From the project root, a single command starts the server, admin, and website together (via concurrently):
npm install # installs the root-level dev dependency (concurrently)
npm run devOr run each app individually, in its own terminal:
# Terminal 1 — API server (http://localhost:5000)
cd server && npm run dev
# Terminal 2 — Admin dashboard (http://localhost:5173)
cd admin && npm run dev
# Terminal 3 — Public website (http://localhost:3000)
cd website && npm run devOn its first run, the server automatically creates an initial admin account if none exists yet, so you can log straight into the dashboard on a fresh database.
cd admin && npm run lint
cd website && npm run lintcd admin && npm run build
cd website && npm run build && npm start
cd server && npm startAll three apps deploy independently to Vercel, each with its own vercel.json — the server runs there via @vercel/node with a catch-all route into server.js. The database and media storage are both external managed services (MongoDB Atlas and Cloudinary), so none of the three apps need to manage persistent storage themselves.
Server: Express.js · Mongoose/MongoDB · JWT + bcrypt · Cloudinary · Multer · Nodemailer Admin: React 19 · Vite · Tailwind CSS · TinyMCE · Framer Motion · Recharts · dnd-kit Website: Next.js · React 19