Full-stack MVC framework — Express backend + Vue 3 frontend, wired together with Vite.
Vulkano is a full-stack framework that gives you a convention-based Express API backend (@vulkano/core) and a Vue 3 frontend — both running from the same project, bundled by Vite.
Inspired by KumbiaPHP.
app/is the backendfrontend/— multi entry point for Vue 3 SPA or vanilla JS
See references/AGENTS/BUILD.md for how multiple entry points work.
Full folder layout: see references/AGENTS/ARCHITECTURE.md. Rules per area: references/AGENTS/BACKEND.md and references/AGENTS/FRONTEND.md. Worked code (routing, controller/model, auth, components, forms, testing, ...) lives as Claude Code skills under .claude/skills/, loaded automatically when a task matches.
| Layer | Technology |
|---|---|
| Runtime | Node.js >=24, pnpm |
| Backend | Express 5, Mongoose, Socket.io, JWT, i18n, @vulkano/core |
| Frontend | Vue 3, Vue Router, JS Vanilla, Vite |
| Styling | SCSS, Foundation Sites |
| Dev tools | Nodemon, Vite Plus |
Make sure you have these installed on your machine:
-
nvm (recommended, manages Node versions) — github.com/nvm-sh/nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash source ~/.bashrc nvm install 24 nvm use 24
-
pnpm — run this once in your terminal:
# macOS / Linux wget -qO- https://get.pnpm.io/install.sh | sh - # Windows iwr https://get.pnpm.io/install.ps1 -useb | iex
-
Vite+ (
vpCLI — installs Vite, Vitest, and the rest of the toolchain globally):# macOS / Linux curl -fsSL https://vite.plus | bash # Windows irm https://vite.plus/ps1 | iex
Then open a new terminal and verify it works:
vp help -
MongoDB (optional — only needed if you use models)
-
Redis (optional — Socket.io adapter or sessions)
.claude/skills/vulkano-skills is a git submodule — plain git clone leaves it empty. vp install's postinstall hook runs git submodule update --init --recursive automatically, so a normal clone + install is enough. If it's still empty (e.g. installed from a tarball with no .git, or .gitmodules missing/broken):
git submodule update --init --recursive
# still empty?
git clone https://github.com/vulkanojs/vulkano-skills.git .claude/skills/vulkano-skillsvp installNew project? Run the interactive cleanup — choose how many frontend entrypoints you want (1 keeps only website, 2 keeps both as shipped) and optionally strip the demo boilerplate (example controller/model, HelloWorld component, demo view):
vp run cleanAsks for confirmation before deleting anything. Skip this if you want to keep both entrypoints and the demo as a reference.
| Command | Description |
|---|---|
vp run dev |
Start Express + Vite dev server with HMR |
vp run clean |
Choose entrypoint count + remove demo boilerplate (new projects) |
vp build |
Build frontend assets into public/ |
vp run start |
Start Express in production mode |
vp lint |
Format/lint/typecheck |
vp test |
Run tests |
vp run dev starts Express and the Vite dev server together, but only one port matters: open http://localhost:$PORT (8000 by default, set in .env). Express serves the page and injects the Vite-bundled frontend automatically — no need to also open localhost:5173 in a second tab, that's Vite's internal dev server, not a second app.
Copy .env.example to .env in the project root and adjust the values. Every variable is documented there.
Be specific about the layer, the data, and the behavior you want.
Instead of: "add a contact form"
Say: "add a contact form with name, email, and message fields, a
ContactController that validates them and saves a Contact model, and a success message on the frontend"
Instead of: "add authentication"
Say: "add JWT login using the existing @vulkano/core auth conventions, with a User model and a login view under frontend/website/views/Login"
Instead of: "show a list of users"
Say: "add a /users route backed by UserController#index that returns paginated User documents, and a frontend/website/views/Users/Index.vue that renders them in a table"
Claude Code picks up the controller/model/view/auth/testing conventions
automatically from .claude/skills/ — no need to paste them into your
prompt. See AGENTS.md for the rules your agent reads
automatically (Claude Code, and any tool that honors
AGENTS.md/CLAUDE.md) — workflow, security boundaries, and handoff
checklist.
- Tell your AI agent: "add a
[table]model with fields[...]" - The agent will create/update
app/models/[table].js
- Tell your AI agent: "add a route to save
[table]to the database" — usuallydomain.com/api/[table] - The agent creates the matching controller under
app/controllers/api/and wires it to the model
Say which one you want, they're not the same:
- Frontend view (Vue SPA, client-rendered): "create a view to show
[table]records" →frontend/website/views/[Table]/Index.vue, fetches data viafrontend/website/Api.js - Backend view (Nunjucks, server-rendered): "create a backend view to show
[table]records" →app/views/[table]/index.html, rendered by the controller viares.vsr/res.render
- Tell your AI agent: "create a route to create a form" (e.g. "add a
/posts/newroute with a form to create aPost") - The agent adds the route in
frontend/website/routes.jsand a view underfrontend/website/views/, wired to the API route that saves the model
| Task | What to tell your agent |
|---|---|
| New component | "add a PostCard component" → frontend/website/components/PostCard/ |
| Run checks | vp check (format/lint/typecheck) and vp test (tests) |
Drop photographic images (.jpg/.jpeg/.png) directly under public/img/, then run:
vp run webpDetails (what the script rewrites, loading="lazy" on <img>): see references/AGENTS/FRONTEND.md § Assets.
The framework supports several deploy options. Pick one per environment (e.g. staging, production) and record only the selected ones in PROJECT.md § Deployment.
The project ships with an ecosystem.config.js for PM2:
pm2 start ecosystem.config.jsBuild and run the production image directly:
docker build -t vulkano-framework .
docker run --env-file .env -p 8000:8000 vulkano-frameworkOr use Docker Compose, which reads .env for you:
docker compose up --buildBy default this only starts the app service — set MONGO_URI in .env to
point at an external MongoDB (Atlas, a managed instance, etc). If you'd
rather run MongoDB locally in a container, start the local-db profile
instead:
docker compose --profile local-db up --buildPoint Coolify at this repo and pick a build pack in the app settings:
- Nixpacks (Coolify's default) — builds from
nixpacks.toml(Node 24,pnpm install --frozen-lockfile,pnpm run build, starts withpnpm run start). - Dockerfile — builds the repo's
Dockerfile. - Docker Compose — builds from
docker-compose.yml, which builds theDockerfile.
.env is gitignored and never reaches the build, so set your environment
variables (PORT, MONGO_URI, SALT_KEY, JWT_SECRET_KEY, COOKIES_SECRET_KEY, etc) in Coolify's
own Environment Variables panel for the app — Coolify injects them into
the running container at deploy time.
MIT © Vulkano Team
