Use when building a complete Nextcloud app, connecting PHP backend to Vue.js frontend, or implementing CRUD operations. Prevents skipping the service layer, tight coupling between controllers and database, and missing initial state bridge. Covers full-stack Nextcloud app development workflow including creating controllers with routes, implementing service layer with DI, database entities and mappers, Vue.js frontend with @nextcloud packages, initial state bridge between PHP and JavaScript, and the development lifecycle. Keywords: full-stack, CRUD, service layer, initial state, routes.php, Vue.js, controller, mapper, build full app, connect frontend to backend, CRUD operations, full-stack tutorial..
Instrucciones de origen · Vista previa de solo lectura
name
nextcloud-impl-app-development
description
Use when building a complete Nextcloud app, connecting PHP backend to Vue.js frontend, or implementing CRUD operations. Prevents skipping the service layer, tight coupling between controllers and database, and missing initial state bridge. Covers full-stack Nextcloud app development workflow including creating controllers with routes, implementing service layer with DI, database entities and mappers, Vue.js frontend with @nextcloud packages, initial state bridge between PHP and JavaScript, and the development lifecycle. Keywords: full-stack, CRUD, service layer, initial state, routes.php, Vue.js, controller, mapper, build full app, connect frontend to backend, CRUD operations, full-stack tutorial..
license
MIT
compatibility
Designed for Claude Code. Requires Nextcloud 28+.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
nextcloud-impl-app-development
Quick Reference
Full-Stack App Layer Map
Layer
PHP (Backend)
Vue.js (Frontend)
Entry point
lib/AppInfo/Application.php
src/main.js
Routing
appinfo/routes.php
@nextcloud/router
Controllers
lib/Controller/*.php
N/A
Services
lib/Service/*.php
src/services/*.js
Data access
lib/Db/Entity.php + Mapper.php
@nextcloud/axios
State bridge
IInitialState::provideInitialState()
loadState()
UI components
N/A
@nextcloud/vue
Notifications
N/A
@nextcloud/dialogs
Development Commands
Command
Purpose
npm run dev
Build frontend for development
npm run build
Build frontend for production
npm run watch
Rebuild on file changes
npm run serve
Dev server with HMR
php occ app:enable myapp
Enable the app
php occ app:disable myapp
Disable the app
php occ migrations:migrate myapp
Run database migrations
Critical Warnings
ALWAYS set <namespace> in appinfo/info.xml -- auto-wiring and autoloading depend on it.
ALWAYS use @nextcloud/axios for HTTP requests -- it handles CSRF tokens and authentication automatically.
ALWAYS use provideInitialState() in PHP and loadState() in JS for server-to-client data -- NEVER inject data via inline scripts or global variables.
ALWAYS use CSS custom properties (--color-*) for colors -- NEVER hardcode colors (breaks dark mode and theming).
ALWAYS use direct component imports (@nextcloud/vue/components/NcButton) -- barrel imports increase bundle size.
NEVER use \OCP\Server::get() for service resolution -- use constructor injection for testability.
NEVER use OCP\ILogger -- deprecated since NC 24. Use Psr\Log\LoggerInterface.
NEVER use raw fetch() or plain axios -- use @nextcloud/axios which handles auth headers automatically.
NEVER call loadState() without a fallback for optional data -- it throws on missing keys.
NEVER modify existing migration files -- create new migrations for schema changes.
Decision Tree: Route Type Selection
Is this endpoint consumed by external clients or other apps?
├── YES: Will responses need the OCS JSON/XML envelope?
│ ├── YES → Use OCS route + OCSController
│ │ Route: 'ocs' => [['name' => 'api#method', 'url' => '/api/v1/...']]
│ └── NO → Use regular route + ApiController (adds CORS)
│ Route: 'routes' => [['name' => 'api#method', 'url' => '/api/...']]
└── NO: Internal app use only
├── Page rendering? → Use Controller + TemplateResponse
│ Route: 'routes' => [['name' => 'page#index', 'url' => '/']]
├── CRUD resource? → Use resource routes
│ Route: 'resources' => ['item' => ['url' => '/items']]
└── AJAX from Vue frontend? → Use regular route + JSONResponse
Route: 'routes' => [['name' => 'item#create', 'url' => '/items']]
// package.json (relevant sections){"scripts":{"build":"webpack --node-env production --progress","dev":"webpack --node-env development --progress","watch":"webpack --node-env development --progress --watch","serve":"webpack --node-env development serve --progress"},"dependencies":{"@nextcloud/axios":"^2.0.0","@nextcloud/dialogs":"^5.0.0","@nextcloud/initial-state":"^2.0.0","@nextcloud/router":"^3.0.0","@nextcloud/vue":"^8.0.0","vue":"^2.7.0"},"devDependencies":{"@nextcloud/webpack-vue-config":"^6.0.0"}}