Skip to content

Directory Structure

newmeta is a monorepo — PHP backend, Nuxt frontend, migrations, CLI tools, and docs all live in a single checkout. This page explains what lives where and which folders you develop in.

Top level

newmeta/
├── index.php                 # Entry point — routing via .htaccess
├── .htaccess                 # URL rewriting (/{view}/{item}/{child}/{value}/{add})
├── config.php                # Versioned system config (systemVersion, pw_salt)
├── config.local.php          # DB + update credentials (git-ignored)
├── config.local.example.php  # Template for new installs
├── robots.txt
├── sitemap.xml               # Generated (scheduled task)

├── _core/                    # Framework core (PHP)
├── _public/                  # Plugins / extensions
├── _theme/                   # Nuxt frontend themes
├── _migrations/              # SQL migrations
├── _templates/               # Legacy Smarty templates (transition)
├── _bin/                     # Ad-hoc PHP scripts (imports, cleanup)
├── console/                  # CLI runner for cron tasks
├── include/                  # PHP helpers (DB, auth, URL)
├── websocket/                # Node.js WebSocket server (Express + Socket.io)
├── media/                    # User uploads (images, PDFs, videos)
├── docs/                     # This VitePress documentation

├── tmp/                      # Runtime folder (see "Runtime folders" below)
├── templates_c/
├── var/
├── z_uploads/
└── z_legacy_migration.php

Underscore prefix

Folders with an _ prefix are internal buckets (framework, plugins, themes, migrations). Everything without a prefix is either an entry point or a runtime folder.

_core/ — Framework core

_core/
├── libs/                     # Vendored PHP libs (no Composer)
└── system/
    ├── admin/controller/     # Admin controllers (language, modal, install)
    ├── api/                  # apiBaseController, apiBaseModel, PageService, RateLimiter
    ├── auth/                 # Session handling, 2FA, Fail2Ban
    ├── base/                 # Shared base classes (e.g. Encryption)
    ├── cron/                 # TaskRunner, QueueWorker
    ├── migration/            # MigrationRunner
    └── webhook/              # WebhookDispatcher, WebhookDeliveryWorker

The core provides the building blocks — plugins extend it, but never modify it directly.

  • API routing: _core/system/api/apiBaseController.php is the entry point for /api/*
  • Plugin registration: every plugin extends install_controller from _core/system/admin/controller/
  • Sessions: IP-bound, mirrored in the DB (recovery after GC)

See Plugins › Plugin Anatomy for how plugins interact with core classes.

_public/ — Plugin directory

_public/
├── extensions/
│   └── core/
│       └── backend/          # Backend plugins (42 in total)
│           ├── demoAPI/      # Main API hub (auth, pages, settings, user, webhook, ...)
│           ├── pagebuilder/  # Visual page builder
│           ├── shop/         # Shop + widgets + checkout (its own api/)
│           ├── elearning/    # CME training (its own api/)
│           ├── menueditor/   # Visual menu editor (its own api/)
│           ├── ai/           # Multi-provider AI plugin (its own api/)
│           ├── abtesting/
│           ├── shopware6/    # Headless SW6 integration (its own api/)
│           ├── elasticsearch/
│           ├── emailmarketing/
│           ├── redirects/
│           ├── updatemanager/
│           ├── taskmanager/
│           └── ... (30 more)
└── src/                      # Shared assets (CSS/LESS incl. css/frontend/menu.less, fonts, images, JS)

Every plugin is self-contained:

{plugin-name}/
├── bootstrap.php             # Registration (content, buttons, API, webhooks)
├── layout/                   # Vue admin components (index.vue, index_detail.vue)
├── script/                   # PHP action scripts
├── api/                      # (optional) plugin-local API models
├── widgets/                  # (optional) Pagebuilder widgets
└── migrations/               # (optional) plugin-local SQL migrations

See Plugins › Plugin Anatomy for details.

API routing: demoAPI + plugin-local APIs

A main hub bundles many endpoints, but plugins with a large API ship their own api/ directory and register their models in their own bootstrap.php.

demoAPI (main hub):

demoAPI/
└── api/
    ├── auth/model.php                # class auth
    ├── pages/model.php               # class pages
    ├── settings/model.php            # class settings
    ├── menu/model.php                # class menu
    ├── user/orders/model.php         # class user_orders
    ├── shop/cart/model.php           # class shop_cart
    ├── checkout/model.php            # class checkout
    ├── webhook/...
    └── backend/
        ├── auth/model.php            # class backend_auth
        ├── page/model.php            # class backend_page
        └── pagebuilder/model.php     # class backend_pagebuilder

Plugins with their own API (11 total, in addition to the hub):

elearning/api/elearning/my-courses/model.php   # class elearning_my_courses
shop/api/shop/...
menueditor/api/...
ai/api/backend/ai/model.php                    # class backend_ai
shopware6/api/...
elasticsearch/api/...
emailmarketing/api/...
abtesting/api/...
design/api/...
taskmanager/api/...
updatemanager/api/...

Class naming

Path segments (including dashes) become underscores — user/ordersclass user_orders, elearning/my-coursesclass elearning_my_courses. See Plugins › API Endpoints.

_theme/ — Nuxt frontend

_theme/
├── vue-base/                 # Default theme (Nuxt 4)
├── base/                     # Shared component building blocks
├── projekt01/                # Project-specific overrides (example)
├── custom/                   # Customer tweaks
└── backend/                  # Backend-specific asset bundle

The active theme is selected via NUXT_PUBLIC_THEME (in .env) — see Themes › Nuxt aliases.

vue-base/

_theme/vue-base/
├── app/
│   ├── app.vue
│   ├── components/
│   │   ├── admin/            # NsModal, NsForm, NsTable, NsSelect, MediaManager, ...
│   │   └── pagebuilder/      # PagebuilderWidget/Row/Column (frontend rendering)
│   ├── composables/          # useSeoHead, useSchemaOrg, useUserCenter, ...
│   ├── layouts/              # admin.vue, admin-login.vue, default.vue
│   ├── middleware/
│   ├── pages/                # File-based routing (admin/[...slug].vue, [...slug].vue)
│   ├── plugins/              # admin-css, cookieconsent, ab-tracking, gsap-animations
│   ├── stores/               # Pinia (admin.ts, layout.ts, sw6Store.ts, ...)
│   ├── utils/
│   └── widgets/
├── public/
│   ├── backend/
│   │   ├── css/style.less           # Admin light theme
│   │   └── css/style-darkmode.less  # Admin dark theme
│   ├── css/
│   └── fonts/
├── server/
├── nuxt.config.ts
└── package.json

Important:

  • Single admin route: app/pages/admin/[...slug].vue — no index.vue. All plugin layouts load dynamically via import.meta.glob
  • Component convention: admin components carry the Ns prefix (NsModal, NsForm, …)

_migrations/ — Database schema

_migrations/
├── core/                     # 001_baseline.sql, 002_add_sessions.sql, ...
├── plugins/                  # Plugin migrations shipped with the core
│   ├── shop/
│   ├── ai/
│   └── ...
└── changelogs/               # Version changelogs (Markdown, one per release)

Plugin-local migrations can also live under _public/extensions/core/backend/{plugin}/migrations/ — the MigrationRunner scans both sources. See Plugins › Migrations for details.

include/ — PHP helpers

A legacy function library that pre-dates the OOP refactor. Still used heavily in production:

include/
├── connect.php               # DB connection
├── mysql.php                 # query, fetch_assoc, fetch_all, num_rows,
│                             # insert_id, real_escape_string
├── rights.php                # ACL checks
├── translation_engine.php    # Multi-language helpers
├── get_url.php               # URL builder
└── ...

Use insert_id, not last_insert_id

The project uses the insert_id() function from include/mysql.phpnever last_insert_id() (it doesn't exist).

console/ — CLI runner

console/
└── bin                       # Dispatcher — see --help for subcommands

Key commands:

bash
php console/bin scheduled-tasks --time-limit=540
php console/bin process-queue   --time-limit=55
php console/bin process-webhooks --time-limit=25
php console/bin list-tasks

Recommended cron setup:

cron
*/10 * * * *  php /path/console/bin scheduled-tasks --time-limit=540
*   *   * * * php /path/console/bin process-queue   --time-limit=55
*   *   * * * php /path/console/bin process-webhooks --time-limit=25
*   *   * * * sleep 30 && php /path/console/bin process-webhooks --time-limit=25   # second run after 30s (half-minute cadence)

docs/ — This documentation

docs/
├── .vitepress/
│   ├── config.ts             # Site meta, nav, sidebar
│   └── theme/
│       ├── index.ts
│       └── custom.css        # Brand colors (Electric Indigo #4F46E5)
├── api-reference/            # Scalar embed
├── getting-started/
├── plugins/
├── widgets/
├── themes/
├── public/
│   └── openapi.json          # Generated OpenAPI spec
├── scripts/
│   └── build-openapi.sh      # Wrapper for swagger-php
├── index.md                  # Home page
├── package.json
└── README.md

Build:

bash
cd docs
npm install
npm run dev              # http://localhost:5173
npm run build            # Output: docs/.vitepress/dist/
npm run build:openapi    # Regenerate docs/public/openapi.json

Runtime folders (not versioned)

FolderContents
media/User uploads (images, PDFs, videos)
tmp/Temporary files (e.g. deployment dumps)
templates_c/Smarty compiled templates
var/Runtime state (AI jobs, queues, locks)
z_uploads/Legacy upload folder

These directories must be writable on the server, but are not part of the Git checkout.

See also