dalim-fusion-es-api/generate_docs.py
DJP 584b7df68b feat: Dalim DAM web application — full build
Complete client-facing DAM interface for Dalim ES FUSiON GraphQL API:

- Asset browsing, search with faceted filtering, project/folder navigation
- Send To distribution to 17 MMS platforms (PIM, Social, Google, In-Store, Print)
- 10 workflow templates, approval queue, process monitor with progress bars
- Collections with thumbnail mosaics, dashboard with KPI cards and activity feed
- Docker Compose (app + PostgreSQL), mock mode, error boundaries
- Two-tier API reference docs (466 operations indexed, 29 detailed)
- MediaMarkt branding: Noto Sans Display, #DF0000 red, dark sidebar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 22:12:18 -04:00

486 lines
21 KiB
Python

#!/usr/bin/env python3
"""Generate Tier 1 index and Tier 2 reference from parsed API data."""
import json
import re
DOCS_DIR = '/Users/daveporter/Desktop/CODING-2024/DALIM-API/docs'
# Domain groupings based on operation name patterns
DOMAIN_PATTERNS = [
('Authentication & System', [
'connectAs', 'disconnectAs', 'whoami', 'serverInformation', 'authentications',
'createAuthentication', 'deleteAuthentication', 'editAuthentication',
'clientApplications', 'createClientApplication', 'deleteClientApplication', 'editClientApplication',
'getCorsSetting', 'setCorsSetting',
'getLogLevel', 'setLogLevel', 'getLogQueries', 'setLogQueries',
'getMaxQueryComplexity', 'setMaxQueryComplexity', 'getMaxQuerySize', 'setMaxQuerySize',
'getMaxTopLevelFieldCount', 'setMaxTopLevelFieldCount', 'queryStatistics',
'servlets', 'openDialogueConnection', 'closeDialogueConnection', 'dialogueConnections',
'get2FAQRCode', 'getSecret2FAKey', 'send2FAQRCodeByEmail', 'enable2FA', 'disable2FA',
'verify2FACode', 'reset2FAKey',
'myWebAuthnRegistrations', 'webAuthnRegistrations',
'deleteMyWebAuthnRegistration', 'deleteWebAuthnRegistration',
'editMyWebAuthnRegistration', 'editWebAuthnRegistration',
'startWebAuthnRegistration', 'finishWebAuthnRegistration',
'userConnectionById', 'userConnectionByClientId', 'userConnections',
'revokeUserConnection', 'authenticationChanged',
'reIndexAll', 'dummy',
]),
('Users & Profiles', [
'users', 'userById', 'createUser', 'changeUser', 'deleteUser',
'editUser', 'editMyUser', 'moveUser',
'changeMyPassword', 'changeMyProfile', 'resetUserPassword',
'userPreference', 'setUserPreference', 'editUserPreference',
'uploadAvatar', 'userChange', 'whenUserChange',
]),
('Security Profiles', [
'securityProfiles', 'securityProfileById', 'securityRoles',
'createAdminSecurityProfile', 'createDefaultSecurityProfile',
'createUserSecurityProfile', 'createSecurityProfileMask',
'deleteSecurityProfile', 'editSecurityProfile', 'duplicateSecurityProfile',
'addProfileToUser', 'removeProfileFromUser',
'putSecurityProperties', 'removeSecurityProperties',
'putSecurityRoles', 'removeSecurityRoles', 'setSecurityRoles',
]),
('Groups & Roles', [
'groups', 'groupById', 'createGroup', 'deleteGroup', 'editGroup',
'addUserToGroup', 'removeUserFromGroup',
'roles', 'roleById', 'createRole', 'deleteRole', 'editRole',
'addRoleToUser', 'removeRoleFromUser',
]),
('Organizations & Customers', [
'organizations', 'organizationById', 'organizationsByFilter',
'createOrganization', 'deleteOrganization', 'renameOrganization', 'editOrganization',
'uploadOrganizationLogo',
'customers', 'customerById', 'createCustomer', 'deleteCustomer',
'renameCustomer', 'editCustomer',
'addCustomerToGroup', 'addCustomerToOrganization',
'removeCustomerFromGroup', 'removeCustomerFromOrganization',
]),
('Projects', [
'projects', 'projectById', 'projectTemplates', 'projectTemplateById',
'projectFolderById',
'createProject', 'deleteProject', 'renameProject', 'duplicateProject',
'editProject', 'moveProject', 'moveProjectToCustomer',
'createProjectFolder', 'deleteProjectFolder',
'renameProjectFolder', 'editProjectFolder', 'moveProjectFolder',
'createProjectTemplate', 'deleteProjectTemplate',
'editProjectTemplate', 'duplicateProjectTemplate',
'createFolderFromProject', 'createProjectFromFolder',
'participantsByRoleFilter',
'projectChange', 'projectFolderChange',
]),
('Folders', [
'folders', 'folderById',
'createFolder', 'deleteFolder', 'renameFolder', 'moveFolder', 'editFolder',
'folderChange',
]),
('Assets', [
'assets', 'assetById', 'downloadAsset', 'downloadAssetWithNotes',
'createAsset', 'deleteAsset', 'renameAsset', 'moveAsset', 'editAsset',
'checkOutAsset', 'checkInAsset', 'cancelCheckOutAsset',
'copyAssetToFolder', 'createAssetAlias', 'removeAssetAlias',
'mergeAsset', 'reprocessAsset',
'editRevision', 'editInk',
'streamAttachment', 'streamFile',
'uploadFile', 'uploadOn', 'uploadOnMilestone',
'assetChange', 'mediaChange',
]),
('Collections', [
'collections', 'collectionById', 'anyCollections',
'createCollection', 'deleteCollection', 'renameCollection', 'editCollection',
'addObjectToCollection', 'removeObjectFromCollection',
'moveCollection', 'moveObjectFromCollectionToCollection',
'smartCollections', 'smartCollectionById',
'createSmartCollection', 'deleteSmartCollection',
'editSmartCollection', 'renameSmartCollection',
'collectionChange', 'smartCollectionChange',
]),
('Search & Filters', [
'search', 'searchBySmartCollection', 'entityByPath', 'dumpText',
'namedSearchFilters', 'namedSearchFilterById', 'namedSearchFilterByName',
'createNamedSearchFilter', 'deleteNamedSearchFilter', 'editNamedSearchFilter',
]),
('Approvals', [
'approvals', 'approvalsByUser',
'approve', 'approveObject', 'reject', 'rejectObject',
'resetApproval', 'resetObjectApproval',
]),
('Workflows & Processes', [
'workflows', 'workflowsById', 'workflowsByName', 'workflowsByEntity',
'workflowEngine',
'createWorkflow', 'deleteWorkflow', 'editWorkflow', 'duplicateWorkflow',
'startWorkflow', 'cancelWorkflow',
'editWorkflowEngineCapacity',
'processes', 'processById', 'processMonitoring',
'cancelProcess', 'deleteProcess', 'changeProcessPriority',
'startProcess', 'startFileProcess', 'startURLProcess', 'submitURLProcess',
'restartProcess', 'restartActivity',
'processChanged',
]),
('Notes & Annotations', [
'getNotes', 'noteReport',
'createNote', 'deleteNote', 'updateNote', 'editNote',
'replyToNote', 'editReplyOfNote', 'deleteReplyOfNote',
'addNoteAttachment', 'removeNoteAttachment',
'annotationStatuses', 'annotationStatusById',
'createAnnotationStatus', 'deleteAnnotationStatus',
'updateAnnotationStatus', 'editAnnotationStatus',
'proofReadingMarks', 'proofReadingMarksById',
'myProofReadingMarks', 'myProofReadingMarksById',
'createGlobalProofReadingMark', 'createPrivateProofReadingMark',
'deleteAnyProofReadingMark', 'deleteMyProofReadingMark',
'editGlobalProofReadingMark', 'editPrivateProofReadingmark',
'noteChange', 'whenNoteChange', 'proofReadingMarkChange',
]),
('Notifications', [
'notifications', 'userNotifications', 'notificationSender',
'notificationTemplates', 'notificationTemplateById',
'createNotificationTemplate', 'deleteNotificationTemplate',
'editNotificationTemplate', 'editNotifications',
'disableNotifications', 'enableNotifications',
'updateNotificationSender', 'stopStartNotificationSender',
'markAsSeen', 'resendMail',
]),
('Sharing', [
'getSharing', 'sharingById', 'sharingByUser', 'sharings', 'mySharing',
'createSharing', 'deleteSharing', 'deleteMySharing',
'updateSharing', 'editSharing', 'editMySharing', 'share',
]),
('Email & Output Channels', [
'emailTemplates', 'emailTemplateById',
'createEmailTemplate', 'deleteEmailTemplate',
'updateEmailTemplate', 'editEmailTemplate',
'outputChannelGroups', 'outputChannelGroupById', 'outputChannelById',
'createOutputChannelGroup', 'deleteOutputChannelGroup', 'editOutputChannelGroup',
'createEmailOutputChannel', 'deleteEmailOutputChannel', 'editEmailOutputChannel',
'createFileOutputChannel', 'deleteFileOutputChannel', 'editFileOutputChannel',
]),
('Input Channels & Rules', [
'inputChannels', 'inputChannelById',
'createInputChannel', 'deleteInputChannel', 'editInputChannel',
'inputRuleSets', 'inputRuleSetById',
'createInputRuleSet', 'deleteInputRuleSet', 'editInputRuleSet',
]),
('Metadata', [
'metadataDefinitionById', 'metadataDefinitionByRef',
'createMetadataDefinition', 'deleteMetadataDefinition',
'editMetadataDefinition', 'renameMetadataDefinition',
'nameSpaceDefinitions', 'nameSpaceDefinitionById',
'nameSpaceDefinitionByPrefix', 'nameSpaceDefinitionByURI',
'createMetadataNameSpace', 'deleteMetadataNameSpace', 'editMetadataNameSpace',
'getProperties', 'getProperty', 'setProperties', 'setContent', 'deleteProperty',
]),
('Thesaurus & Taxonomy', [
'thesaurus', 'thesaurusById', 'thesaurusByLabel', 'thesaurusByURI',
'createThesaurus', 'deleteThesaurus',
'synSetById', 'synSetByLabel', 'synSetByURI',
'createSynSet', 'deleteSynSet', 'editSynSet',
'reactivateSynSet', 'retireSynSet',
]),
('Volumes & Hosts', [
'volumes', 'volumeById', 'checkVolumeConnectivity',
'createVolume', 'createFileSystemVolume', 'deleteVolume',
'editVolume', 'editFileSystemVolume', 'updateFileSystemVolumeDiskId',
'hosts', 'hostById', 'hostFoldersByPath',
'deleteHost', 'editHost',
]),
('Color Management', [
'colorSpaces', 'colorSpaceById',
'createColorSpace', 'deleteColorSpace', 'editColorSpace',
'iccProfiles', 'iccProfileById', 'iccProfileByName',
'deleteIccProfile', 'uploadIccProfile',
'inks', 'inkById', 'inkByName', 'inkCoverage',
'viewingConditions', 'viewingConditionById',
'createViewingCondition', 'deleteViewingCondition', 'editViewingCondition',
'editIccContext', 'densitometer', 'gamutCheck', 'gamutWarning',
]),
('Layouts', [
'layouts', 'layoutById',
'createLayout', 'deleteLayout', 'editLayout',
]),
('User Actions', [
'userActions', 'userActionById', 'userActionIconNames',
'userActionInstancesById', 'userActionInstancesByUser',
'createUserAction', 'deleteUserAction', 'editUserAction',
'clearUserActionInstancesById', 'clearUserActionInstancesByUser',
'executeUserAction', 'startUserAction',
'uploadUserActionIcon',
'userActionChange', 'whenUserActionChange',
]),
('UI & Files', [
'getUIFiles', 'getUIFileContent', 'getUIFilesByFilter',
'getUIProjects', 'getUIProjectFiles', 'getUIProjectsByFilter',
'getUIProjectsByName', 'getUIProjectsByType',
'createUIFile', 'createAndUploadUIFile', 'deleteUIFile',
'editUIFile', 'saveUIFile', 'uploadUIFile',
'createUIFolder', 'deleteUIFolder',
'createUIProject', 'createUIProjectWithType', 'deleteUIProject',
'editUIProject',
'streamUIFileContent', 'getFileContent', 'saveFile',
]),
('Preflighting & Rasterizing', [
'preflightReport', 'streamPreflightPreview', 'rasterize', 'readBarCode',
]),
('Import / Export', [
'importedFiles', 'getImportConflicts', 'getImportInfo',
'importData', 'exportData', 'uploadImportFile',
'getSchemaExtensions', 'createSchemaExtension', 'deleteSchemaExtension',
'editSchemaExtension',
]),
('Events & Logging', [
'getEventLogs',
'whenObjectChange', 'whenStepStatusChange',
]),
('Relations', [
'createRelation', 'deleteRelation', 'deleteRelationFromObject', 'editRelation',
]),
('Reports', [
'reports', 'getReportURL',
]),
('Trash', [
'trashedObjects', 'deleteAllTrashedObjects', 'deleteObject',
'restoreTrashedObject', 'trashObject', 'unTrashObject', 'unTrashAllObjects',
]),
('Milestones', [
'createMilestone',
]),
('Activities', [
'activities', 'activityById', 'activityIconById', 'activityIcons',
'activityPresets', 'activityVariables',
'deleteActivity', 'deleteActivityIcon', 'deleteActivityPreset',
'duplicateActivity', 'createCustomActivity', 'deleteCustomActivity',
'editActivity', 'editActivityPreset', 'editCustomActivity',
'editActivityEngineCapacity', 'editActivityEngineTemplate',
'uploadActivityIcon',
]),
]
# Seed endpoints for Tier 2 detailed docs
SEED_ENDPOINTS = [
# Auth & System
'connectAs', 'disconnectAs', 'whoami', 'serverInformation',
# Users
'users', 'userById', 'createUser', 'changeUser',
# Security
'securityProfiles', 'createUserSecurityProfile', 'addProfileToUser', 'addRoleToUser',
# Projects
'projects', 'projectById', 'projectTemplates', 'createProject', 'deleteProject', 'createFolder',
# Assets
'assets', 'assetById', 'createAsset', 'deleteAsset', 'downloadAsset',
# Org
'customers', 'customerById', 'groups', 'addUserToGroup',
# Search
'search',
# Approvals
'approve', 'approveObject',
]
def generate_tier1_index(operations):
"""Generate the full capability index."""
lines = []
lines.append("# Dalim ES FUSiON API — Full Capability Index")
lines.append("")
lines.append("This file lists **all** GraphQL operations available in the Dalim ES FUSiON API.")
lines.append("For detailed docs (arguments, types, examples) on actively used endpoints, see `dalim-api-reference.md`.")
lines.append("")
lines.append(f"**Total: {len(operations)} operations** — {sum(1 for o in operations if o['type']=='query')} Queries, {sum(1 for o in operations if o['type']=='mutation')} Mutations, {sum(1 for o in operations if o['type']=='subscription')} Subscriptions")
lines.append("")
# Build a lookup
op_lookup = {op['name']: op for op in operations}
assigned = set()
for domain, names in DOMAIN_PATTERNS:
domain_ops = []
for name in names:
if name in op_lookup:
domain_ops.append(op_lookup[name])
assigned.add(name)
if not domain_ops:
continue
lines.append(f"## {domain}")
lines.append("")
# Group by type within domain
for op_type, label in [('query', 'Queries'), ('mutation', 'Mutations'), ('subscription', 'Subscriptions')]:
typed = [op for op in domain_ops if op['type'] == op_type]
if not typed:
continue
lines.append(f"### {label}")
for op in typed:
desc = op['description'] or 'No description'
# Clean up description
desc = desc.replace('\n', ' ').strip()
if len(desc) > 120:
desc = desc[:117] + '...'
ret = op['response_type']
lines.append(f"- `{op['name']}` — {desc} → `{ret}`")
lines.append("")
# Catch any unassigned operations
unassigned = [op for op in operations if op['name'] not in assigned]
if unassigned:
lines.append("## Other Operations")
lines.append("")
for op_type, label in [('query', 'Queries'), ('mutation', 'Mutations'), ('subscription', 'Subscriptions')]:
typed = [op for op in unassigned if op['type'] == op_type]
if not typed:
continue
lines.append(f"### {label}")
for op in typed:
desc = op['description'] or 'No description'
desc = desc.replace('\n', ' ').strip()
if len(desc) > 120:
desc = desc[:117] + '...'
ret = op['response_type']
lines.append(f"- `{op['name']}` — {desc} → `{ret}`")
lines.append("")
return '\n'.join(lines)
def generate_tier2_reference(operations):
"""Generate detailed reference for seed endpoints."""
op_lookup = {op['name']: op for op in operations}
lines = []
lines.append("# Dalim ES FUSiON API — Active Endpoint Reference")
lines.append("")
lines.append("Detailed documentation for the endpoints actively used in this project.")
lines.append("For a full list of all 466 available operations, see `dalim-api-index.md`.")
lines.append("")
lines.append("---")
lines.append("")
lines.append("## Authentication")
lines.append("")
lines.append("The API uses OAuth2 with HMAC SHA256 signing.")
lines.append("")
lines.append("**Token endpoint:** `https://{HOST}/ES/api/oauth/token`")
lines.append("**GraphQL endpoint:** `https://{HOST}/ES/api/graphql`")
lines.append("")
lines.append("**Get a token:**")
lines.append("```python")
lines.append('token_data = {')
lines.append(' "grant_type": "password",')
lines.append(' "client_id": CLIENT_ID,')
lines.append(' "client_secret": CLIENT_SECRET,')
lines.append(' "username": USERNAME,')
lines.append(' "password": PASSWORD')
lines.append('}')
lines.append('response = requests.post(TOKEN_URL, data=token_data)')
lines.append('access_token = response.json()["access_token"]')
lines.append('headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}')
lines.append("```")
lines.append("")
lines.append("**Dependency chain** (must create in this order):")
lines.append("Security Profiles → Users → Projects → Assets")
lines.append("")
lines.append("---")
lines.append("")
# Group seed endpoints by category
categories = [
("System & Auth", ['connectAs', 'disconnectAs', 'whoami', 'serverInformation']),
("Users", ['users', 'userById', 'createUser', 'changeUser']),
("Security Profiles", ['securityProfiles', 'createUserSecurityProfile', 'addProfileToUser', 'addRoleToUser']),
("Projects", ['projects', 'projectById', 'projectTemplates', 'createProject', 'deleteProject', 'createFolder']),
("Assets", ['assets', 'assetById', 'createAsset', 'deleteAsset', 'downloadAsset']),
("Organizations & Customers", ['customers', 'customerById', 'groups', 'addUserToGroup']),
("Search", ['search']),
("Approvals", ['approve', 'approveObject']),
]
for cat_name, cat_endpoints in categories:
lines.append(f"## {cat_name}")
lines.append("")
for ep_name in cat_endpoints:
if ep_name not in op_lookup:
lines.append(f"### {ep_name}")
lines.append(f"*Not found in API — may have a different name*")
lines.append("")
continue
op = op_lookup[ep_name]
lines.append(f"### {op['name']}")
lines.append("")
lines.append(f"**Type:** {op['type'].capitalize()}")
lines.append(f"**Returns:** `{op['response_type']}`")
lines.append("")
if op['description']:
lines.append(f"{op['description']}")
lines.append("")
if op['arguments']:
lines.append("**Arguments:**")
lines.append("")
lines.append("| Name | Type | Required | Description |")
lines.append("|------|------|----------|-------------|")
for arg in op['arguments']:
req = "Yes" if arg['required'] else "No"
desc = arg['description'] or ''
lines.append(f"| `{arg['name']}` | `{arg['type']}` | {req} | {desc} |")
lines.append("")
if op['example_query']:
lines.append("**Example Query:**")
lines.append("```graphql")
lines.append(op['example_query'])
lines.append("```")
lines.append("")
if op['example_variables']:
lines.append("**Example Variables:**")
lines.append("```json")
lines.append(op['example_variables'])
lines.append("```")
lines.append("")
if op['example_response']:
# Truncate very long responses
resp = op['example_response']
if len(resp) > 800:
resp = resp[:800] + '\n... (truncated)'
lines.append("**Example Response:**")
lines.append("```json")
lines.append(resp)
lines.append("```")
lines.append("")
lines.append("---")
lines.append("")
return '\n'.join(lines)
def main():
with open(f'{DOCS_DIR}/api_parsed.json') as f:
data = json.load(f)
operations = data['operations']
print(f"Loaded {len(operations)} operations")
# Generate Tier 1
tier1 = generate_tier1_index(operations)
tier1_path = f'{DOCS_DIR}/dalim-api-index.md'
with open(tier1_path, 'w') as f:
f.write(tier1)
print(f"Tier 1 index: {len(tier1):,} bytes → {tier1_path}")
# Generate Tier 2
tier2 = generate_tier2_reference(operations)
tier2_path = f'{DOCS_DIR}/dalim-api-reference.md'
with open(tier2_path, 'w') as f:
f.write(tier2)
print(f"Tier 2 reference: {len(tier2):,} bytes → {tier2_path}")
if __name__ == '__main__':
main()