Ga naar hoofdinhoud
AcademytutorialBouw een Nextcloud-app op de Conduction-stack, Deel 1: Scaffold

Bouw een Nextcloud-app op de Conduction-stack, Deel 1: Scaffold

Kloon de Conduction-app-template, hernoem hem naar DeskDesk, bouw, activeer en zie het canonieke app-chassis. Het eerste van zes delen die een werkende bureau-reserveringsapp bouwen op de volledige Conduction-stack.

TutorialApp developmentNextcloudOpenRegisternextcloud-vueTutorial series
8 min read

Dit is Deel 1 van een zesdelige tutorial waarin we DeskDesk bouwen, een flexibele bureau-reserveringsapp voor een open-kantoor-omgeving, op de volledige Conduction Nextcloud-stack. Het eindproduct: kies een bureau op een verdieping, boek een slot, zie je boeking in je Nextcloud Calendar, en haal zone-specifieke kennisartikelen uit xWiki op naast de boeking. Elk onderdeel hergebruikt wat @conduction/nextcloud-vue en OpenRegister je al gratis geven.

In Deel 1 zet je de app op, hernoem je hem, bouw je hem, en zie je het canonieke app-chassis op je scherm. Geen data, nog geen integraties. We krijgen eerst het skelet goed.

Wat we bouwen, over alle zes delen heen

DeelTitelVoegt toe
1Scaffold (je bent hier)Lege app-schil, chassis zichtbaar, navigeerbaar
2Schema's + manifestDesk- en booking-schema's, volledige CRUD, dashboard
3Schema-gedreven integratiesBoekingen verschijnen in NC Calendar via de OpenRegister calendar provider
4Externe kennis + shipxWiki-bron via OpenConnector, sidebar-tab, packagen, publiceren
5Geavanceerde manifest-featuresactionToggles, fieldWidgets, public-mode pagina's, de overige page types
6IntegrerenCross-register-reads, OpenConnector source/sync, tweerichtings-webhook terug naar OR

Dezelfde vorm, twee repos:

Stap 1: Gebruik de template

ConductionNL/nextcloud-app-template is een GitHub repository template. De knop "Use this template" geeft je een verse repo met de volledige starter kit: Vue 2 + Pinia-frontend, PHP-backend, OpenRegister-bedrading, kwaliteitspijplijn, OpenSpec-scaffolding, GitHub Actions.

gh repo create ConductionNL/deskdesk \
  --template ConductionNL/nextcloud-app-template \
  --public \
  --description "Flexible desk booking for open-office environments"

Kloon hem daarna naast je andere Nextcloud-apps. De meeste workspaces houden ze in één apps-extra/-map die de dev-container mount.

cd /path/to/your/nextcloud/workspace/apps-extra
git clone https://github.com/ConductionNL/deskdesk.git
cd deskdesk

Je hebt nu een directory met de volledige template-inhoud onder de nieuwe naam. Binnenin is nog niets hernoemd. De map heet deskdesk/, maar elk bestand zegt nog app-template, AppTemplate, OCA\AppTemplate. Stap 2 lost dat op.

Stap 2: Hernoem de app

Nextcloud vereist dat drie identifiers overeenkomen:

  • De directorynaam (deskdesk/) ✅ klaar
  • De <id> in appinfo/info.xml
  • De PHP-namespace (OCA\AppTemplateOCA\DeskDesk)

Plus een handvol ondersteunende bestanden die naar het oude id verwijzen. De volledige lijst is klein genoeg om met de hand te doen, en met de hand doen is hier de juiste keuze. Project-geheugen: gebruik nooit sed of scripted edits op code-bestanden, gebruik een echte editor met project-aware refactoring, of lees elk bestand één keer voor je het wijzigt.

2a. De boot-kritische bestanden

Dit zijn degene die voorkomen dat Nextcloud de app überhaupt opstart. Bewerk elk met Find & replace all in je editor: AppTemplateDeskDesk en app-templatedeskdesk:

BestandVervangen
appinfo/info.xml<id>, <name>, <namespace>, <navigation>, <settings> paden
composer.jsonname, description, het psr-4 autoload-prefix
package.jsonname
webpack.config.jsde appId-constante
templates/index.php en templates/settings/admin.phpOCA\AppTemplateOCA\DeskDesk, het data-* element-id
lib/AppInfo/Application.phpnamespace, APP_ID-constante, docblock
Elk ander PHP-bestand in lib/namespace OCA\AppTemplate\…namespace OCA\DeskDesk\…, elke use OCA\AppTemplate\… import, elke docblock
appinfo/routes.phpalleen docblock
Elk Vue-bestand in src/de t('app-template', '…') vertaalnamespace wordt t('deskdesk', '…')
src/router/index.jsgenerateUrl('/apps/app-template')generateUrl('/apps/deskdesk')
src/store/store.js, src/store/modules/settings.js'/apps/app-template/api/settings''/apps/deskdesk/api/settings', fallback register-slug
src/settings.jsloadTranslations('app-template', …) en de #app-template-settings mount-selector
lib/Settings/app_template_register.jsonhernoem naar lib/Settings/deskdesk_register.json (en het app-veld erin)

2b. De "kan later"-bestanden

Tests (tests/Unit/AppTemplateTest.php, de integratie-Postman-collectie), phpcs.xml / phpmd.xml / REUSE.toml headers, en de .github/ workflow-inputs. Die verwijzen alleen in metadata naar het template-id; de app start prima zonder dat je ze aanraakt. Fix ze als je CI opzet.

2c. Eén Nextcloud-versie compatibiliteitsfix

De lib/AppInfo/Application.php van de template registreert een repair step at runtime:

$context->registerRepairStep(InitializeSettings::class);

registerRepairStep() ontbreekt op IRegistrationContext in een paar Nextcloud-builds (je ziet Call to undefined method in nextcloud.log). Verplaats het naar appinfo/info.xml in plaats daarvan, zelfde effect, beter draagbaar:

<repair-steps>
    <install>
        <step>OCA\DeskDesk\Repair\InitializeSettings</step>
    </install>
    <post-migration>
        <step>OCA\DeskDesk\Repair\InitializeSettings</step>
    </post-migration>
</repair-steps>

Haal daarna de registerRepairStep()-regel en de use OCA\DeskDesk\Repair\InitializeSettings; import weg uit lib/AppInfo/Application.php.

Stap 3: Bouwen en activeren

De template levert zijn build-output ongecommit. Het eerste in een verse kloon is dus dependencies installeren en de JS-bundels bouwen, anders is de app-UI gewoon een lege <div id="content">.

composer install --no-dev
composer dump-autoload
npm install --legacy-peer-deps
npm run build

Zorg daarna dat je Nextcloud-container de directory kan zien. In een typische Docker-setup is de apps-extra/ host-directory gemount op /var/www/html/custom_apps/ in de container. Gebruikt je compose-file één bind-mount per app, voeg dan een regel toe voor deskdesk en restart. Anders:

docker cp ./deskdesk nextcloud:/var/www/html/custom_apps/
docker exec -u root nextcloud chown -R www-data:www-data /var/www/html/custom_apps/deskdesk

Nu activeren:

docker exec nextcloud php occ app:enable deskdesk

Je zou moeten zien:

deskdesk 0.1.0 enabled

Open http://localhost:8080/apps/deskdesk/ en log in. Je ziet een placeholder-dashboard met voorbeeld-KPI-kaarten, twee lege panelen, drie nav-items (Dashboard / Items / Documentation) en een Settings-entry vastgezet onderaan de rail. Dat is het chassis.

Het chassis: de hele bedoeling van Deel 1

Elke Conduction-app, DeskDesk, OpenRegister, OpenCatalogi, Procest, MyDash, de dozijn anderen, ziet er op het eerste gezicht hetzelfde uit. Dezelfde vijf structurele stukken, dezelfde plek, hetzelfde gedrag. Die herkenbaarheid is wat @conduction/nextcloud-vue afdwingt: een gebruiker die één app leerde, navigeert de volgende zonder docs.

Het chassis is één vorm, vijf atomen. Elke kaart hieronder focust op één atoom: de gefocuste zone staat op volledige dekking met een KNVB-oranje rand, de rest vervaagt naar 25% zodat je ziet waar het atoom zit.

.topbar

Topbar

App · Desk · always

The Nextcloud chrome row. Sits across every page unconditionally because every Conduction app lives inside Nextcloud's workspace. The shelf icons are the cross-app navigation; per-app links never go here.

.nav

Left navigation

App · required · Desk: never

The per-app sidebar. Carries this app's own primary navigation, plus a footer pinned to the bottom for global access (Settings, Feedback). The active item is the only place cobalt-100 backgrounds a row.

.col

Main column

App · Desk · always

The work surface. In an App pattern, the column opens with a .pageHeader (title + actions), then KPI strip and panels. In a Desk pattern, .col nests inside .grid to become a full-bleed widget canvas with no page header.

.pageHeader

Page header

Index · Detail · Desk: never

The first row of .col on every Index and Detail template. Carries the page title (left) and exactly two action buttons (right): one ghost (secondary), one primary (filled cobalt). The header tracks .col's width: full-spread when the sidebar is closed, constrained when it is open.

.detail

Sidebar

App · optional · Desk: never

The right-hand sidebar. Optional, dismissible, anchored to the active record or the active view. Carries an icon + title + description in a header, then a tabbed body (Search / Columns by default). Class stays .detail for code; we call it the Sidebar in copy.

In Deel 2 leer je hoe manifest.json plus een JSON-schema deze atomen vult met echte data. De placeholder Items-nav-entry, het lege dashboard, en het "article"-schema dat je op het scherm zag, worden allemaal bureaus, boekingen, en een echt bezettings-dashboard, zonder dat je één atoom met de hand uitlegt.

Troubleshooting

Wat volgt

Volgende stappen