# Architecture Rules - Frontend Rules
# Combined rules for JavaScript, Templates, Components, and Styling

# ============================================================================
# JAVASCRIPT ARCHITECTURE RULES
# ============================================================================

javascript_rules:

  - id: "JS-001"
    name: "Use centralized logger, not console"
    severity: "error"
    description: |
      Use window.LogConfig.createLogger() for consistent logging.
      Never use console.log, console.error, console.warn directly.
    pattern:
      file_pattern: "static/**/js/**/*.js"
      anti_patterns:
        - "console\\.log"
        - "console\\.error"
        - "console\\.warn"
      exceptions:
        - "// eslint-disable"
        - "console.log('✅"
      auto_exclude_files:
        - "init-*.js"
        - "vendor/"

  - id: "JS-002"
    name: "Use lowercase apiClient for API calls"
    severity: "error"
    description: |
      Use lowercase 'apiClient' consistently, not 'ApiClient' or 'API_CLIENT'
    pattern:
      file_pattern: "static/**/js/**/*.js"
      anti_patterns:
        - "ApiClient\\."
        - "API_CLIENT\\."
      required_pattern: "apiClient\\."

  - id: "JS-003"
    name: "Alpine components must spread ...data()"
    severity: "error"
    description: |
      All Alpine.js components must inherit base layout data using spread operator
    pattern:
      file_pattern: "static/**/js/**/*.js"
      required_in_alpine_components:
        - "\\.\\.\\.data\\(\\)"

  - id: "JS-004"
    name: "Alpine components must set currentPage"
    severity: "error"
    description: |
      All Alpine.js page components must set a currentPage identifier
    pattern:
      file_pattern: "static/**/js/**/*.js"
      required_in_alpine_components:
        - "currentPage:"

  - id: "JS-005"
    name: "Initialization methods must include guard"
    severity: "error"
    description: |
      Init methods should prevent duplicate initialization with guard
    pattern:
      file_pattern: "static/**/js/**/*.js"
      recommended_pattern: |
        if (window._pageInitialized) return;
        window._pageInitialized = true;
      auto_exclude_files:
        - "vendor/"

  - id: "JS-006"
    name: "All async operations must have try/catch with error logging"
    severity: "error"
    description: |
      All API calls and async operations must have error handling
    pattern:
      file_pattern: "static/**/js/**/*.js"
      check: "async_error_handling"

  - id: "JS-013"
    name: "Components overriding init() must call parent init"
    severity: "error"
    description: |
      When an Alpine.js component spreads ...data() and defines its own init() method,
      it MUST call the parent init() first. The parent init() sets critical properties
      like vendorCode (from URL), currentUser, and theme preference.

      Without calling parent init(), properties like vendorCode will be null, causing
      API calls like `/vendor/${this.vendorCode}/settings` to fail with
      "Endpoint not found: /api/v1/vendor/null/settings".

      WRONG (parent init never called):
        function vendorSettings() {
            return {
                ...data(),
                async init() {
                    await this.loadSettings(); // this.vendorCode is null!
                }
            };
        }

      RIGHT (call parent init first):
        function vendorSettings() {
            return {
                ...data(),
                async init() {
                    // IMPORTANT: Call parent init first to set vendorCode from URL
                    const parentInit = data().init;
                    if (parentInit) {
                        await parentInit.call(this);
                    }

                    await this.loadSettings(); // this.vendorCode is now set
                }
            };
        }

      This pattern is required for ALL page-specific JavaScript files that:
      1. Use ...data() to inherit base layout functionality
      2. Define their own init() method
    pattern:
      file_pattern: "static/vendor/js/**/*.js"
      check: "parent_init_call"
      required_when:
        - "contains: '...data()'"
        - "contains: 'async init()'"
      required_pattern:
        - "data\\(\\)\\.init"
        - "parentInit"
      exceptions:
        - "init-alpine.js"
        - "login.js"

  - id: "JS-014"
    name: "Vendor API calls must not include vendorCode in path"
    severity: "error"
    description: |
      Vendor API endpoints use JWT token authentication, NOT URL path parameters.
      The vendor is identified from the JWT token via get_current_vendor_api dependency.

      Do NOT include vendorCode in API paths for authenticated vendor endpoints.

      WRONG (vendorCode in API path):
        apiClient.get(`/vendor/${this.vendorCode}/orders`)
        apiClient.post(`/vendor/${this.vendorCode}/products`, data)

      RIGHT (no vendorCode, uses JWT):
        apiClient.get(`/vendor/orders`)
        apiClient.post(`/vendor/products`, data)

      EXCEPTIONS (these endpoints DO use vendorCode in path):
        - /vendor/{vendor_code} - Public vendor info (info.router)
        - /vendor/{vendor_code}/content-pages/* - Content pages management
        - Page URLs (not API calls) like window.location.href = `/vendor/${vendorCode}/...`

      Why this matters:
      - Including vendorCode causes 404 errors ("/vendor/orion/orders" not found)
      - The JWT token already identifies the vendor
      - Consistent with the API design pattern
    pattern:
      file_pattern: "static/vendor/js/**/*.js"
      anti_patterns:
        - "apiClient\\.(get|post|put|delete|patch)\\s*\\(\\s*`/vendor/\\$\\{this\\.vendorCode\\}/(orders|products|customers|inventory|analytics|dashboard|profile|settings|team|notifications|invoices|payments|media|marketplace|letzshop|billing|features|usage)"
      exceptions:
        - "init-alpine.js"
        - "login.js"
        - "content-pages.js"
        - "content-page-edit.js"

  - id: "JS-007"
    name: "Set loading state before async operations"
    severity: "warning"
    description: |
      Loading state should be set before and cleared after async operations
    pattern:
      file_pattern: "static/**/js/**/*.js"
      recommended_pattern: |
        loading = true;
        try {
          // operation
        } finally {
          loading = false;
        }

  - id: "JS-008"
    name: "Use apiClient for API calls, not raw fetch()"
    severity: "error"
    description: |
      All API calls must use the apiClient helper instead of raw fetch().
      The apiClient automatically:
      - Adds Authorization header with JWT token from cookies
      - Sets Content-Type headers
      - Handles error responses consistently
      - Provides logging integration

      WRONG (raw fetch):
        const response = await fetch('/api/v1/admin/products/123');

      RIGHT (apiClient):
        const response = await apiClient.get('/admin/products/123');
        const result = await apiClient.post('/admin/products', data);
        await apiClient.delete('/admin/products/123');
    pattern:
      file_pattern: "static/**/js/**/*.js"
      anti_patterns:
        - "fetch\\('/api/"
        - 'fetch\\("/api/'
        - "fetch\\(`/api/"
      exceptions:
        - "init-api-client.js"

  - id: "JS-009"
    name: "Use Utils.showToast() for notifications, not alert() or window.showToast"
    severity: "error"
    description: |
      All user notifications must use Utils.showToast() from static/shared/js/utils.js.
      Never use browser alert() dialogs or undefined window.showToast.

      Utils.showToast() provides:
      - Consistent styling (Tailwind-based toast in bottom-right corner)
      - Automatic fade-out after duration
      - Color-coded types (success=green, error=red, warning=yellow, info=blue)

      WRONG (browser dialog):
        alert('Product saved successfully');

      RIGHT (Utils helper):
        Utils.showToast('Product saved successfully', 'success');
        Utils.showToast('Failed to save product', 'error');
    pattern:
      file_pattern: "static/**/js/**/*.js"
      anti_patterns:
        - "alert\\("
        - "window\\.showToast"
      exceptions:
        - "utils.js"

  - id: "JS-015"
    name: "Use confirm_modal macros, not native confirm()"
    severity: "error"
    description: |
      All confirmation dialogs must use the project's confirm_modal or
      confirm_modal_dynamic Jinja2 macros from shared/macros/modals.html.
      Never use the native browser confirm() dialog.

      The modal macros provide:
      - Consistent styled dialogs matching the admin/store theme
      - Dark mode support
      - Variant colors (danger=red, warning=yellow, info=blue)
      - Icon support
      - Double-confirm pattern for destructive operations

      WRONG (native browser dialog):
        if (!confirm('Are you sure you want to delete this?')) return;
        if (!confirm(I18n.t('confirmations.delete'))) return;

      RIGHT (state variable + modal macro):
        // In JS: add state variable and remove confirm() guard
        showDeleteModal: false,
        async deleteItem() {
            // No confirm() guard — modal already confirmed
            await apiClient.delete('/admin/items/' + this.item.id);
        }

        // In template: button sets state, macro shows modal
        <button @click="showDeleteModal = true">Delete</button>
        {{ confirm_modal('deleteModal', 'Delete Item', 'Are you sure?',
           'deleteItem()', 'showDeleteModal', 'Delete', 'Cancel', 'danger') }}

      For dynamic messages (containing JS expressions):
        {{ confirm_modal_dynamic('deleteModal', 'Delete Item',
           "'Delete ' + item.name + '?'",
           'deleteItem()', 'showDeleteModal', 'Delete', 'Cancel', 'danger') }}
    pattern:
      file_pattern: "static/**/js/**/*.js"
      anti_patterns:
        - "confirm\\("
      exceptions:
        - "utils.js"
        - "vendor/"

  - id: "JS-010"
    name: "Use PlatformSettings for pagination rows per page"
    severity: "error"
    description: |
      All pages with tables MUST use window.PlatformSettings.getRowsPerPage()
      to load the platform-configured rows per page setting. This ensures
      consistent pagination behavior across the entire admin and vendor interface.

      The setting is configured at /admin/settings under the Display tab.
      Settings are cached client-side for 5 minutes to minimize API calls.

      Required pattern in init() method:
        async init() {
            // Guard against multiple initialization
            if (window._pageNameInitialized) return;
            window._pageNameInitialized = true;

            // REQUIRED: Load platform settings for pagination
            if (window.PlatformSettings) {
                this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
            }

            await this.loadData();
        }

      WRONG (hardcoded pagination):
        pagination: {
            page: 1,
            per_page: 50,  // Hardcoded!
            total: 0
        }

      RIGHT (platform settings):
        pagination: {
            page: 1,
            per_page: 20,  // Default, overridden by PlatformSettings
            total: 0
        }

        async init() {
            if (window.PlatformSettings) {
                this.pagination.per_page = await window.PlatformSettings.getRowsPerPage();
            }
        }

      Documentation: docs/frontend/shared/platform-settings.md
    pattern:
      file_pattern: "static/admin/js/**/*.js"
      required_in_pages_with_pagination:
        - "PlatformSettings\\.getRowsPerPage"
        - "window\\.PlatformSettings"
      exceptions:
        - "init-alpine.js"
        - "init-api-client.js"
        - "settings.js"

  - id: "JS-011"
    name: "Use standard pagination object structure"
    severity: "error"
    description: |
      All pages with tables MUST use the standard nested pagination object
      structure. This ensures compatibility with the pagination macro and
      consistent behavior across all pages.

      REQUIRED structure:
        pagination: {
            page: 1,
            per_page: 20,
            total: 0,
            pages: 0
        }

      WRONG (flat structure):
        page: 1,
        limit: 20,
        total: 0,
        skip: 0

      WRONG (different property names):
        pagination: {
            currentPage: 1,
            itemsPerPage: 20
        }

      Required computed properties:
        - totalPages
        - startIndex
        - endIndex
        - pageNumbers

      Required methods:
        - previousPage()
        - nextPage()
        - goToPage(pageNum)

      Documentation: docs/frontend/shared/pagination.md
    pattern:
      file_pattern: "static/**/js/**/*.js"
      required_in_pages_with_pagination:
        - "pagination:"
        - "pagination\\.page"
        - "pagination\\.per_page"
      anti_patterns_in_pagination_pages:
        - "^\\s*page:\\s*\\d"
        - "^\\s*limit:\\s*\\d"
        - "^\\s*skip:\\s*"
      exceptions:
        - "init-alpine.js"

  - id: "JS-012"
    name: "Do not include /api/v1 prefix in API endpoints"
    severity: "error"
    description: |
      When using apiClient.get(), apiClient.post(), etc., do NOT include
      the /api/v1 prefix in the endpoint path. The apiClient automatically
      prepends this prefix.

      CORRECT:
        apiClient.get('/admin/vendors')
        apiClient.post('/admin/products')
        const url = '/admin/vendors'

      WRONG (causes double prefix /api/v1/api/v1/...):
        apiClient.get('/api/v1/admin/vendors')
        const url = '/api/v1/admin/vendors'
        const endpoint = '/api/v1/admin/products'

      Exception: Direct fetch() calls without apiClient should use full path.

      Documentation: docs/frontend/shared/api-client.md
    pattern:
      file_pattern: "static/**/js/**/*.js"
      anti_patterns:
        - "apiClient\\.(get|post|put|delete|patch)\\s*\\(\\s*['\"`]/api/v1"
        - "(const|let|var)\\s+(url|endpoint|apiEndpoint|apiUrl|path)\\s*=\\s*['\"`]/api/v1"
        - "\\$\\{.*\\}/api/v1"
      exceptions:
        - "init-api-client.js"
        - "api-client.js"

# ============================================================================
# TEMPLATE RULES (Jinja2)
# ============================================================================

template_rules:

  - id: "TPL-001"
    name: "Admin templates must extend admin/base.html"
    severity: "error"
    description: |
      All admin templates must extend the base template for consistency.

      Auto-excluded files:
      - login.html - Standalone login page (no sidebar/navigation)
      - errors/*.html - Error pages extend errors/base.html instead
      - test-*.html - Test/development templates

      Standalone template markers (place in first 5 lines):
      - {# standalone #} - Mark template as intentionally standalone
      - {# noqa: TPL-001 #} - Standard noqa style to suppress error
      - <!-- standalone --> - HTML comment style
    pattern:
      file_pattern: "app/templates/admin/**/*.html"
      required_patterns:
        - "{% extends ['\"]admin/base\\.html['\"] %}"
      auto_exclude_files:
        - "login.html"
        - "errors/"
        - "test-"
      standalone_markers:
        - "{# standalone #}"
        - "{# noqa: tpl-001 #}"
        - "<!-- standalone -->"
      exceptions:
        - "base.html"
        - "partials/"

  - id: "TPL-002"
    name: "Vendor templates must extend vendor/base.html"
    severity: "error"
    description: "All vendor templates must extend the base template"
    pattern:
      file_pattern: "app/templates/vendor/**/*.html"
      required_patterns:
        - "{% extends ['\"]vendor/base\\.html['\"] %}"
      exceptions:
        - "base.html"
        - "partials/"

  - id: "TPL-003"
    name: "Shop templates must extend shop/base.html"
    severity: "error"
    description: "All shop templates must extend the base template"
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      required_patterns:
        - "{% extends ['\"]shop/base\\.html['\"] %}"
      exceptions:
        - "base.html"
        - "partials/"

  - id: "TPL-004"
    name: "Use x-text for dynamic text content (prevents XSS)"
    severity: "warning"
    description: |
      Use x-text directive for dynamic content to prevent XSS vulnerabilities
    pattern:
      file_pattern: "app/templates/**/*.html"
      recommended_pattern: '<p x-text="item.name"></p>'

  - id: "TPL-005"
    name: "Use x-html ONLY for safe content"
    severity: "error"
    description: |
      Use x-html only for trusted content like icons, never for user-generated content
    pattern:
      file_pattern: "app/templates/**/*.html"
      safe_usage:
        - 'x-html="\\$icon\\('

  - id: "TPL-006"
    name: "Implement loading state for data loads"
    severity: "warning"
    description: |
      All templates that load data should show loading state
    pattern:
      file_pattern: "app/templates/**/*.html"
      recommended_pattern: '<div x-show="loading">Loading...</div>'

  - id: "TPL-007"
    name: "Implement empty state when no data"
    severity: "warning"
    description: |
      Show empty state when lists have no items
    pattern:
      file_pattern: "app/templates/**/*.html"
      recommended_pattern: '<template x-if="items.length === 0">No items</template>'

  - id: "TPL-008"
    name: "Use table_header_custom for custom headers, not table_header"
    severity: "error"
    description: |
      When using {% call %} to create custom table headers with th_sortable
      or custom <th> elements, you MUST use table_header_custom(), not table_header().

      The table_header() macro takes a columns list and does NOT support caller().
      Using {% call table_header() %} causes a Jinja2 error:
        "macro 'table_header' was invoked with two values for the special caller argument"

      WRONG (causes 500 error):
        {% call table_header() %}
            {{ th_sortable('name', 'Name', 'sortBy', 'sortOrder') }}
            <th class="px-4 py-3">Actions</th>
        {% endcall %}

      RIGHT (supports caller):
        {% call table_header_custom() %}
            {{ th_sortable('name', 'Name', 'sortBy', 'sortOrder') }}
            <th class="px-4 py-3">Actions</th>
        {% endcall %}

      OR for simple headers (list of column names):
        {{ table_header(['Name', 'Email', 'Status', 'Actions']) }}
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - "{%\\s*call\\s+table_header\\s*\\(\\s*\\)\\s*%}"
      required_alternative: "table_header_custom"

  - id: "TPL-009"
    name: "Use valid block names from base templates"
    severity: "error"
    description: |
      Templates must use block names that exist in their base template.
      Using undefined blocks silently fails (content is not rendered).

      Admin base blocks: title, extra_head, alpine_data, content, extra_scripts
      Vendor base blocks: title, extra_head, alpine_data, content, extra_scripts
      Shop base blocks: title, description, extra_head, alpine_data, content, extra_scripts

      WRONG: {% block page_scripts %}...{% endblock %}  (undefined)
      RIGHT: {% block extra_scripts %}...{% endblock %}
    pattern:
      file_pattern: "app/templates/admin/**/*.html"
      valid_blocks:
        - "title"
        - "extra_head"
        - "alpine_data"
        - "content"
        - "extra_scripts"
      forbidden_patterns:
        - "{% block page_scripts %}"
        - "{% block scripts %}"
        - "{% block js %}"
        - "{% block footer_scripts %}"
      exceptions:
        - "base.html"

  - id: "TPL-013"
    name: "Use new pagination macro API"
    severity: "error"
    description: |
      The pagination macro was simplified to only accept show_condition.
      It now relies on standardized Alpine.js component properties.

      OLD (deprecated - will break):
        {{ pagination(
            current_page='pagination.page',
            total_pages='totalPages',
            ...
        ) }}

      NEW (correct):
        {{ pagination(show_condition="!loading && pagination.total > 0") }}

      Required Alpine.js component properties:
        - pagination.page, pagination.total
        - totalPages, pageNumbers
        - startIndex, endIndex
        - previousPage(), nextPage(), goToPage()
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - "pagination\\s*\\([^)]*current_page\\s*="
        - "pagination\\s*\\([^)]*total_pages\\s*="
        - "pagination\\s*\\([^)]*page_numbers\\s*="
      exceptions:
        - "shared/macros/pagination.html"

  - id: "TPL-015"
    name: "Use correct page_header macro API"
    severity: "error"
    description: |
      The page_header macro does not accept a buttons=[] parameter.
      Use action_label/action_onclick for a single action button,
      or use page_header_flex with {% call %} for multiple buttons.

      OLD (deprecated - will break):
        {{ page_header('Title', buttons=[
            {'text': 'Add', 'icon': 'plus', 'click': 'doSomething()'}
        ]) }}

      NEW (single action button):
        {{ page_header('Title', action_label='Add', action_icon='plus', action_onclick='doSomething()') }}

      NEW (multiple buttons - use page_header_flex):
        {% call page_header_flex(title='Title') %}
        <button @click="action1()">Button 1</button>
        <button @click="action2()">Button 2</button>
        {% endcall %}

      Parameters for page_header:
        - title, subtitle
        - action_label, action_url, action_icon, action_onclick
        - back_url, back_label
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - "page_header\\s*\\([^)]*buttons\\s*="
      exceptions:
        - "shared/macros/headers.html"

  - id: "TPL-014"
    name: "Use new modal_simple macro API with call block"
    severity: "error"
    description: |
      The modal_simple macro now uses {% call %}...{% endcall %} syntax.
      Content (including buttons) goes inside the call block.

      OLD (deprecated - will break):
        {{ modal_simple(
            show_var='showModal',
            title='Title',
            icon='exclamation',
            confirm_text='OK',
            confirm_fn='doSomething()'
        ) }}
        <template x-if="showModal">...</template>

      NEW (correct):
        {% call modal_simple('modalId', 'Title', show_var='showModal') %}
        <div class="space-y-4">
            <p>Modal content here</p>
            <div class="flex justify-end gap-3">
                <button @click="showModal = false">Cancel</button>
                <button @click="doSomething()">OK</button>
            </div>
        </div>
        {% endcall %}

      Parameters: modal_simple(id, title, show_var='isModalOpen', size='md')
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - "\\{\\{\\s*modal_simple\\s*\\("
        - "modal_simple\\s*\\([^)]*icon\\s*="
        - "modal_simple\\s*\\([^)]*confirm_text\\s*="
        - "modal_simple\\s*\\([^)]*confirm_fn\\s*="
      exceptions:
        - "shared/macros/modals.html"

# ============================================================================
# FRONTEND COMPONENT RULES
# ============================================================================

frontend_component_rules:

  - id: "FE-001"
    name: "Use pagination macro instead of inline HTML"
    severity: "warning"
    description: |
      Use the shared pagination macro instead of duplicating pagination HTML.
      Import from shared/macros/pagination.html.

      RIGHT (use macro):
        {% from 'shared/macros/pagination.html' import pagination %}
        {{ pagination() }}
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - 'aria-label="Table navigation"'
        - "previousPage\\(\\).*nextPage\\(\\)"
      exceptions:
        - "shared/macros/pagination.html"
        - "components.html"

  - id: "FE-002"
    name: "Use $icon() helper instead of inline SVGs"
    severity: "warning"
    description: |
      Use the Alpine.js $icon() helper for consistent iconography.
      Do not use inline <svg> elements.

      RIGHT (icon helper):
        <span x-html="$icon('arrow-left', 'w-4 h-4')"></span>
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - "<svg.*viewBox.*>.*</svg>"
      exceptions:
        - "base.html"
        - "components.html"
        - "shared/macros/"

  - id: "FE-003"
    name: "Use table macros for consistent table styling"
    severity: "info"
    description: |
      Use the shared table macros for consistent table styling.
      Import from shared/macros/tables.html.
    pattern:
      file_pattern: "app/templates/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/tables.html' import"

  - id: "FE-004"
    name: "Use form macros for consistent form styling"
    severity: "info"
    description: |
      Use the shared form macros for consistent input styling and validation.
      Import from shared/macros/forms.html.
    pattern:
      file_pattern: "app/templates/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/forms.html' import"

  - id: "FE-008"
    name: "Use number_stepper macro for quantity inputs"
    severity: "warning"
    description: |
      Use the shared number_stepper macro instead of raw <input type="number">.
      This ensures consistent styling, proper dark mode support, and hides
      native browser spinners that render inconsistently.

      RIGHT (use macro):
        {% from 'shared/macros/inputs.html' import number_stepper %}
        {{ number_stepper(model='quantity', min=1, max=99) }}

      Suppress with:
        - {# noqa: FE-008 #} on the line or at file level
    pattern:
      file_pattern: "app/templates/**/*.html"
      anti_patterns:
        - 'type="number"'
        - "type='number'"
      exceptions:
        - "shared/macros/inputs.html"
        - "components.html"

  - id: "FE-009"
    name: "Use product_card macro for product displays"
    severity: "info"
    description: |
      Use the shared product_card macro for consistent product presentation.
      Import from shared/macros/shop/product-card.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/product-card.html' import"

  - id: "FE-010"
    name: "Use product_grid macro for product listings"
    severity: "info"
    description: |
      Use the shared product_grid macro for responsive product grids.
      Import from shared/macros/shop/product-grid.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/product-grid.html' import"

  - id: "FE-011"
    name: "Use add_to_cart macros for cart interactions"
    severity: "info"
    description: |
      Use the shared add-to-cart macros for consistent cart functionality.
      Import from shared/macros/shop/add-to-cart.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/add-to-cart.html' import"

  - id: "FE-012"
    name: "Use mini_cart macro for cart dropdown"
    severity: "info"
    description: |
      Use the shared mini_cart macros for header cart functionality.
      Import from shared/macros/shop/mini-cart.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/mini-cart.html' import"

  - id: "FE-013"
    name: "Use product_gallery macro for image galleries"
    severity: "info"
    description: |
      Use the shared product_gallery macros for product image displays.
      Import from shared/macros/shop/product-gallery.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/product-gallery.html' import"

  - id: "FE-014"
    name: "Use variant_selector macros for product options"
    severity: "info"
    description: |
      Use the shared variant_selector macros for product variant selection.
      Import from shared/macros/shop/variant-selector.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/variant-selector.html' import"

  - id: "FE-015"
    name: "Use product_info macros for product details"
    severity: "info"
    description: |
      Use the shared product_info macros for product detail sections.
      Import from shared/macros/shop/product-info.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/product-info.html' import"

  - id: "FE-016"
    name: "Use product_tabs macro for product content tabs"
    severity: "info"
    description: |
      Use the shared product_tabs macros for tabbed product information.
      Import from shared/macros/shop/product-tabs.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/product-tabs.html' import"

  - id: "FE-017"
    name: "Use category_nav macros for category navigation"
    severity: "info"
    description: |
      Use the shared category_nav macros for category navigation sidebars and menus.
      Import from shared/macros/shop/category-nav.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/category-nav.html' import"

  - id: "FE-018"
    name: "Use breadcrumbs macros for breadcrumb navigation"
    severity: "info"
    description: |
      Use the shared breadcrumbs macros for navigation trails.
      Import from shared/macros/shop/breadcrumbs.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/breadcrumbs.html' import"

  - id: "FE-019"
    name: "Use search_bar macros for product search"
    severity: "info"
    description: |
      Use the shared search_bar macros for product search functionality.
      Import from shared/macros/shop/search-bar.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/search-bar.html' import"

  - id: "FE-020"
    name: "Use filter_sidebar macros for product filtering"
    severity: "info"
    description: |
      Use the shared filter_sidebar macros for product filtering panels.
      Import from shared/macros/shop/filter-sidebar.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/filter-sidebar.html' import"

  - id: "FE-021"
    name: "Use star_rating macros for rating displays"
    severity: "info"
    description: |
      Use the shared star_rating macros for all rating displays and inputs.
      Import from shared/macros/shop/star-rating.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/star-rating.html' import"

  - id: "FE-022"
    name: "Use review macros for review displays"
    severity: "info"
    description: |
      Use the shared review macros for product reviews.
      Import from shared/macros/shop/reviews.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/reviews.html' import"

  - id: "FE-023"
    name: "Use trust_badges macros for trust signals"
    severity: "info"
    description: |
      Use the shared trust_badges macros for security and trust indicators.
      Import from shared/macros/shop/trust-badges.html.
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      encouraged_patterns:
        - "{% from 'shared/macros/shop/trust-badges.html' import"

# ============================================================================
# FRONTEND STYLING RULES
# ============================================================================

styling_rules:

  - id: "CSS-001"
    name: "Use Tailwind utility classes"
    severity: "warning"
    description: |
      Prefer Tailwind utility classes over custom CSS
    pattern:
      file_pattern: "app/templates/**/*.html"
      encouraged: true

  - id: "CSS-002"
    name: "Support dark mode with dark: prefix"
    severity: "warning"
    description: |
      All color classes should include dark mode variants
    pattern:
      file_pattern: "app/templates/**/*.html"
      recommended_pattern: 'class="bg-white dark:bg-gray-800"'

  - id: "CSS-003"
    name: "Shop templates use vendor theme CSS variables"
    severity: "error"
    description: |
      Shop templates must use CSS variables for vendor-specific theming
    pattern:
      file_pattern: "app/templates/shop/**/*.html"
      required_pattern: 'var\\(--color-primary\\)'

  - id: "CSS-004"
    name: "Mobile-first responsive design"
    severity: "warning"
    description: |
      Use mobile-first responsive classes
    pattern:
      file_pattern: "app/templates/**/*.html"
      recommended_pattern: 'class="grid-cols-1 md:grid-cols-2 lg:grid-cols-4"'
