Files
dss/.knowledge/dss-coding-standards.json
Digital Production Factory 276ed71f31 Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
2025-12-09 18:45:48 -03:00

736 lines
30 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"$schema": "dss-knowledge-v1",
"type": "coding_standards",
"version": "1.0.0",
"last_updated": "2025-12-08",
"description": "Immutable coding best practices for all DSS code. These standards are enforced via pre-commit hooks and guide all code contributions.",
"web_components": {
"principle": "All UI components MUST be Web Components using Custom Elements API",
"rules": [
{
"id": "WC-001",
"rule": "Shadow DOM Required",
"requirement": "MUST use attachShadow({ mode: 'open' }) for all components",
"exceptions": "None - this is non-negotiable for style encapsulation",
"rationale": "Prevents global CSS pollution and ensures component isolation",
"enforcement": "Pre-commit hook fails if component extends HTMLElement without Shadow DOM"
},
{
"id": "WC-002",
"rule": "Lifecycle Management",
"requirement": "MUST implement connectedCallback, disconnectedCallback, and attributeChangedCallback where appropriate",
"pattern": "Always clean up event listeners and subscriptions in disconnectedCallback",
"example": "disconnectedCallback() { if (this.unsubscribe) this.unsubscribe(); if (this.abortController) this.abortController.abort(); }"
},
{
"id": "WC-003",
"rule": "Observable Attributes",
"requirement": "Define observedAttributes static getter for reactive attributes",
"pattern": "static get observedAttributes() { return ['title', 'value', 'color']; }",
"rationale": "Enables reactive attribute changes without manual DOM manipulation"
},
{
"id": "WC-004",
"rule": "Component Registration",
"requirement": "Define custom element in component file using customElements.define()",
"pattern": "customElements.define('ds-component-name', ComponentClass);",
"naming": "All DSS components prefixed with 'ds-' to avoid conflicts"
}
]
},
"style_management": {
"principle": "Zero inline styles policy - all styles in Shadow DOM or external stylesheets",
"rules": [
{
"id": "STYLE-001",
"rule": "NO Inline Styles",
"requirement": "FORBIDDEN: style=\"...\" attributes in templates",
"exceptions": "ONLY dynamic computed values (e.g., transform: translateX(${x}px), width: ${percent}%)",
"enforcement": "Pre-commit hook fails if >10 inline styles detected",
"rationale": "Maintainability, separation of concerns, style encapsulation"
},
{
"id": "STYLE-002",
"rule": "Shadow DOM Styles",
"requirement": "All component styles in <style> block within shadowRoot.innerHTML",
"pattern": "this.shadowRoot.innerHTML = `<style>:host { display: block; } .card { padding: 16px; }</style><div class=\"card\">...</div>`;",
"best_practice": "Define styles at top of template for clarity"
},
{
"id": "STYLE-003",
"rule": "VSCode Theme Tokens",
"requirement": "MUST use CSS custom properties from VSCode theme",
"required_variables": [
"--vscode-foreground",
"--vscode-background",
"--vscode-sidebar-background",
"--vscode-button-background",
"--vscode-button-foreground",
"--vscode-button-secondaryBackground",
"--vscode-button-secondaryForeground",
"--vscode-focusBorder",
"--vscode-list-hoverBackground",
"--vscode-list-activeSelectionBackground",
"--vscode-list-activeSelectionForeground",
"--vscode-descriptionForeground",
"--vscode-widget-border",
"--vscode-errorForeground"
],
"rationale": "Ensures consistent theming with VSCode dark/light mode"
},
{
"id": "STYLE-004",
"rule": "Constructable Stylesheets",
"requirement": "Use for shared styles across multiple components",
"pattern": "const sheet = new CSSStyleSheet(); sheet.replaceSync(css); shadowRoot.adoptedStyleSheets = [sheet];",
"use_cases": ["Common button styles", "Typography system", "Layout utilities"]
},
{
"id": "STYLE-005",
"rule": "CSS Hover Effects",
"requirement": "Use :hover pseudo-class, NOT onmouseover/onmouseout",
"correct": ".card:hover { background: var(--vscode-list-hoverBackground); }",
"forbidden": "onmouseover=\"this.style.background='...'\" onmouseout=\"this.style.background=''\"",
"rationale": "Performance, maintainability, separation of concerns"
}
]
},
"event_handling": {
"principle": "Event delegation pattern - NO inline event handlers",
"rules": [
{
"id": "EVENT-001",
"rule": "NO Inline Events",
"requirement": "FORBIDDEN: onclick, onmouseover, onmouseout, onkeydown, onkeyup, etc. in HTML",
"enforcement": "Pre-commit hook fails if ANY inline event handlers detected",
"rationale": "Security (CSP compliance), maintainability, testability, separation of concerns"
},
{
"id": "EVENT-002",
"rule": "Event Delegation Pattern",
"requirement": "Single delegated listener per component using data-action attributes",
"pattern": "this.shadowRoot.addEventListener('click', (e) => { const action = e.target.closest('[data-action]')?.dataset.action; if (action && this[`handle${action}`]) { this[`handle${action}`](e); } });",
"html_example": "<button data-action=\"save\" type=\"button\">Save</button>",
"js_example": "handleSave(e) { /* implementation */ }"
},
{
"id": "EVENT-003",
"rule": "Custom Events for Communication",
"requirement": "Component communication via CustomEvent with composed: true",
"pattern": "this.dispatchEvent(new CustomEvent('ds-action', { detail: { action, data }, bubbles: true, composed: true }));",
"rationale": "composed: true allows events to bubble out of Shadow DOM boundaries"
},
{
"id": "EVENT-004",
"rule": "Event Listener Cleanup",
"requirement": "Always remove event listeners in disconnectedCallback",
"pattern": "this.abortController = new AbortController(); addEventListener('click', handler, { signal: this.abortController.signal }); // disconnectedCallback: this.abortController.abort();",
"alternative": "Store handlers as methods and call removeEventListener explicitly"
},
{
"id": "EVENT-005",
"rule": "Keyboard Navigation",
"requirement": "Support Tab, Enter, Escape, Arrow keys for interactive components",
"pattern": "this.shadowRoot.addEventListener('keydown', (e) => { if (e.key === 'Escape') this.close(); if (e.key === 'Enter') this.submit(); });",
"rationale": "Accessibility requirement for keyboard-only users"
}
]
},
"accessibility": {
"principle": "WCAG 2.1 Level AA compliance minimum",
"rules": [
{
"id": "A11Y-001",
"rule": "Semantic HTML",
"requirement": "MUST use semantic elements: <button>, <nav>, <main>, <aside>, <header>, <footer>, <article>, <section>",
"forbidden": "<div onclick=\"...\"> for interactive elements, <div class=\"button\">",
"correct": "<button type=\"button\">Click me</button>",
"rationale": "Screen readers rely on semantic HTML for navigation and interaction"
},
{
"id": "A11Y-002",
"rule": "Button Type Attribute",
"requirement": "ALL <button> elements MUST have type=\"button\" (or type=\"submit\" in forms)",
"pattern": "<button type=\"button\">Action</button>",
"rationale": "Prevents accidental form submission in HTML forms",
"enforcement": "Pre-commit hook warns about buttons without type attribute"
},
{
"id": "A11Y-003",
"rule": "ARIA Attributes",
"requirement": "Use when semantic HTML insufficient",
"required_patterns": [
"aria-label for icon-only buttons",
"aria-labelledby for complex widgets",
"aria-describedby for additional context",
"role for custom interactive elements"
],
"examples": [
"<button aria-label=\"Close dialog\" type=\"button\">×</button>",
"<div role=\"group\" aria-labelledby=\"tools-heading\">...</div>"
]
},
{
"id": "A11Y-004",
"rule": "Focus Management",
"requirement": "Keyboard navigation support for all interactive elements",
"css_pattern": ".btn:focus-visible { outline: 2px solid var(--vscode-focusBorder); outline-offset: 2px; }",
"js_requirements": [
"trapFocus() for modals",
"restoreFocus() on close",
"Skip links for main content",
"Focus first invalid field on validation error"
]
},
{
"id": "A11Y-005",
"rule": "Color Contrast",
"requirement": "Minimum 4.5:1 for normal text, 3:1 for large text",
"tool": "Use VSCode theme tokens which meet contrast requirements",
"testing": "Chrome DevTools Lighthouse audit"
},
{
"id": "A11Y-006",
"rule": "Screen Reader Testing",
"requirement": "Test all components with NVDA/JAWS (Windows) or VoiceOver (Mac)",
"checklist": [
"Navigation order makes sense",
"All buttons have clear labels",
"Error messages announced",
"Status updates announced with aria-live"
]
}
]
},
"state_management": {
"principle": "Centralized state with reactive updates",
"rules": [
{
"id": "STATE-001",
"rule": "Context Store for Global State",
"requirement": "Use contextStore for application-wide state (projectId, teamId, userId)",
"pattern": "this.unsubscribe = contextStore.subscribeToKey('projectId', (newValue) => { this.projectId = newValue; this.render(); });",
"path": "admin-ui/js/stores/context-store.js"
},
{
"id": "STATE-002",
"rule": "Component Local State",
"requirement": "Component-specific state in this.state object",
"pattern": "this.state = { isLoading: false, data: null, error: null }; setState(updates) { Object.assign(this.state, updates); this.render(); }",
"best_practice": "Initialize state in constructor"
},
{
"id": "STATE-003",
"rule": "NO Direct DOM Manipulation",
"requirement": "State changes trigger re-renders, not direct DOM updates",
"forbidden": "document.getElementById('foo').textContent = 'bar'; element.style.display = 'none';",
"correct": "this.setState({ foo: 'bar', visible: false }); // render() handles DOM updates",
"rationale": "Maintains single source of truth, prevents state/view desync"
},
{
"id": "STATE-004",
"rule": "Subscription Cleanup",
"requirement": "Always unsubscribe in disconnectedCallback",
"pattern": "connectedCallback() { this.unsubscribe = store.subscribe(...); } disconnectedCallback() { if (this.unsubscribe) this.unsubscribe(); }",
"rationale": "Prevents memory leaks from orphaned subscriptions"
},
{
"id": "STATE-005",
"rule": "Immutable State Updates",
"requirement": "Create new state objects, don't mutate existing",
"correct": "this.state = { ...this.state, count: this.state.count + 1 };",
"forbidden": "this.state.count++; // direct mutation",
"rationale": "Enables change detection and debugging"
}
]
},
"code_organization": {
"principle": "Single Responsibility, clear structure, modular design",
"rules": [
{
"id": "ORG-001",
"rule": "File Size Limit",
"requirement": "Maximum 500 lines per file",
"action": "If larger, split into multiple modules",
"enforcement": "Quality check warns on files >500 lines",
"current_violation": "app.js at 4,347 lines must be decomposed"
},
{
"id": "ORG-002",
"rule": "Directory Structure",
"requirement": "Strict organization by type and purpose",
"structure": {
"admin-ui/js/components/": "Web components (*.js)",
"admin-ui/js/components/layout/": "Layout components (shell, header, sidebar)",
"admin-ui/js/components/metrics/": "Dashboard and metric components",
"admin-ui/js/components/tools/": "Tool-specific components",
"admin-ui/js/components/listings/": "List/table components",
"admin-ui/js/stores/": "State management",
"admin-ui/js/utils/": "Helper functions and utilities",
"admin-ui/js/core/": "Core modules (router, messaging, workflows)",
"admin-ui/js/workdesks/": "Team workdesk controllers",
"admin-ui/js/config/": "Configuration files"
}
},
{
"id": "ORG-003",
"rule": "Import Style",
"requirement": "Explicit named imports, no wildcards",
"correct": "import { hydrateComponent } from '../config/component-registry.js';",
"forbidden": "import * as registry from '../config/component-registry.js';",
"rationale": "Tree-shaking, explicit dependencies, better IDE support"
},
{
"id": "ORG-004",
"rule": "Export Style",
"requirement": "Named exports for utilities, default export for components",
"utility_pattern": "export function debounce(fn, ms) { ... } export function throttle(fn, ms) { ... }",
"component_pattern": "export default class MyComponent extends HTMLElement { ... }",
"rationale": "Convention clarity, supports tree-shaking"
},
{
"id": "ORG-005",
"rule": "Single Responsibility Principle",
"requirement": "One component = one concern, one file = one primary export",
"examples": [
"ds-metric-card.js: Displays a single metric card",
"ds-frontpage.js: Orchestrates dashboard layout",
"context-store.js: Manages global application state"
],
"anti_pattern": "utility-functions.js with 50 unrelated functions"
}
]
},
"error_handling": {
"principle": "Structured logging, user-friendly errors, graceful degradation",
"rules": [
{
"id": "ERROR-001",
"rule": "Centralized Logger",
"requirement": "Use logger utility for all logging",
"path": "admin-ui/js/utils/logger.js",
"methods": [
"logger.debug(msg, ...args): Development-only logging",
"logger.info(msg, ...args): Informational messages",
"logger.warn(msg, ...args): Warning conditions",
"logger.error(msg, ...args): Error conditions"
],
"pattern": "import { logger } from '../utils/logger.js'; logger.info('[ComponentName] Action completed', { data });"
},
{
"id": "ERROR-002",
"rule": "NO console.log in Production",
"requirement": "Replace all console.log/warn/error with logger methods",
"enforcement": "Pre-commit hook warns if >10 console statements",
"exceptions": "Core initialization logging in app.js only",
"migration": "console.log('foo') → logger.debug('foo')"
},
{
"id": "ERROR-003",
"rule": "User-Friendly Error Messages",
"requirement": "Error messages must be actionable and clear",
"good": "Failed to load projects. Please check your internet connection and try again.",
"bad": "Error: HTTP 500", "TypeError: Cannot read property 'id' of undefined",
"pattern": "Show what failed + why it might have failed + what user can do"
},
{
"id": "ERROR-004",
"rule": "Error Taxonomy",
"requirement": "Use structured error codes from messaging.js",
"codes": {
"E1xxx": "User errors (invalid input, forbidden actions)",
"E2xxx": "Validation errors (missing fields, invalid formats)",
"E3xxx": "API errors (request failed, timeout, unauthorized)",
"E4xxx": "System errors (unexpected, network, storage)",
"E5xxx": "Integration errors (Figma, external APIs)",
"S1xxx": "Success codes"
},
"usage": "notifyError('E3001', 'Failed to fetch projects', error);"
},
{
"id": "ERROR-005",
"rule": "Graceful Degradation",
"requirement": "Components must handle missing/invalid data gracefully",
"patterns": [
"if (!data) return this.renderEmptyState();",
"if (error) return this.renderError(error);",
"const items = data?.items ?? [];"
],
"anti_pattern": "Assuming data exists and causing cascading failures"
},
{
"id": "ERROR-006",
"rule": "Try-Catch for Async Operations",
"requirement": "Wrap all async operations in try-catch",
"pattern": "async loadData() { try { const data = await fetch(...); } catch (error) { logger.error('[Component] Failed to load', error); this.handleError(error); } }",
"rationale": "Prevents unhandled promise rejections"
}
]
},
"performance": {
"principle": "Optimize for user experience, measure and improve",
"rules": [
{
"id": "PERF-001",
"rule": "Lazy Loading",
"requirement": "Non-critical components loaded on-demand via hydrateComponent()",
"pattern": "await hydrateComponent('ds-screenshot-gallery', container);",
"benefits": "Faster initial load, reduced bundle size",
"applies_to": ["Tool components", "Heavy visualizations", "Rarely-used features"]
},
{
"id": "PERF-002",
"rule": "Virtual Scrolling",
"requirement": "Use for lists >100 items",
"libraries": ["lit-virtualizer", "virtual-scroller"],
"pattern": "import { VirtualScroller } from 'virtual-scroller'; new VirtualScroller(container, { items, renderItem });",
"applies_to": ["Token lists", "Component catalogs", "Log viewers"]
},
{
"id": "PERF-003",
"rule": "Debouncing and Throttling",
"requirement": "Debounce search inputs, throttle scroll/resize handlers",
"debounce_pattern": "this.searchDebounced = debounce(() => this.performSearch(), 300);",
"throttle_pattern": "this.onScrollThrottled = throttle(() => this.handleScroll(), 100);",
"use_cases": {
"debounce": "Search inputs, form validation, autosave",
"throttle": "Scroll handlers, resize handlers, mousemove tracking"
}
},
{
"id": "PERF-004",
"rule": "Avoid Unnecessary Re-renders",
"requirement": "Only re-render when state actually changes",
"pattern": "attributeChangedCallback(name, oldValue, newValue) { if (oldValue === newValue) return; this.render(); }",
"best_practice": "Compare old vs new state before rendering"
},
{
"id": "PERF-005",
"rule": "Bundle Size Monitoring",
"requirement": "Monitor and optimize JavaScript bundle sizes",
"targets": {
"individual_component": "<50KB",
"total_bundle": "<500KB",
"critical_path": "<200KB"
},
"tools": ["webpack-bundle-analyzer", "source-map-explorer"]
},
{
"id": "PERF-006",
"rule": "Minimize DOM Operations",
"requirement": "Batch DOM updates, use DocumentFragment for multiple inserts",
"pattern": "const fragment = document.createDocumentFragment(); items.forEach(item => fragment.appendChild(createNode(item))); container.appendChild(fragment);",
"anti_pattern": "items.forEach(item => container.appendChild(createNode(item))); // causes multiple reflows"
}
]
},
"security": {
"principle": "Secure by default, defense in depth",
"rules": [
{
"id": "SEC-001",
"rule": "NO Hardcoded Secrets",
"requirement": "FORBIDDEN: API keys, passwords, tokens, credentials in code",
"enforcement": "Pre-commit hook fails if secret patterns detected (apiKey, api_key, password, secret, token)",
"correct": "Use environment variables or secure configuration service",
"rationale": "Prevents credential leaks in version control"
},
{
"id": "SEC-002",
"rule": "Input Sanitization",
"requirement": "ALWAYS escape user input before rendering to DOM",
"utility": "ComponentHelpers.escapeHtml(userInput)",
"pattern": "<div>${ComponentHelpers.escapeHtml(project.name)}</div>",
"forbidden": "<div>${project.name}</div> // XSS vulnerability",
"rationale": "Prevents XSS attacks"
},
{
"id": "SEC-003",
"rule": "CSP Compliance",
"requirement": "NO eval(), NO new Function(), NO inline scripts",
"forbidden": [
"eval(code)",
"new Function('x', 'return x * 2')",
"<script>alert(1)</script> in templates"
],
"rationale": "Content Security Policy compatibility, prevents code injection"
},
{
"id": "SEC-004",
"rule": "HTTPS Only",
"requirement": "All external requests use HTTPS",
"enforcement": "No http:// URLs in fetch() calls",
"correct": "fetch('https://api.example.com/data')",
"forbidden": "fetch('http://api.example.com/data')",
"exceptions": "localhost development only"
},
{
"id": "SEC-005",
"rule": "Validate API Responses",
"requirement": "Always validate structure and content of API responses",
"pattern": "const data = await response.json(); if (!data || !Array.isArray(data.items)) throw new Error('Invalid response');",
"rationale": "Prevents errors from malformed/malicious responses"
},
{
"id": "SEC-006",
"rule": "Authentication Token Handling",
"requirement": "Store auth tokens securely, never in localStorage",
"correct": "sessionStorage (better: httpOnly cookies)",
"forbidden": "localStorage for sensitive tokens",
"rationale": "localStorage accessible to XSS attacks"
}
]
},
"testing_and_quality": {
"principle": "Automated quality gates, comprehensive testing",
"rules": [
{
"id": "TEST-001",
"rule": "Pre-commit Hooks",
"requirement": "MUST pass all quality checks before commit",
"script": "scripts/verify-quality.sh",
"thresholds": {
"inline_styles": "≤10 (exceptions for dynamic values only)",
"inline_events": "0 (zero tolerance)",
"console_statements": "≤10 (production code only)",
"file_size": "≤100KB per file",
"syntax_errors": "0 (zero tolerance)"
},
"bypass": "git commit --no-verify (not recommended, requires justification)"
},
{
"id": "TEST-002",
"rule": "Component Unit Tests",
"requirement": "Unit tests for all components",
"coverage": "Minimum 80% for critical paths",
"framework": "Web Test Runner or Vitest",
"test_cases": [
"Component renders correctly",
"Props/attributes update component",
"Event handlers work",
"Cleanup happens on disconnect"
]
},
{
"id": "TEST-003",
"rule": "Integration Tests",
"requirement": "Test critical user flows end-to-end",
"examples": [
"Project creation workflow",
"Token extraction from Figma",
"Component audit process",
"User authentication flow"
],
"tools": ["Playwright", "Cypress"]
},
{
"id": "TEST-004",
"rule": "Visual Regression Testing",
"requirement": "Screenshot comparison for UI changes",
"tools": ["Playwright screenshots", "Percy", "Chromatic"],
"process": "Capture baseline → Make changes → Compare → Approve/reject",
"applies_to": "All visible UI components"
},
{
"id": "TEST-005",
"rule": "Documentation",
"requirement": "JSDoc comments for public APIs and complex logic",
"pattern": "/**\n * Load project data from API\n * @param {string} projectId - The project identifier\n * @returns {Promise<Project>} The loaded project\n * @throws {Error} If project not found or network error\n */\nasync loadProject(projectId) { ... }",
"applies_to": ["Public component methods", "Utility functions", "Store APIs"]
},
{
"id": "TEST-006",
"rule": "Code Review Checklist",
"requirement": "All PRs reviewed against these standards",
"checklist": [
"✓ Shadow DOM used for all components",
"✓ No inline styles or event handlers",
"✓ Proper accessibility attributes",
"✓ Event listeners cleaned up",
"✓ User input sanitized",
"✓ Error handling implemented",
"✓ Tests added/updated"
]
}
]
},
"enforcement": {
"description": "How these standards are enforced in the development workflow",
"mechanisms": [
{
"type": "Pre-commit Hooks",
"file": ".git/hooks/pre-commit",
"action": "Runs scripts/verify-quality.sh automatically",
"can_bypass": "git commit --no-verify (requires justification)"
},
{
"type": "Quality Verification Script",
"file": "scripts/verify-quality.sh",
"checks": [
"Inline event handlers detection",
"Inline styles counting",
"Missing ARIA attributes",
"Console.log statements",
"JavaScript syntax validation",
"Hardcoded secrets detection",
"Shadow DOM usage statistics",
"File size warnings"
]
},
{
"type": "Immutability Protection",
"file": ".clauderc",
"protection": "This file listed in protected_core_files",
"requirement": "ALLOW_CORE_CHANGES=true to modify"
},
{
"type": "AI Agent Instructions",
"description": "AI assistants programmed to follow these standards",
"behavior": [
"Always use Shadow DOM for components",
"Never generate inline event handlers",
"Extract inline styles to style blocks",
"Add proper accessibility attributes",
"Use logger instead of console.log"
]
}
]
},
"migration_strategy": {
"description": "How to migrate existing code to these standards",
"phases": [
{
"phase": 1,
"name": "Foundation Fixes",
"duration": "Week 1",
"priority": "Critical",
"tasks": [
"Refactor tool-templates.js to generate compliant HTML",
"Create logger utility (admin-ui/js/utils/logger.js)",
"Update verify-quality.sh thresholds",
"Create migration guide with examples"
]
},
{
"phase": 2,
"name": "Component Migration - Batch A",
"duration": "Week 2",
"priority": "High",
"targets": [
"Layout components (ds-project-selector, ds-shell, ds-header)",
"Most violated: ds-screenshot-gallery, ds-network-monitor"
],
"pattern": "Add Shadow DOM → Extract styles → Replace inline events → Add ARIA"
},
{
"phase": 3,
"name": "Component Migration - Batch B",
"duration": "Week 3",
"priority": "High",
"targets": [
"Tool components (ds-activity-log, ds-test-results)",
"Admin/listings (ds-project-list, ds-token-list)"
]
},
{
"phase": 4,
"name": "Monolith Decomposition",
"duration": "Week 4",
"priority": "Critical",
"target": "app.js (4,347 lines → 7 modules)",
"modules": [
"app.js: Main orchestrator (<500 lines)",
"router.js: Hash routing",
"auth-manager.js: Authentication",
"api-client.js: Fetch wrapper",
"error-handler.js: Global errors",
"state-manager.js: State coordination",
"init.js: Initialization"
]
},
{
"phase": 5,
"name": "Quality Enforcement",
"duration": "Week 5",
"priority": "Medium",
"tasks": [
"Update thresholds (inline styles ≤10, events = 0)",
"Add ESLint/Stylelint rules",
"CI/CD integration",
"Developer training"
]
}
]
},
"reference_implementations": {
"description": "Examples of components that follow these standards",
"files": [
{
"file": "admin-ui/js/workdesks/base-workdesk.js",
"demonstrates": [
"Semantic HTML (buttons not divs)",
"Event delegation pattern",
"Extracted styles in style block",
"ARIA attributes",
"Focus management"
]
},
{
"file": "admin-ui/js/components/metrics/ds-frontpage.js",
"demonstrates": [
"Shadow DOM implementation",
"Zero inline styles",
"Lifecycle management",
"State subscription pattern",
"Event cleanup"
]
},
{
"file": "admin-ui/js/components/metrics/ds-metric-card.js",
"demonstrates": [
"Observable attributes",
"Shadow DOM encapsulation",
"Reactive rendering",
"Component composition"
]
}
]
},
"success_metrics": {
"description": "Measurable goals for DSS code quality",
"current_state": {
"shadow_dom_adoption": "23% (12/53 components)",
"inline_event_handlers": "20+",
"inline_styles": "1,288",
"console_statements": "100+",
"largest_file": "app.js at 4,347 lines / 156KB"
},
"target_state": {
"shadow_dom_adoption": "100% (53/53 components)",
"inline_event_handlers": "0 (zero tolerance)",
"inline_styles": "<10 (dynamic values only)",
"console_statements": "<10 (core only)",
"largest_file": "<500 lines per file"
},
"tracking": {
"method": "Pre-commit hook statistics",
"frequency": "Every commit",
"reporting": "Monthly code quality dashboard"
}
}
}