diff --git a/docs-issue-businessprocessselection-refactor.md b/docs-issue-businessprocessselection-refactor.md
new file mode 100644
index 0000000000..5ed58c1f5f
--- /dev/null
+++ b/docs-issue-businessprocessselection-refactor.md
@@ -0,0 +1,305 @@
+# Issue: Update BusinessProcessSelection Component to Follow Standard Page Framework Pattern
+
+## Overview
+
+The BusinessProcessSelection component currently uses a custom `useDAKUrlParams` hook instead of the standard page framework pattern. This issue tracks the work to migrate it to use the standard `usePage()` hook and follow the wrapper + content component pattern for consistency and maintainability.
+
+## Current State
+
+### Implementation
+The component currently:
+- Uses custom `useDAKUrlParams` hook for accessing page context
+- Does not follow the wrapper + content pattern
+- Calls hooks before PageLayout wrapping
+- Works correctly but differs from the standard pattern used by other DAK components
+
+### Code Location
+- **File**: `src/components/BusinessProcessSelection.js`
+- **Pattern**: Custom hook usage with direct PageLayout wrapping
+
+### Current Code Structure
+```javascript
+const BusinessProcessSelection = () => {
+ const { profile, repository, selectedBranch } = useDAKUrlParams();
+ // Component logic...
+
+ return (
+
+ {/* Content */}
+
+ );
+};
+```
+
+## Problem Statement
+
+### Issues with Current Implementation
+
+1. **Pattern Inconsistency**: Does not follow the standard wrapper + content pattern used by other DAK components (DAKDashboard, ActorEditor, CoreDataDictionaryViewer, etc.)
+
+2. **Framework Integration**: Uses custom `useDAKUrlParams` hook instead of the page framework's standard `usePage()` hook
+
+3. **Maintainability Risk**: Custom patterns make the codebase harder to maintain and understand for new developers
+
+4. **Future Compatibility**: May be affected by future changes to the page framework if it doesn't follow standard patterns
+
+5. **Documentation Compliance**: Does not comply with REQ-ARCH-001, REQ-ARCH-002, REQ-ARCH-003 requirements established for component architecture
+
+### Context
+
+This issue was identified during an audit of all DAK components following the fix for ActorEditor page load failure (Issue #1076). The audit revealed that all other DAK components follow the standard pattern except BusinessProcessSelection.
+
+## Requirements
+
+### Functional Requirements
+
+**REQ-BPS-001**: Component MUST follow the wrapper + content pattern
+- Split BusinessProcessSelection into wrapper and content components
+- Wrapper component only wraps PageLayout
+- Content component contains all logic and state
+
+**REQ-BPS-002**: Component MUST use standard page framework hooks
+- Replace `useDAKUrlParams` with `usePage()` hook
+- Access page context through standard framework interface
+- Remove dependency on custom hook
+
+**REQ-BPS-003**: Component MUST maintain existing functionality
+- All current features must continue to work as before
+- No regression in user experience
+- No breaking changes to external interfaces
+
+**REQ-BPS-004**: Component MUST handle loading and error states
+- Properly handle loading state from page context
+- Display appropriate error messages when context is unavailable
+- Gracefully degrade when required data is missing
+
+### Non-Functional Requirements
+
+**REQ-BPS-NF-001**: Code quality and consistency
+- Follow the same pattern as DAKDashboard reference implementation
+- Maintain or improve code readability
+- Add appropriate comments where needed
+
+**REQ-BPS-NF-002**: Documentation compliance
+- Update component to comply with REQ-ARCH-001, REQ-ARCH-002, REQ-ARCH-003
+- Ensure component matches patterns documented in page-framework.md
+- Update component-architecture-audit.md to reflect changes
+
+**REQ-BPS-NF-003**: Testing requirements
+- Verify component loads correctly via URL navigation
+- Test loading and error states
+- Verify BPMN file listing and preview functionality
+- Test branch switching if applicable
+
+## Proposed Solution
+
+### Target Architecture
+
+```javascript
+// Wrapper component - exports this
+const BusinessProcessSelection = () => {
+ return (
+
+
+
+ );
+};
+
+// Content component - contains all logic and hooks
+const BusinessProcessSelectionContent = () => {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const { profile, repository, branch, loading, error } = usePage();
+
+ // Handle loading state
+ if (loading) {
+ return (
+
+
Loading...
+
Initializing business process selection...
+
+ );
+ }
+
+ // Handle error state
+ if (error) {
+ return (
+
+ {/* Direct content instead of separate component */}
+
+
+ );
+};
+// Missing: MyComponentContent that uses hooks
+```
+
+### Testing Your Component
+
+Verify your component works correctly:
+
+1. **URL Pattern Test**: Navigate to `/{component}/{user}/{repo}/{branch}`
+2. **Console Check**: No "PageContext is null" errors
+3. **Loading States**: Component handles loading gracefully
+4. **Error States**: Component handles missing context
+5. **Branch Switching**: Component updates when branch changes
+
## Migration Guide
To migrate existing pages to the enhanced framework:
@@ -732,6 +1043,7 @@ To migrate existing pages to the enhanced framework:
2. **Replace authentication checks**: Use access services instead of direct GitHub checks
3. **Update save operations**: Use data access layer for consistent behavior
4. **Add user type handling**: Ensure pages work for all user types
-5. **Test thoroughly**: Verify functionality across user types and permission levels
+5. **Apply wrapper + content pattern**: Split components that use PageLayout and page hooks
+6. **Test thoroughly**: Verify functionality across user types and permission levels
The framework is designed to minimize changes to existing page logic while providing comprehensive user access management and consistent behavior across the application.
\ No newline at end of file
diff --git a/public/docs/requirements.md b/public/docs/requirements.md
index 798b0075cf..9e52127e1e 100644
--- a/public/docs/requirements.md
+++ b/public/docs/requirements.md
@@ -368,6 +368,49 @@ For detailed information about each DAK component, see [DAK Components Documenta
- CDN compatibility (Netlify, Vercel)
- Specific GitHub Pages integration for smart-base repo
+### 3.7 Component Architecture
+
+**REQ-ARCH-001**: The system SHALL enforce consistent component architecture patterns for PageLayout components
+- All DAK components using `PageLayout` MUST follow the wrapper + content pattern
+- Wrapper component MUST only wrap `PageLayout` with no hooks
+- Content component MUST use page hooks (`usePage()` or `useDAKParams()`) to access context
+- This pattern ensures `PageProvider` context exists before hooks attempt to access it
+
+**REQ-ARCH-002**: The system SHALL provide clear component structure requirements
+- Component exports MUST be the wrapper component (not content)
+- All React hooks MUST be called in the content component (after PageProvider initialization)
+- Loading and error states MUST be handled in the content component
+- Components MUST follow the established pattern from `DAKDashboard`, `ActorEditor`, and `CoreDataDictionaryViewer`
+
+**REQ-ARCH-003**: The system SHALL prevent PageProvider context initialization errors
+- No page hooks (`usePage()`, `useDAKParams()`) SHALL be called before `PageProvider` exists
+- Components SHALL handle the case where page context is loading or contains errors
+- Components SHALL degrade gracefully when required context is unavailable
+
+**Component Pattern Example**:
+```javascript
+// Wrapper component - exports this
+const MyDAKComponent = () => {
+ return (
+
+
+
+ );
+};
+
+// Content component - contains all logic and hooks
+const MyDAKComponentContent = () => {
+ const { profile, repository, branch, loading, error } = usePage();
+
+ if (loading) return
Loading...
;
+ if (error) return
Error: {error}
;
+
+ return
{/* Component implementation */}
;
+};
+
+export default MyDAKComponent;
+```
+
## 4. User Experience Requirements
### 4.1 Branding
diff --git a/src/components/ActorEditor.js b/src/components/ActorEditor.js
index a614ba34ce..22171de17a 100644
--- a/src/components/ActorEditor.js
+++ b/src/components/ActorEditor.js
@@ -1,506 +1,9 @@
import React, { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import actorDefinitionService from '../services/actorDefinitionService';
-import { PageLayout, useDAKParams } from './framework';
+import { PageLayout, usePage } from './framework';
-const ActorEditor = () => {
- const navigate = useNavigate();
- const pageParams = useDAKParams();
-
- // For now, we'll set editActorId to null since it's not in URL params
- // This could be enhanced later to support URL-based actor editing
- const editActorId = null;
-
- // State management - ALL HOOKS MUST BE AT THE TOP
- const [actorDefinition, setActorDefinition] = useState(null);
- const [loading, setLoading] = useState(true);
- const [saving, setSaving] = useState(false);
- const [errors, setErrors] = useState({});
- const [showPreview, setShowPreview] = useState(false);
- const [fshPreview, setFshPreview] = useState('');
- const [stagedActors, setStagedActors] = useState([]);
- const [showActorList, setShowActorList] = useState(false);
- const [activeTab, setActiveTab] = useState('basic');
-
- // Initialize component
- const initializeEditor = useCallback(async () => {
- setLoading(true);
-
- try {
- if (editActorId) {
- // Load existing actor definition from staging ground
- const actorData = actorDefinitionService.getFromStagingGround(editActorId);
- if (actorData) {
- setActorDefinition(actorData.actorDefinition);
- } else {
- setActorDefinition(actorDefinitionService.createEmptyActorDefinition());
- }
- } else {
- // Create new actor definition
- setActorDefinition(actorDefinitionService.createEmptyActorDefinition());
- }
-
- // Load staged actors list
- const staged = actorDefinitionService.listStagedActors();
- setStagedActors(staged);
-
- } catch (error) {
- console.error('Error initializing actor editor:', error);
- setErrors({ initialization: 'Failed to initialize editor' });
- } finally {
- setLoading(false);
- }
- }, [editActorId]);
-
- useEffect(() => {
- // Only initialize if we have valid page parameters
- if (!pageParams.error && !pageParams.loading) {
- initializeEditor();
- }
- }, [pageParams.error, pageParams.loading, initializeEditor]);
-
- // Handle form field changes
- const handleFieldChange = useCallback((field, value) => {
- setActorDefinition(prev => ({
- ...prev,
- [field]: value
- }));
-
- // Clear field-specific errors
- if (errors[field]) {
- setErrors(prev => {
- const newErrors = { ...prev };
- delete newErrors[field];
- return newErrors;
- });
- }
- }, [errors]);
-
- // Handle nested field changes
- const handleNestedFieldChange = useCallback((parentField, index, field, value) => {
- setActorDefinition(prev => {
- const newDefinition = { ...prev };
- if (!newDefinition[parentField]) {
- newDefinition[parentField] = [];
- }
- if (!newDefinition[parentField][index]) {
- newDefinition[parentField][index] = {};
- }
- newDefinition[parentField][index][field] = value;
- return newDefinition;
- });
- }, []);
-
- // Add new item to array field
- const addArrayItem = useCallback((field, defaultItem = {}) => {
- setActorDefinition(prev => ({
- ...prev,
- [field]: [...(prev[field] || []), defaultItem]
- }));
- }, []);
-
- // Remove item from array field
- const removeArrayItem = useCallback((field, index) => {
- setActorDefinition(prev => ({
- ...prev,
- [field]: prev[field].filter((_, i) => i !== index)
- }));
- }, []);
-
- // Validate form data
- const validateForm = useCallback(() => {
- const newErrors = {};
-
- if (!actorDefinition?.id) {
- newErrors.id = 'Actor ID is required';
- }
-
- if (!actorDefinition?.name) {
- newErrors.name = 'Actor name is required';
- }
-
- if (!actorDefinition?.description) {
- newErrors.description = 'Actor description is required';
- }
-
- if (!actorDefinition?.type) {
- newErrors.type = 'Actor type is required';
- }
-
- // Validate roles
- if (actorDefinition?.roles) {
- actorDefinition.roles.forEach((role, index) => {
- if (!role.code) {
- newErrors[`roles.${index}.code`] = 'Role code is required';
- }
- if (!role.display) {
- newErrors[`roles.${index}.display`] = 'Role display name is required';
- }
- if (!role.system) {
- newErrors[`roles.${index}.system`] = 'Role system is required';
- }
- });
- }
-
- // Validate qualifications
- if (actorDefinition?.qualifications) {
- actorDefinition.qualifications.forEach((qual, index) => {
- if (!qual.code) {
- newErrors[`qualifications.${index}.code`] = 'Qualification code is required';
- }
- if (!qual.display) {
- newErrors[`qualifications.${index}.display`] = 'Qualification display name is required';
- }
- });
- }
-
- setErrors(newErrors);
- return Object.keys(newErrors).length === 0;
- }, [actorDefinition]);
-
- // Generate FSH preview
- const generatePreview = useCallback(() => {
- if (!actorDefinition) return;
-
- try {
- const fsh = actorDefinitionService.generateFSH(actorDefinition);
- setFshPreview(fsh);
- } catch (error) {
- console.error('Error generating FSH preview:', error);
- setErrors({ general: 'Failed to generate FSH preview' });
- }
- }, [actorDefinition]);
-
- // Save actor definition to staging ground
- const handleSave = useCallback(async () => {
- if (!validateForm()) {
- return;
- }
-
- setSaving(true);
-
- try {
- actorDefinitionService.saveToStagingGround(actorDefinition, {
- type: 'actor-definition',
- actorId: actorDefinition.id,
- actorName: actorDefinition.name,
- branch: branch,
- repository: repository?.name,
- owner: profile?.login
- });
-
- // Refresh staged actors list
- const staged = actorDefinitionService.listStagedActors();
- setStagedActors(staged);
-
- setErrors({});
- } catch (error) {
- console.error('Error saving actor definition:', error);
- setErrors({ general: 'Failed to save actor definition' });
- } finally {
- setSaving(false);
- }
- }, [actorDefinition, validateForm, branch, repository, profile]);
-
- // Load template
- const loadTemplate = useCallback((templateId) => {
- const templates = actorDefinitionService.getActorTemplates();
- const template = templates.find(t => t.id === templateId);
- if (template) {
- setActorDefinition(template);
- }
- }, []);
-
- // Load staged actor
- const loadStagedActor = useCallback((actorId) => {
- const actorData = actorDefinitionService.getFromStagingGround(actorId);
- if (actorData) {
- setActorDefinition(actorData.actorDefinition);
- setShowActorList(false);
- }
- }, []);
-
- // Delete staged actor
- const deleteStagedActor = useCallback((actorId) => {
- if (window.confirm('Are you sure you want to delete this staged actor?')) {
- actorDefinitionService.removeFromStagingGround(actorId);
- const staged = actorDefinitionService.listStagedActors();
- setStagedActors(staged);
- }
- }, []);
-
- // Handle PageProvider initialization issues - AFTER all hooks
- if (pageParams.error) {
- return (
-
-
-
-
Page Context Error
-
{pageParams.error}
-
This component requires a DAK repository context to function properly.