Ga naar hoofdinhoud

App Lifecycle — Creating and Managing Nextcloud Apps

App lifecycle commands live in the app- namespace. OpenSpec workflow commands (opsx-) handle feature implementation; app- commands handle the app itself — bootstrapping, configuration, and health checks.


Flow Diagram

[/app-design] ← optional: architecture, features, wireframes

/app-create ──► /app-explore ──► /app-apply ──► /app-verify
▲ │
└──────────── revisit (if drift found) ───┘

openspec/app-config.json ◄── single source of truth

Commands

/app-design [app-name] (optional pre-step)

Full upfront design for a new app — architecture, features, wireframes, OpenSpec setup.

Run this before /app-create when building a brand new app from scratch. It does deep research and produces:

ArtifactContentsOptional?
docs/ARCHITECTURE.mdStandards research, data model, entity definitions, OpenRegister schema, Vue component decisionsNo
docs/FEATURES.md10+ competitor analysis, feature matrix (MVP/V1/Enterprise), settings & notifications derived from featuresNo
docs/DESIGN-REFERENCES.mdASCII wireframes, UX inspiration, missing feature patternsNo
openspec/config.yamlOpenSpec CLI context — standards, architecture summary, rules for specs/design/tasksNo
img/app-store.svgBlue hexagon app logoYes (asked during Phase 5)
docusaurus/ + .github/workflows/documentation.ymlDocusaurus documentation site, GitHub Pages deploymentYes (asked during Phase 5)

/app-create and /app-explore will automatically read these documents as context when they exist.

When to use: Starting a brand new app and you want comprehensive design research before writing any code. Skip for simple apps or when onboarding an existing repo.

Re-running: Safe to run again — prompts you to overwrite, update, or skip each existing document individually.

openspec/config.yaml — OpenSpec CLI configuration

/app-design generates this file as part of its output. The template uses the shared conduction schema; customise the context and rules blocks for your project:

schema: conduction

context: |
Project: <Project Name>
Repo: ConductionNL/<repo-name>
Type: Nextcloud App (PHP)
Description: <one-line description>
Key components: <list main components>
Database: PostgreSQL (via OpenRegister's ObjectService)
Mount path: /var/www/html/custom_apps/<appname>

Shared specs: See ../openspec/specs/ for cross-project conventions
Project guidelines: See ../project.md for workspace-wide standards

rules:
proposal:
- Reference shared nextcloud-app spec for app structure requirements
- <add project-specific proposal rules>
specs:
- <add project-specific spec rules>
design:
- <add project-specific design rules>
tasks:
- <add project-specific task rules>
  • context: Injected into every artifact Claude generates — include purpose, tech stack, and architecture
  • rules: Per-artifact-type rules that guide Claude when writing specs for this project

If not using /app-design, create this file manually before running openspec validate --all.


/app-create [app-id]

Bootstrap or onboard a Nextcloud app.

Starts the interactive setup process. Collects app identity, goal, dependency choices, and GitHub details — then either clones the template as a starting point or onboards an existing folder by comparing it against the template structure.

Always creates an openspec/ folder with:

  • app-config.json — the canonical config file for all decisions
  • README.md — documents the app's goal and structure

If /app-design was run first, reads docs/ARCHITECTURE.md and docs/FEATURES.md to pre-populate fields. Never overwrites existing design artifacts.

After /app-create you have a fully scaffolded app with all template placeholders replaced and both main + development branches on GitHub.

When to use: Starting a brand new app, or onboarding an existing repo into the lifecycle flow for the first time.

project.md — project description for Claude context

Each app should have a project.md at its root. This file is loaded by Claude as context when working on the project. /app-create scaffolds a stub; complete it with the details below:

# <Project Name>

## Overview
<What this project does and why it exists>

## Repository
- **GitHub**: https://github.com/ConductionNL/<repo-name>
- **Organization**: ConductionNL
- **Container mount**: /var/www/html/custom_apps/<appname>

## Architecture

### Key Components
- **<Component A>**<description>
- **<Component B>**<description>

### Important Patterns
- <Pattern or gotcha worth knowing, e.g. "route ordering matters in routes.php">

### Directory Structure
​```
lib/
Controller/
Service/
Db/
appinfo/
info.xml
routes.php
​```

## Dependencies
- **Depends on**: <list upstream dependencies>
- **Depended on by**: <list downstream dependents>

## API
- Base URL: `/index.php/apps/<appname>/api/`
- Auth: <authentication method>
- Format: JSON

## Testing
- <How to run tests for this project>

List known gotchas, dependencies in both directions, and any project-specific patterns that differ from the workspace-wide standards in apps-extra/project.md.


/app-explore [app-id]

Think through and evolve the app configuration.

Opens an interactive exploration session. Acts as a thinking partner — questions assumptions, maps features, explores architecture, and helps you clarify what the app should do and how it should be built.

Reads openspec/app-config.json, feature specs, ADRs, and — when present — docs/ARCHITECTURE.md, docs/FEATURES.md, and docs/DESIGN-REFERENCES.md from /app-design. Never writes application code.

What you can do in explore mode:

  • Refine the app's goal or summary
  • Map out features and write openspec/specs/{feature-name}/spec.md files
  • Change category, OpenRegister dependency, CI settings
  • Sketch architecture with ASCII diagrams
  • Surface open questions and risks
  • Create app-specific ADRs in openspec/architecture/

When to use: When starting to plan features, when the app's purpose has evolved, or when you need to think through a design decision before building.


/app-apply [app-id]

Apply config changes from openspec/app-config.json to the actual app files.

Reads the config, compares it against all tracked files, shows you a diff of what would change, and applies approved changes. Updates appinfo/info.xml, all CI/CD workflows, composer.json, package.json, Vue files, README, and more.

Always shows the change summary and asks for confirmation before modifying anything.

When to use: After /app-explore has updated openspec/app-config.json and you're ready to push those changes into the codebase. Also use after manually editing app-config.json directly.


/app-verify [app-id]

Audit the app files against openspec/app-config.json.

Read-only. Checks every tracked file and reports findings with severity:

  • CRITICAL — Identity mismatches that break CI or cause runtime errors
  • WARNING — Metadata drift that is incorrect but not breaking
  • INFO — Minor cosmetic differences

Also checks for deprecated components (CnDetailViewLayout) and CHANGELOG version alignment.

When to use: After /app-apply to confirm changes landed correctly. Also useful as a periodic health check to detect drift (e.g. after manual edits to CI files).


The openspec/ Folder

Every app managed by this lifecycle has an openspec/ folder at its root. This folder is the single source of truth for all configuration decisions — it is what /app-apply reads and what /app-verify checks against.

openspec/
├── app-config.json # Core configuration (id, name, goal, dependencies, CI settings)
├── README.md # Documents the app's goal and structure
├── architecture/ # Architectural Decision Records (app-specific ADRs)
│ └── adr-001-*.md
└── specs/ # Feature specifications (created during /app-explore)
└── {feature-name}/
└── spec.md

app-config.json Structure

{
"id": "my-app",
"name": "My App",
"namespace": "MyApp",
"summary": "One-line description (~100 chars)",
"goal": "Full description of what this app does and the problem it solves.",
"category": "organization",
"version": "0.1.0",
"license": "EUPL-1.2",
"author": "Conduction B.V.",
"repository": "https://github.com/ConductionNL/my-app",
"dependencies": {
"requiresOpenRegister": true,
"additionalCiApps": [
{"repo": "ConductionNL/openregister", "app": "openregister", "ref": "main"}
]
},
"cicd": {
"phpVersions": ["8.3", "8.4"],
"nextcloudRefs": ["stable31", "stable32"],
"enableNewman": false
},
"createdAt": "2026-01-01",
"updatedAt": "2026-03-20"
}

Feature Specs

Feature specs live in openspec/specs/{feature-name}/spec.md and are created during /app-explore sessions:

# {Feature Name} Specification

**Status**: idea | planned | in-progress | done

**OpenSpec changes:** _(links to openspec/changes/ when in-progress or done)_

## Purpose

What this feature does and why it matters to users.

## Requirements

### Requirement: {Requirement Name}
The system MUST/SHOULD/MAY {requirement statement}.

#### Scenario: {Scenario Name}
- GIVEN {precondition}
- WHEN {action}
- THEN the system {MUST/SHOULD} {expected outcome}

## User Stories

- As a [role], I want to [action] so that [outcome]

## Acceptance Criteria

- [ ] ...

## Notes

Open questions, constraints, dependencies, related ADRs.

For idea status, a lightweight spec (Purpose + User Stories + Acceptance Criteria) is fine. Fill in formal Requirements/Scenarios when moving to planned — that is what /opsx-ff reads to generate the change artifacts.


Tracked Files

/app-apply and /app-verify track the following files and keep them in sync with app-config.json:

FileWhat is tracked
appinfo/info.xmlApp ID, name, summary, goal, namespace, category, GitHub URLs
lib/AppInfo/Application.phpAPP_ID constant, PHP namespace
composer.jsonPackage name, PSR-4 namespace
package.jsonPackage name
webpack.config.jsApp ID constant
src/App.vueOpenRegister gate (present/absent)
README.mdTitle, goal section
.github/workflows/code-quality.ymlApp name, PHP versions, NC refs, Newman flag, additional apps
.github/workflows/release-beta.ymlApp name
.github/workflows/release-stable.ymlApp name
.github/workflows/issue-triage.ymlApp name
.github/workflows/openspec-sync.ymlApp name

Typical Sessions

Starting a brand new app (full design-first flow)

/app-design my-new-app # Architecture, competitor research, wireframes, OpenSpec setup
/app-create my-new-app # Scaffold from template, create GitHub repo
/app-explore my-new-app # Think through goals and features
# Approve saving changes to openspec/
/app-apply my-new-app # Push config changes to app files
/app-verify my-new-app # Confirm everything landed correctly
openspec validate --all # Verify OpenSpec config is valid
/opsx-onboard # Confirm Claude integration works

Starting a new app (quick flow, no upfront design)

/app-create my-new-app # Scaffold from template, create GitHub repo
/app-explore my-new-app # Think through goals and features
/app-apply my-new-app # Push config changes to app files
/app-verify my-new-app # Confirm everything landed correctly
openspec validate --all # Verify OpenSpec config is valid
/opsx-onboard # Confirm Claude integration works

Onboarding checklist

After completing the steps above, confirm:

  • openspec/ directory initialized with app-config.json
  • openspec/config.yaml present and pointing to conduction schema with project context
  • project.md at app root — describes purpose, architecture, and dependencies
  • openspec validate --all passes
  • /opsx-onboard works in Claude Code

Evolving an existing app

/app-explore my-app # Revisit goals, add feature files
# Update summary, category, or CI settings
/app-apply my-app # Apply the changes
/app-verify my-app # Verify

Legacy app without @spec annotations? If the app predates the spec traceability convention (ADR-003), run the Retrofit Playbook before feature work — /opsx-coverage-scan/opsx-annotate/opsx-reverse-spec.

Periodic health check

/app-verify my-app # Check for drift
# If CRITICAL or WARNING issues:
/app-apply my-app # Fix them

Architectural Decision Records (ADRs)

App-specific ADRs live in openspec/architecture/ and document why the app is built the way it is. They are created and explored during /app-explore sessions.

Company-wide ADRs live in hydra/openspec/architecture/ and apply to all Conduction apps. Only create an app-specific ADR when the decision is unique to that app.

Good candidates for app-specific ADRs:

  • Data storage approach (OpenRegister vs own tables)
  • Frontend architecture choices unique to this app
  • Authentication and authorization model
  • External API dependencies and coupling decisions
  • Standards compliance choices (ZGW, GEMMA, CMMN)

Format: openspec/architecture/adr-{NNN}-{slug}.md with fields for Context, Decision, Consequences, and Alternatives Considered.


Handoff to OpenSpec — The Cut-off Point

The app lifecycle flow handles everything up to and including "we know what to build". OpenSpec takes over when you are ready to write the spec and implement.

The cut-off is driven by feature status:

openspec/specs/ openspec/changes/
─────────────── ─────────────────
idea (not here yet)
planned ─────────────────► /opsx-ff creates the change
in-progress proposal.md → specs.md → tasks.md
done archived

Trigger: When a feature in openspec/specs/ moves from idea to planned — meaning it has a clear goal, user stories, and acceptance criteria — it is ready for /opsx-ff {feature-name}.

One feature → multiple changes

A single feature can result in multiple OpenSpec changes. This is intentional — OpenSpec changes should be independently deployable slices:

openspec/specs/document-upload/spec.md (planned)

├──► openspec/changes/document-upload-backend/ (schema + API)
├──► openspec/changes/document-upload-frontend/ (Vue upload UI)
└──► openspec/changes/document-upload-notify/ (notifications)

The feature spec tracks the overall concept; the OpenSpec changes track implementation.


Preventing Duplication Between openspec/ and openspec/changes/

The two layers have distinct roles — duplication is avoided by keeping each layer at the right level of detail:

openspec/ (app config layer)openspec/changes/ (implementation layer)
QuestionWHAT should this app do?HOW should we build it?
LevelConcept and goalTechnical specification
Feature detailUser stories + acceptance criteriaArchitecture, design, tasks
DecisionsWHY (ADRs in openspec/architecture/)HOW (design.md per change)
OutputInput for OpenSpecOutput for development

Rule of thumb:

  • If you are deciding what the app needs → openspec/specs/{feature}/spec.md
  • If you are deciding how to implement a specific change → openspec/changes/{change}/
  • If a decision is about the overall architecture of the app → openspec/architecture/adr-NNN-*.md
  • If a decision is about the design of a specific feature → openspec/changes/{change}/design.md

The README.md in the app root references the openspec/ folder and links to key documents — it is the entry point, not a duplicate.


Scope of /app-apply

App Apply is deliberately narrow. It only touches scaffold and configuration files:

Syncs: appinfo/info.xml, CI/CD workflow parameters, PHP namespaces, package names, README.md header sections, src/App.vue OpenRegister gate.

Does not touch: Feature code, business logic, Vue components, controllers, OpenRegister schemas.

If a user asks /app-apply to do something outside this scope, it redirects to the right tool:

  • Config decision → /app-explore to capture it, then /app-apply
  • Feature implementation → /opsx-ff {feature-name}

/app-design vs /app-explore vs /app-create — When to Use Which

These three commands can feel overlapping. Here's the clear distinction:

/app-design/app-create/app-explore
WhenBefore the repo existsOnce, at bootstrapRepeatedly throughout app lifetime
DoesResearch + document (architecture, competitors, wireframes)Scaffold files + set up GitHubThink + iterate on config and features
Writes todocs/, openspec/config.yaml, openspec/specs/Template files, openspec/app-config.jsonopenspec/app-config.json, openspec/specs/, openspec/architecture/
RequiresNothing (pre-repo)Git repo, optionally design docsExisting app with openspec/app-config.json
Skip whenOnboarding existing repo / simple appAlready doneNever — use it repeatedly

Overlap note: /app-design creates openspec/config.yaml and initial openspec/specs/. /app-create creates openspec/app-config.json. These are different files with different purposes — the design docs don't replace the machine-readable config file.


Relationship to the OpenSpec Flow

App lifecycle commands (app-) work alongside the OpenSpec workflow commands (opsx-), making the full workflow coherent:

App Lifecycle commandsOpenSpec implementation commands
PurposeBootstrap, configure, and audit the app itselfSpecify, implement, and validate features
Source of truthopenspec/app-config.jsonopenspec/changes/ directories
Writes toApp files (metadata, CI, config)Application code (PHP, Vue, schemas)
Start withA new or existing app repoA specific feature or change to implement
ADR locationopenspec/architecture/ (app-wide decisions)openspec/changes/*/design.md (feature decisions)

Typical combined workflow:

  1. Design (optional): /app-design
  2. Bootstrap and configure: /app-create/app-explore/app-apply
  3. Define features and ADRs: /app-explore (repeated as the app evolves)
  4. Implement features: /opsx-ff {feature-name}/opsx-apply/opsx-verify → test (/test-functional, /test-counsel) → /create-pr/opsx-archive
  5. Keep config in sync: /app-verify periodically, /app-apply when drift is found

For guidance on testing commands and when to use each, see testing.md.