diff --git a/ai-agent-skills/README.md b/ai-agent-skills/README.md new file mode 100644 index 000000000..a617ae045 --- /dev/null +++ b/ai-agent-skills/README.md @@ -0,0 +1,100 @@ + + +# OFBiz Agent Skills Plugin + +## Overall Goal +The `ai-agent-skills` plugin is a repository of standardized knowledge, best practices, and implementation patterns for Apache OFBiz. Its primary purpose is to empower AI agents (like Antigravity) to perform complex OFBiz development tasksβ€”such as creating entities, defining services, building screens, and managing business logicβ€”with high accuracy and adherence to framework-specific guardrails. + +By providing these "skills" in a structured format, we ensure that agents follow the correct design patterns (e.g., favoring View Entities over manual iteration, using Worker classes correctly, adhering to security standards) without manual intervention for every step. + +## Agent Setup & Activation + +For an AI agent (like Antigravity, Cursor, or GitHub Copilot) to effectively use these skills, they need to be linked or aggregated into the specific directories those agents expect at the root of your workspace. + +### 1. Framework Location (Plugin) +Keep the source of these skills in your OFBiz plugins directory so they remain version-controlled alongside your project: +`~/ofbiz-framework/plugins/ai-agent-skills/` + +### 2. Synchronization via Gradle +To make these skills available and properly formatted for your specific AI agents, run the automated Gradle synchronization tasks from your OFBiz root directory. + +```bash +# Navigate to your OFBiz framework root +cd ~/ofbiz-framework + +# Option 1: Sync to the default generic agents directory (.agents/skills) +./gradlew syncAgentSkills +``` + +### Updating Skills +If you modify or add any content inside `plugins/ai-agent-skills`, you must re-run the sync command for the changes to take effect in your AI agents: + +```bash +./gradlew syncAgentSkills +``` +This command recopies the structured files into the `.agents/` folder by default. + +```bash +# Option 2: Sync targets individually using the -Pagent parameter +./gradlew syncAgentSkills -Pagent=agents # Copies folder to .agents/skills/ +./gradlew syncAgentSkills -Pagent=gemini # Copies folder to .gemini/skills/ +./gradlew syncAgentSkills -Pagent=claude # Copies folder to .claude/skills/ +./gradlew syncAgentSkills -Pagent=github # Copies folder to .github/skills/ +./gradlew syncAgentSkills -Pagent=cursor # Copies folder to .cursor/skills/ + +# You can also use "all" to copy to all supported agents at once: +./gradlew syncAgentSkills -Pagent=all + +# Or pass separated agents to target a subset explicitly: +./gradlew syncAgentSkills -Pagent=claude,github +``` + +Using these tasks ensures that as the skills in the plugin are updated, your agents automatically inherit the updates locally without manual intervention. + +## How to Use with an Agent +Once synced, the agents will automatically discover these skills when working in your OFBiz project directory. + +### Integration Patterns +- **Generic Agents**: Point them to the `.agents/skills` directory. +- **Gemini (Antigravity)**: Automatically reads from `.gemini/skills/`. +- **Claude**: Automatically reads contexts from `.claude/skills/`. +- **Cursor**: Automatically reads contexts from `.cursor/skills/`. +- **GitHub Copilot**: Automatically incorporates capabilities from `.github/skills/`. + +## Directory Structure +The master source of these skills should be placed within the `plugins` directory of your OFBiz framework: +`/path/to/ofbiz/plugins/ai-agent-skills/` + +Each directory contains: +- `SKILL.md`: The core knowledge file containing the goal, procedures, and guardrails for that specific skill. + +## Available Skills +For a detailed list of all skills with short descriptions, see [SKILLS_SUMMARY.md](~/ai-agent-skills/SKILLS_SUMMARY.md). + +The toolkit currently covers: +- **Core Abstractions**: `manage-entities`, `manage-services`, `manage-data`. +- **UI & Interaction**: `manage-screens`, `manage-forms`, `manage-menus`, `manage-templates`, `manage-ajax`. +- **Logic & Flows**: `manage-groovy`, `manage-java`, `manage-java-patterns`, `manage-eca`, `manage-service-groups`. +- **Integrations**: `manage-api-integration`, `manage-email-services`. +- **Advanced Management**: `manage-security-advanced`, `manage-localization-advanced`, `manage-webapps`, `manage-cache-and-performance`. +- **Strategies**: `manage-strategies` (Xml vs Java/Groovy, Dos and Donts). + +## Deployment and Updates +This plugin is linked to the GitHub repository. To update the skills available to your agent, pull the latest changes from the repository. diff --git a/ai-agent-skills/SKILLS_SUMMARY.md b/ai-agent-skills/SKILLS_SUMMARY.md new file mode 100644 index 000000000..d1dd494b2 --- /dev/null +++ b/ai-agent-skills/SKILLS_SUMMARY.md @@ -0,0 +1,85 @@ + + +# OFBiz Agent Skills: Summary of Coverage + +This document provides a high-level summary of the specialized skills developed for the OFBiz Agent Toolkit. These skills provide the necessary guardrails, patterns, and procedures for an AI agent to interact with the Apache OFBiz framework effectively. + +## πŸ—οΈ Core Abstractions +| Skill | Description | +| :--- | :--- | +| **manage-entities** | Handle Data Model changes, including entity definitions, relations, and primary keys. | +| **manage-services** | Define and implement OFBiz services (Java, Groovy, Script) with proper attributes and parameters. | +| **manage-data** | Manage Seed, Demo, and Setup data using Entity Engine XML artifacts. | +| **manage-dynamic-view-entities**| Create advanced View Entities dynamically for optimized data retrieval without raw SQL. | + +## 🎨 UI & Interaction +| Skill | Description | +| :--- | :--- | +| **manage-screens** | Build complex, reusable UI layouts using XML Screen Definitions and decorators. | +| **manage-forms** | Implement declarative data entry and display forms using the OFBiz Form Widget. | +| **manage-menus** | Manage application navigation and menu hierarchies. | +| **manage-templates** | Develop dynamic UI components using Apache FreeMarker (FTL) and macros. | +| **manage-ajax** | Implement seamless UI updates using OFBiz-standard AJAX patterns and event handling. | +| **manage-themes** | Handle visual styling, CSS integration, and theme-specific properties. | +| **manage-labels** | Manage internationalization (i18n) and UI text labels across multiple languages. | +| **manage-content** | Work with the OFBiz Content Management System (DataResource, Content, ElectronicText). | +| **manage-pdf-export** | Design and implement professional documents (Invoices, Labels) using Apache FOP (PDF). | + +## βš™οΈ Logic & Flows +| Skill | Description | +| :--- | :--- | +| **manage-groovy** | Write business logic using Groovy scripts, leveraging the `run-groovy` engine and DSL. | +| **manage-java** | Implement typed business logic and worker classes in the Java source layer. | +| **manage-java-patterns** | Adhere to OFBiz-specific Java design patterns (e.g., Worker classes, internal service calls). | +| **manage-java-events** | Implement OFBiz Events (web boundaries) and route HTTP requests in Java. | +| **manage-minilang** | Maintain and legacy MiniLang (XML) logic for standard service workflows. | +| **manage-eca** | Orchestrate Event Condition Actions (Service ECA and Entity ECA) for automated flows. | +| **manage-service-groups** | Define and manage aggregate service executions and engine-level groupings. | +| **manage-controller** | Configure web request mappings, security constraints, and view handlers in `controller.xml`. | +| **manage-async** | Manage asynchronous execution, scheduled jobs, and the JobSandbox in OFBiz. | +| **manage-quartz-jobs** | Schedule and manage background tasks, job polling, and temporal expressions. | + +## πŸ”Œ Integrations & Communication +| Skill | Description | +| :--- | :--- | +| **manage-api-integration** | Expose services via REST or SOAP and handle JSON/XML data mapping. | +| **manage-email-services** | Configure SMTP, manage email templates, and automate outgoing communications. | + +## πŸ” Advanced Management +| Skill | Description | +| :--- | :--- | +| **manage-security-advanced** | Implement complex security permissions, ACLs, and service-level data filtering. | +| **manage-security-deployment** | Harden and secure an OFBiz deployment at the infrastructure limit. | +| **manage-localization-advanced** | Handle advanced i18n, time zones, and locale-specific formatting. | +| **manage-webapps** | Configure web application boundaries, session management, and filter chains. | +| **manage-cache-and-performance** | Optimize performance through Entity Cache, Service Cache, and SQL query tuning. | +| **manage-properties** | Centralize configuration settings in `.properties` files for environment management. | + +## πŸš€ Project Lifecycle +| Skill | Description | +| :--- | :--- | +| **create-component** | Scaffold new OFBiz plugins using standardized directory structures. | +| **manage-component** | Manage component-level dependencies and `ofbiz-component.xml` registrations. | +| **coding-standards** | General guidelines for clean code, commenting, and OFBiz contribution standards. | + +## 🧠 Strategic Thinking +| Skill | Description | +| :--- | :--- | +| **manage-strategies** | High-level decision-making guide: XML vs Java, Service vs Event, and Performance tradeoffs. | diff --git a/ai-agent-skills/build.gradle b/ai-agent-skills/build.gradle new file mode 100644 index 000000000..3a51b78a9 --- /dev/null +++ b/ai-agent-skills/build.gradle @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths + +def ofbizRoot = project.file('../../').toPath() +def skillsDir = project.file('.').toPath() + +task syncAgentSkills { + group = 'AI Agents' + description = 'Syncs skills to agent directories. Usage: ./gradlew syncAgentSkills -Pagent=claude,gemini,github,cursor,agents,all (default is agents)' + doLast { + def agentsArg = project.hasProperty('agent') ? project.getProperty('agent') : 'agents' + def selectedAgents = agentsArg.split(',').collect { it.trim().toLowerCase() } + def supportedAgents = ['agents', 'gemini', 'claude', 'github', 'cursor'] + + def targetsToSync = selectedAgents.contains('all') ? supportedAgents : selectedAgents + + targetsToSync.each { agent -> + if (!supportedAgents.contains(agent)) { + println "⚠️ Unknown agent: ${agent}. Supported options are: ${supportedAgents.join(', ')}, all" + return + } + + def targetDirPath = ".${agent}/skills" + def targetDir = ofbizRoot.resolve(targetDirPath) + targetDir.toFile().mkdirs() + + copy { + from skillsDir.toFile() + into targetDir.toFile() + exclude "build" + exclude ".gradle" + exclude "build.gradle" + exclude "ofbiz-component.xml" + exclude "README.md" + exclude "SKILLS_SUMMARY.md" + } + println "βœ… Copied skills to ${targetDirPath}" + } + } +} + diff --git a/ai-agent-skills/coding-standards/SKILL.md b/ai-agent-skills/coding-standards/SKILL.md new file mode 100644 index 000000000..649343f58 --- /dev/null +++ b/ai-agent-skills/coding-standards/SKILL.md @@ -0,0 +1,73 @@ + + +--- +name: coding-standards +description: Guidelines for writing production-quality code, focusing on commenting style, cleanliness, and professionalism. +--- + +# Skill: coding-standards +## Goal +Ensure all OFBiz contributions meet production-grade standards for clarity, maintainability, and architectural alignment. + +## Triggers +**ALWAYS** read this skill when: +- Writing any code (Java, Groovy, XML, CSS). +- Reviewing PRs or auditing existing code for OFBiz alignment. +- Using OFBiz utility libraries for validation and map creation. +- Preparing a pull request or implementing new features. + +## General Rules +1. **Explain the WHY**: Code shows *what* happens. Comments must explain *why* (e.g., explaining a workaround for a legacy constraint). +2. **No Internal Monologue**: Delete "thinking out loud" or "maybe this works" comments. +3. **Guard against Technical Debt**: Avoid `// TODO` without a tracking reference. +4. **Remove Debug Code**: Clean up `System.out.println`, `println`, or excessive `Debug.logInfo` before completion. + +## OFBiz Specific Standards +1. **XML Actions**: Keep logic flat. If it requires complex loops or nesting, move to Groovy. +2. **Naming Conventions**: + - **Components**: `kebab-case` (e.g., `order-management`). + - **Entities/Services**: `UpperCamelCase` for entities, `lowerCamelCase` for services. + - **Java/Groovy**: `lowerCamelCase` for methods/variables, `UpperCamelCase` for classes. +3. **Documentation**: + - **Services**: Every service MUST have a `` in `services.xml`. + - **Java/Groovy**: Use Javadoc/Groovydoc for public methods and complex logic. +4. **Utility Libraries**: + - **Validation**: ALWAYS use `UtilValidate.isEmpty()` or `isNotEmpty()`. + - **Maps/Lists**: Use `UtilMisc.toMap(...)` and `UtilMisc.toList(...)` for concise creation. + - **Logging**: Use `Debug.logInfo(...)`, `Debug.logError(...)` with a `MODULE` tag. + - Use `.filterByDate()` for all date-effective entities (e.g., `ProductPrice`, `StatusItem`). + - Prefer `EntityQuery` over `delegator.findOne(...)`. +5. **Internationalization (i18n)**: + - Never hardcode user-facing strings. Use `uiLabelMap.LabelKey`. + +## Guardrails +- **Consistency**: Follow the existing indentation and naming conventions of the component you are editing. +- **Transactional Integrity**: Respect OFBiz service boundaries; don't commit transactions manually. + +## Examples +**Example: Clean documentation** +```java +// Check if the product is active based on current system time. +// We use filterByDate to ensure we only get valid price records. +GenericValue price = EntityQuery.use(delegator).from("ProductPrice") + .where("productId", productId) + .filterByDate() + .queryFirst(); +``` diff --git a/ai-agent-skills/create-component/SKILL.md b/ai-agent-skills/create-component/SKILL.md new file mode 100644 index 000000000..a5234992b --- /dev/null +++ b/ai-agent-skills/create-component/SKILL.md @@ -0,0 +1,73 @@ + + +--- +name: create-component +description: Scaffold a new OFBiz component (plugin) using Gradle. Use when starting a new feature set or isolating custom code. +--- + +# Skill: create-component +## Goal +Create a new, isolated OFBiz component with the correct directory structure and configuration. + +## Triggers +**ALWAYS** read this skill when: +- Creating a new plugin or component. +- Isolating a large feature set into a separate module. +- Understanding plugin discovery vs. manual registration. + +## Use when +- Starting a brand new feature (e.g., `my-custom-module`). +- Developing an integration that should not impact core components. + +## Procedure +1. **Gradle Command**: + - Run `./gradlew createPlugin -PpluginId=my-plugin-name`. + - Optional flags: `-PwebappName=my-app`, `-PbasePermission=MY_PERM`. +2. **Base Structure**: + - Ensure the following folders are present: `src`, `webapp`, `entitydef`, `servicedef`, `data`, `widget`. +3. **Initial Configuration**: + - Update `ofbiz-component.xml` with proper titles and descriptions. + - Add basic security permissions in `data/[Component]SecurityData.xml`. +4. **Registration (Automatic)**: + - OFBiz automatically discovers any directory in `plugins/` that contains an `ofbiz-component.xml` file. + - NO command like `./gradlew loadAll` is required for registration. + - OFBiz must be restarted (or a container reload triggered) to detect new components. + +## Post-Scaffold Customization +1. **Directory Structure**: Verify the existence of `entitydef/`, `servicedef/`, `data/`, and `webapp/`. +2. **Component XML**: Update `ofbiz-component.xml` with actual resource locations. +3. **Web Application**: If your component has a UI, ensure the `` entry has a unique `mount-point`. +4. **Permissions**: Define base permissions in `data/MyComponentSecurityData.xml`. + +## Guardrails +- **Naming**: Use lowercase, kebab-case (e.g., `order-management`). +- **Location**: All custom components MUST reside in the `plugins/` directory. +- **Discovery**: Plugins in `plugins/` are auto-discovered. Do not try to manually register them in framework load files. +- **Independence**: Ensure the new component doesn't break existing ones. +- **Best Practice**: Immediately create a dedicated `SecurityData.xml` to avoid permission conflicts. +- **Cleanliness**: Delete unused scaffolded files (e.g., placeholder entities) after creation. + +## Examples +**Example: Creating a new inventory plugin** +```bash +./gradlew createPlugin -PpluginId=inventory-custom -PwebappName=inventoryApp +./gradlew loadAll +``` +Then, verify the folder `plugins/inventory-custom` exists. diff --git a/ai-agent-skills/manage-ajax/SKILL.md b/ai-agent-skills/manage-ajax/SKILL.md new file mode 100644 index 000000000..3ac982057 --- /dev/null +++ b/ai-agent-skills/manage-ajax/SKILL.md @@ -0,0 +1,95 @@ + + +--- +name: manage-ajax +description: Implement AJAX-based UI interactions and partial updates in OFBiz. +--- + +# Skill: manage-ajax +## Goal +Configure and implement AJAX interactions to provide a seamless UI experience with partial page updates and JSON data exchange. + +## Triggers +**ALWAYS** read this skill when: +- Adding `` to forms, grids, or screens. +- Configuring controller responses for AJAX (JSON or partial HTML). +- Implementing autocomplete or dynamic dropdowns. +- Working with `CommonEvents.xml` for JSON responses. + +## Use when +- Updating a list/grid without reloading the entire page (e.g., pagination). +- Submitting a form and updating only the relevant section of the screen. +- Fetching data dynamically for autocompletes. +- Bridging OFBiz backend data with modern frontend frameworks (React/Vue). + +## Procedure +1. **Triggering from Widgets**: + - Use `` inside a `
` or ``. + - **Attributes**: + - `event-type`: `submit` (for buttons), `paginate` (for list navigation), `change` (for input fields). + - `area-id`: The target HTML `id` of the `div` to be replaced. + - `area-target`: The request URI (from `controller.xml`) to execute. +2. **Controller Configuration**: + - **JSON Response**: + ```xml + + + + + + + ``` +4. **Common Events**: Ensure your controller includes the standard JSON event handler (usually inherited or via ``). + - **Partial HTML Response**: + ```xml + + + + + + ``` +3. **Ajax-Specific Screens**: + - Create a screen that only renders the specific widget (form/grid) without the global header/footer. + - Use `` if some layout is still needed, or no decorator for pure fragments. +4. **Passing State**: + - Ensure all necessary parameters (e.g., `exampleId`, `viewIndex`) are passed in the AJAX target request to maintain context. + +## Guardrails +- **ID Collisions**: Ensure `area-id` matches the actual HTML ID rendered on the page. +- **Security**: AJAX requests must still respect `` unless explicitly intended for public access. +- **Error Handling**: Always handle the `error` response in `controller.xml` to prevent silent failures. +- **Performance**: Avoid over-using AJAX for simple transitions; use it where partial updates significantly enhance UX. + +## Examples +**Example: AJAX Pagination for a List** +```xml + + + +``` + +**Example: Auto-saving a field** +```xml + + + + + +``` diff --git a/ai-agent-skills/manage-api-integration/SKILL.md b/ai-agent-skills/manage-api-integration/SKILL.md new file mode 100644 index 000000000..4ef223526 --- /dev/null +++ b/ai-agent-skills/manage-api-integration/SKILL.md @@ -0,0 +1,127 @@ + + +--- +name: manage-api-integration +description: Define and integrate REST and SOAP APIs in OFBiz. +--- + +# Manage API Integration + +Integration patterns for exposing OFBiz services via REST and SOAP, and handling JSON responses. + +## REST API (rest-api plugin) + +OFBiz uses the `rest-api` plugin (based on Jersey) to declaratively expose services. + +### REST API Definitions + +REST endpoints are defined in `*.rest.xml` files located in the `api/` directory of an OFBiz component. These files are automatically discovered and registered by the `rest-api` plugin; no explicit registration in `ofbiz-component.xml` is required. + +**Pattern for `*.rest.xml`:** +```xml + + + + + + + + + + +``` + +### Parameter Handling + +Parameter mapping from REST requests to OFBiz services is **implicit**. The `rest-api` plugin automatically extracts parameters from the request and maps them to service IN parameters whose names match. + +* **Path Parameters:** Extracted from the URI based on placeholders in the `path` attributes (e.g., `{exampleId}`). +* **Query Parameters:** Extracted from the request URL. +* **Request Body:** For `POST`, `PUT`, and `PATCH` requests with `Content-Type: application/json`, the JSON payload is automatically parsed into a map. + +All extracted parameters are aggregated into a single context. The `ServiceRequestHandler` then uses `dispatcher.getDispatchContext().makeValidContext()` to select only those parameters that are defined as IN parameters for the target service. + +### Security and Response Handling +* **Authentication:** Controlled by the `auth="true|false"` attribute on the `` element. +* **Responses:** Services return their OUT parameters (excluding internal ones) as a JSON object. The response is automatically prefixed with `&&&START&&&` for XSSI protection. + +### Core Components +- `OFBizApiConfig.java`: Scans and registers REST definitions. +- `ServiceRequestHandler.java`: Dispatches REST requests to the OFBiz Service Dispatcher. + +## Direct Service REST Export + +OFBiz allows services to be exposed as REST APIs directly via attributes in the service definition. + +### Pattern: +- **Attributes**: Set `export="true"` and `action="VERB"` (e.g., `action="GET"`). +- **Result**: The service becomes reachable as a REST endpoint (e.g., `/rest/public/findProductById` or similar depending on the rest-api plugin configuration). + +```xml + + + +``` + +### Key Considerations: +- **Simplicity**: No need for separate `rest.xml` or controller mappings. +- **Contract-first**: The service signature defines the API request/response. +- **Auth**: Inherits service engine authentication rules. + +## JSON Responses + +For standard controller-based AJAX/API calls, use the `json` response type. + +### Controller Configuration +In `controller.xml`: +```xml + + + + + +``` + +### Response Handling +`CommonEvents.jsonResponseFromRequestAttributes` (or `CommonEvents.jsonResponseFromServiceResults` in some versions) processes the request attributes and writes a JSON object to the response. +- **Security**: A `&&&START&&&` prefix is added to GET responses to prevent JSON hijacking (XSSI). + +## SOAP Integration + +OFBiz provides built-in SOAP support via the `SOAPEventHandler`. + +### Exposing a Service as SOAP +1. Set `export="true"` in the service definition. +2. Ensure the `soap` handler is enabled in `handlers-controller.xml`. +3. Access the WSDL at `https://[host]/[webapp]/control/SOAPService/[ServiceName]?wsdl`. + +### Invoking a Remote SOAP Service +Use the `soap-engine` or `SOAPClientEngine`. +```xml + + + +``` + +## Security & Data Mapping + +- **Authentication**: REST API typically uses JWT or API Keys (configured in `rest-api` common filters). +- **Permissions**: Every service invoked should have proper `permission-service` or `check-permission` logic. +- **Data Mapping**: JSON/XML fields must precisely match service IN attributes for automatic mapping. Use `ServiceUtil.getAndValidateParameters` pattern in custom Java events if manual mapping is needed. diff --git a/ai-agent-skills/manage-async/SKILL.md b/ai-agent-skills/manage-async/SKILL.md new file mode 100644 index 000000000..b907e9460 --- /dev/null +++ b/ai-agent-skills/manage-async/SKILL.md @@ -0,0 +1,83 @@ + + +--- +name: manage-async +description: Manage asynchronous execution, scheduled jobs, and the JobSandbox in OFBiz. +--- + +# Skill: Manage Async Workloads in Apache OFBiz + +## Goal +To properly manage asynchronous execution, scheduled jobs, and the `JobSandbox` in OFBiz, ensuring stability and preventing infinite loops or resource starvation. + +Asynchronous logic in OFBiz can be triggered via `dispatcher.runAsync()`, scheduled Quartz jobs, Service ECAs (`mode="async"`), and the `JobSandbox` recurrences. While powerful, async execution is often misunderstood and can lead to severe system instability if misused. + +## Triggers +- When deciding whether a service or ECA should use `mode="async"` or `mode="sync"`. +- When designing solutions for high-volume background tasks, data imports, or heavy operations. +- When configuring background jobs through the `JobSandbox`. + +## Rules & Procedures + +### 1. Async is CONCURRENT, not "Later" +**Critical Clarification**: Async does not mean "run later". It means "run concurrently". +- Async runs in a separate thread. +- It starts a new transaction. +- It may execute *before* the triggering transaction commits. +- Reads may see no data or partial data. + +*Why this matters*: Agents often falsely assume "Async = safe follow-up after main work". In OFBiz, this assumption is false unless commit boundaries are strictly enforced (e.g., using `event="commit"` in a SECA). + +### 2. Large Data Imports or Batch Workloads +For large data imports or batch workloads: +- **Prefer batching + synchronous execution.** +- Process one record per transaction inside a controlled loop. +- **Avoid** one async service invocation per record. + +## Guardrails + +### 1. Async is NOT a Scalability Strategy at High Volume +Running hundreds or thousands of heavy operations asynchronously does not make them faster. +- Database contention increases. +- Throughput drops and commit times increase. +- The overall system becomes unstable. +- *Rule*: Volume + DB-heavy work β†’ async makes things worse. Avoid choosing async reflexively when you see "heavy" work. + +### 2. Persisted Async Jobs Can DOS Your Own System +A massive number of persisted async operations causes a "JobSandbox explosion". +- **Example**: If processing 500,000 records creates 500,000 persisted async jobs, the `JobSandbox` itself becomes the system bottleneck, not the business logic. +- An agent or junior dev may think `persist="true"` equals "safer". But at scale, DB I/O explodes, and the service engine spends more time managing jobs than executing work. +- **Rule**: Persisted async services must ONLY be used when the job creation rate is ≀ the job consumption rate. + +### 3. Resource Contention Warning +Async services share CPU, memory, threads, and DB connections with synchronous services. +- Excessive async workloads can starve UI and interactive business flows. +- Async usage must be evaluated in the context of the total system workload. + +## Async Decision Checklist +Before choosing an async approach, you must answer **YES** where applicable. If these questions cannot be answered clearly, async is likely the wrong choice: +- [ ] Does this work need to block the user? (If no, async *might* be appropriate, subject to volume). +- [ ] Does it depend on data created in another transaction? +- [ ] What is the expected volume per hour/day? (Volume must be controlled). +- [ ] Can failures be delayed or retried safely? +- [ ] Is batching a better alternative? +- [ ] Should this run only after commit? +- [ ] Does the infrastructure support the async load? + diff --git a/ai-agent-skills/manage-cache-and-performance/SKILL.md b/ai-agent-skills/manage-cache-and-performance/SKILL.md new file mode 100644 index 000000000..39044c6f3 --- /dev/null +++ b/ai-agent-skills/manage-cache-and-performance/SKILL.md @@ -0,0 +1,198 @@ + + +--- +name: manage-cache-and-performance +description: Manage OFBiz caching strategies using UtilCache and Entity Engine caching to optimize application performance. +--- + +# Skill: Manage Cache and Performance + +## Goal +To properly implement and configure caching in OFBiz using `UtilCache` and Entity Engine caching, optimizing performance and reducing database load without introducing memory leaks or stale data. + +## Triggers +- When the user asks to improve database query latency. +- When configuring service ``. +- When designing entity lookups that are frequently read but rarely updated. +- When configuring `cache.properties` for OFBiz system performance. + +## Rules & Procedures + +### 1. Caching with `UtilCache` +`UtilCache` is the primary caching utility in OFBiz. It supports LRU (Least Recently Used) eviction, expiration based on time, and soft references. + +**Pattern: Programmatic Caching** +```java +// Get or create a cache instance +UtilCache myCache = UtilCache.getOrCreateUtilCache("my.custom.cache", 1000, 1000, 3600000, false); + +// Putting a value in cache +myCache.put("myKey", myValue); + +// Retrieving from cache +GenericValue cachedValue = myCache.get("myKey"); + +// Removing from cache +myCache.remove("myKey"); +``` + +### 2. Cache Configuration (`cache.properties`) +Caches are configured in `framework/base/config/cache.properties`. *(See Anti-Pattern 7: Soft References as Primary Strategy)* +```properties +# Set max entries (0 for unlimited) +my.custom.cache.maxSize=5000 + +# Set expire time in milliseconds (e.g., 1 hour = 3600000) +my.custom.cache.expireTime=3600000 + +# Use soft references (allows GC to reclaim memory if needed) +my.custom.cache.useSoftReference=true +``` + +### 3. Entity Engine Caching +OFBiz automatically caches entity lookups if configured. +- **Declarative Caching** in `entitymodel.xml`: + ```xml + + ``` +- **Programmatic Caching (Delegator)**: + ```java + GenericValue val = EntityQuery.use(delegator).from("Product").where("productId", "10000").cache(true).queryOne(); + List list = EntityQuery.use(delegator).from("ProductCategory").cache(true).queryList(); + ``` +*Note: `delegator.findOne(..., true)` hits the shared Entity Engine cache, whereas `UtilCache` is a general-purpose application-level cache.* + +### 4. Service Results Caching +Services can cache their results automatically based on input parameters. +In `services.xml`: +```xml + +``` + +### 5. Cache Key Design Rules +- **Good cache keys**: Have bounded cardinality, are deterministic and repeatable, reflect real reuse patterns. +- **Bad cache keys**: Include timestamps, random values, or high-cardinality identifiers without limits. *(See Anti-Pattern 3: Cache Explosion)* + +### 6. Cache Invalidation Strategy +When external systems or direct SQL modify the database, or when you bypass OFBiz entity triggers, the cache must be cleared manually. +- **Key-based removal** (`myCache.remove(cacheKey);`) is the absolute preferred invalidation approach for granular performance control. +- Use `delegator.clearCacheLine("EntityName")` to clear the entity cache programmatically. +- Use `UtilCache.clearCache("my.custom.cache")` for application caches. + +**Cache invalidation must be triggered by data writes (store/commit), not data reads (find)**. Use EECA (`store`) or SECA (`commit`) to invalidate caches after data is committed. *(See the [manage-eca](../manage-eca/SKILL.md) skill, Good Pattern 1, Anti-Pattern 2, and Anti-Pattern 5).* + +## Guardrails + +### 1. When NOT to Cache +- Frequently updated entities (high write / low read ratio). +- User-specific or session-specific data. *(See Anti-Pattern 4: User/Session Data in Global Cache)* +- Security-sensitive data (permissions, auth state). +- Transaction-dependent data that must reflect real-time DB state. *(See Anti-Pattern 6: Treating Cache as Primary Storage)* +- Data used for financial posting or accounting correctness. + +### 2. Transaction and Async Stale Data Risks +- **Uncommitted Data**: The Entity Engine cache may return uncommitted data within an active transaction. Relying on cache inside a transaction can produce confusing behavior and phantom reads. +- **Async Services**: Async services run concurrently in new transactions. If an async service depends on cached data from the main transaction before it commits, it will see stale data. + +### 3. Distributed Data Services (DDS) +For multi-node setups, ensure cache clearing is synchronized (usually via RMI or JMS in OFBiz). *Assume a single-node setup unless explicitly requested, and do not overly engineer distributed event clearing otherwise.* + +## Examples: Good Patterns vs Anti-Patterns + +### 1. Write-Triggered Invalidation (βœ… GOOD) +```xml + + + + +``` + +### 2. Read-Triggered Invalidation (🚨 ANTI-PATTERN) +```xml + + + + +``` + +### 3. Cache Explosion (🚨 ANTI-PATTERN) +**NEVER** construct cache keys using high-cardinality unbound variables like timestamps or pure UUIDs. +```java +// 🚨 ANTI-PATTERN: Unbounded key cardinality +myCache.put(userId + "_" + orderId + "_" + System.currentTimeMillis(), value); +``` +**Why this is dangerous**: This creates a theoretically infinite number of unique keys. It is a memory leak disguised as a cache. The cache immediately fills up to its `maxSize`, aggressively thrashes via LRU eviction, and consumes massive JVM memory overhead. + +### 4. User/Session Data in Global Cache (🚨 ANTI-PATTERN) +```java +// 🚨 ANTI-PATTERN: Storing user-specific data in a global cache +UtilCache cache = UtilCache.getUtilCache("pricing.cache"); +cache.put(userLoginId, calculatedPrice); +``` +**Why this is dangerous**: +- Data leaks between users. +- Wrong prices / permissions served to the wrong session. +- Memory grows infinitely with the number of users. +- No automatic session cleanup. +**Correct Alternative**: Use `request` scope, `session` attributes, or service context. + +### 5. Caching without Invalidation (🚨 ANTI-PATTERN) +```java +// 🚨 ANTI-PATTERN: Caching without an invalidation strategy +GenericValue product = productCache.get(productId); +if (product == null) { + product = EntityQuery.use(delegator).from("Product").where(key).cache(true).queryOne(); + productCache.put(productId, product); +} +// No invalidation anywhere +``` +**Why this is dangerous**: +- The cache becomes permanently stale. +- The UI shows old values indefinitely. +- Fixes or data updates don't show up until a full system restart. +**Correct Alternative**: Always write an EECA on `store` or a SECA on `commit` to clear the cache when the underlying data changes. + +### 6. Treating Cache as Primary Storage (🚨 ANTI-PATTERN) +```java +// 🚨 ANTI-PATTERN: Treating cache as primary storage +orderCache.put(orderId, orderData); +Order order = orderCache.get(orderId); // DB never consulted +``` +**Why this is dangerous**: +- Data is volatile and will be lost if the server/JVM restarts or memory clears. +- It bypasses database constraints and transactions entirely. +**Correct Alternative**: Always write to the DB first. Use cache strictly to avoid repeated reads. Cache misses MUST fall back to the DB. + +### 7. Soft References as Primary Strategy (🚨 ANTI-PATTERN) +```properties +# 🚨 ANTI-PATTERN: Using soft references to hide memory pressure +my.custom.cache.maxSize=0 +my.custom.cache.useSoftReference=true +``` +**Why this is dangerous**: +- **Unpredictable eviction**: Soft references are cleared only under GC pressure. The cache may work fine for days, then get wiped suddenly during GC. +- **Performance cliffs**: Cache hit ratio collapses instantly. DB load spikes. System appears to β€œrandomly slow down”. +- **Hides real problems**: It masks memory leaks, oversized caches, bad cache keys, or missing invalidation. It delays failures, it doesn’t fix them. +**Correct Alternative βœ…**: Always define `maxSize` and `expireTime`. Use `useSoftReference=true` only as a secondary safety net after sizing correctly. +```properties +# βœ… Correct approach +my.custom.cache.maxSize=5000 +my.custom.cache.expireTime=3600000 +my.custom.cache.useSoftReference=true \ No newline at end of file diff --git a/ai-agent-skills/manage-component/SKILL.md b/ai-agent-skills/manage-component/SKILL.md new file mode 100644 index 000000000..6cf530533 --- /dev/null +++ b/ai-agent-skills/manage-component/SKILL.md @@ -0,0 +1,125 @@ + + +--- +name: manage-component +description: Maintain OFBiz component configuration, dependencies, and resource boundaries. +--- + +# Skill: manage-component +## Goal +Configure and maintain the structure, resources, and dependencies of an OFBiz component (plugin). This includes registering business resources (entities, services, ECAs), defining web applications, and managing inter-component dependencies to ensure classpath and resource availability across the project. + +## Triggers +**ALWAYS** read this skill when: +- Creating a new component or modifying `ofbiz-component.xml`. +- Adding new service, entity, or ECA resource files. +- Managing project dependencies in `build.gradle` or inter-component dependencies. +- Troubleshooting component loading, resource visibility, or classpath issues. + +## Rules & Procedures + +### 1. Resource Registration +Every XML resource must be explicitly registered in `ofbiz-component.xml` to be recognized by the framework. +- **Entities**: `` +- **EECA**: `` +- **Services**: `` +- **SECA**: `` +- **Group Services**: `` +- **Seed/Demo Data**: `` +- **Web Applications**: Register the webapp using ``. + +> [!IMPORTANT] +> **Screens are NOT registered** in `ofbiz-component.xml`. They are referenced directly via URIs or rendered by controllers. + +### 2. Dependency Management +- **Inter-Component**: Use `` in `ofbiz-component.xml`. This ensures that component `xxx` is loaded first and its **classpath and resources** (services, entities) are available to the current component. +- **External Libraries**: **Always prefer Gradle** for dependency management. Add `dependencies { implementation 'group:name:version' }` to `build.gradle`. +- **Legacy Classpath**: Avoid using the `` tag in `ofbiz-component.xml`. OFBiz automatically loads all JAR files located in a component's `/lib` directory. + +### 3. Resource Locations & Properties +- **UI Labels**: Store localized text in `config/[Component]UiLabels.xml`. +- **System Settings**: Store technical/business configurations in `config/[component].properties`. +- **Entity Definitions**: Place in `entitydef/`. +- **Service Definitions**: Place in `servicedef/`. + +## Guardrails +- **URI Enforcement**: **NEVER** use relative paths. ALWAYS use `component://[componentName]/path/to/file` for all resource references across components. +- **Edit Discipline**: Do **NOT** modify `ofbiz-component.xml` unless new resources are actually being introduced. Avoid redundant edits. +- **Circular Dependencies**: Avoid circular `` relationships between components; they lead to unpredictable loading failures. +- **Mount Points**: Ensure a unique `mount-point` for every `` entry to prevent URL collisions. +- **Resource Loaders**: Avoid redefining `` entries unless your component specifically requires a custom implementation. Standard components inherit loaders from core. +- **Registry Completeness**: If it's an entity, service, or ECA XML, it **must** be in `ofbiz-component.xml` or it will not be loaded. + +## Bad Practices & Anti-patterns + +### Anti-pattern: Pathing Traps +**Pitfall**: Hardcoding file system paths or using simple relative paths (e.g., `entitydef/model.xml`). While sometimes working locally, this breaks portability and leads to resource resolution failures in different environments. +- **❌ Bad**: `location="entitydef/model.xml"` +- **βœ… Good**: `location="component://mycomponent/entitydef/model.xml"` + +### Anti-pattern: Redundant Classpath Tagging +**Pitfall**: Explicitly adding `` when JARs in `/lib` are already auto-loaded. This clutters the configuration. +- **❌ Bad**: `` +- **βœ… Good**: Rely on `/lib` auto-loading or use Gradle `dependencies`. + +### Anti-pattern: Mount Point Collisions +**Pitfall**: Defining duplicate `mount-point` values for different `` entries (within the same component or across different components). This causes the web server to fail to start or leads to unpredictable URL routing. +- **❌ Bad (Duplicate Mounts)**: + ```xml + + + ``` +- **βœ… Good (Unique Mounts)**: + ```xml + + + ``` + +--- + +## Common Code Patterns (Examples) + +**Example: Comprehensive ofbiz-component.xml** +```xml + + + + + + + + + + + + + + + + + + + + + + + +``` diff --git a/ai-agent-skills/manage-content/SKILL.md b/ai-agent-skills/manage-content/SKILL.md new file mode 100644 index 000000000..c190cba88 --- /dev/null +++ b/ai-agent-skills/manage-content/SKILL.md @@ -0,0 +1,84 @@ + + +--- +name: manage-content +description: Create and manage OFBiz content data. Use when defining Content, DataResource, or linking content to products/categories. +--- + +# Skill: manage-content +## Goal +Manage the OFBiz Content Management System (CMS) data, including data resources and their associations. + +## Triggers +**ALWAYS** read this skill when: +- Creating content-related data files. +- Linking images, documents, or text to products or orders. +- Troubleshooting content visibility or retrieval issues. + +## Use when +- Creating `DataResource` for files or electronic text. +- Defining `Content` metadata. +- Setting up `ProductContent`, `CategoryContent`, or `OrderContent` associations. + +## Procedure +1. **Define DataResource**: + - The foundational record for actual content (text, URL, or reference to file). + - Fields: `dataResourceId`, `dataResourceTypeId` (e.g., `ELECTRONIC_TEXT`, `LOCAL_FILE`), `dataTemplateTypeId`. +2. **Define Content**: + - The metadata layer over the data resource. + - Fields: `contentId`, `dataResourceId`, `contentTypeId`, `statusId`, `contentName`, `description`. +3. **Link Content (Associations)**: + - Use association entities to link content to business objects. + - Examples: `ProductContent` (links to Product), `ContentAssoc` (links content together). +4. **Electronic Text**: + - For text stored in the database, use `ElectronicText` entity linked to the `DataResource`. + +## Guardrails +- **Naming**: Use clear, descriptive names for `contentId`. +- **Status**: Always set `statusId` (e.g., `CTNT_PUBLISHED`) to ensure visibility if logic filters by status. +- **Paths**: For `LOCAL_FILE`, ensure paths are relative or managed via system properties. + +## Examples +**Example: Product Image Content** +```xml + + + + + + + + + + +``` + +**Example: Electronic Text Content** +```xml + + + + + +``` diff --git a/ai-agent-skills/manage-controller/SKILL.md b/ai-agent-skills/manage-controller/SKILL.md new file mode 100644 index 000000000..033d0167d --- /dev/null +++ b/ai-agent-skills/manage-controller/SKILL.md @@ -0,0 +1,134 @@ + + +--- +name: manage-controller +description: Manage OFBiz Web Controller definitions. Use when defining requests, redirects, and view mappings. +--- + +# Skill: manage-controller +## Goal +Define and maintain request mappings and view definitions within the OFBiz `controller.xml`. + +## Triggers +**ALWAYS** read this skill when: +- Modifying `WEB-INF/controller.xml`. +- Registering a web application in `ofbiz-component.xml`. +- Adding new UI pages (views) or form submission targets (requests). + +## Use when +- Designing URL structures for the web application. +- Mapping requests to Java/Groovy events or OFBiz services. +- Configuring security (HTTPS, Auth) for specific URLs. + +## Procedure +1. **Security & Authentication**: + - Set `uri` to a unique identifier. + - Set `https="true"` for sensitive data. + - Set `auth="true"` to require user login. +2. **Register**: Ensure the webapp is registered in `ofbiz-component.xml`: + ```xml + + ``` +3. **Advanced Request Routing (Events before URIs)**: + - **``**: Runs unconditionally on *every single request* to this webapp before the regular `` logic. Use for global checks, request logging, setting up tenant databases, or enforcing global security rules. + - **``**: Runs only once per user session (on their very first request). Perfect for initializing analytics tracking, setting up an empty shopping cart, or calculating initial geographical settings based on IP. +4. **Request Mapping**: + - Define `` for processing logic. + - **Architectural Decision: Which Event Type to Use?** + - `type="service"`: **Preferred for 90% of requests**. Use this when the request maps directly to a standard OFBiz service (which handles transactions, permissions, and IN/OUT parameter mapping automatically). + - `type="service-multi"`: Use to handle multi-form submissions natively. It extracts tabular POST data (like multiple input rows), loops over them in the framework, and calls a standard single-record service repeatedly. No custom Java/Groovy iteration required. + - `type="groovy"`: Use this for orchestrating multiple services, formatting/pre-processing HTTP Request parameters before calling a service, or writing custom endpoints (like streaming files or returning JSON). + - `type="java"`: **Use sparingly for HTTP Controllers**. Only use this for core framework events (like login/logout, JWT validation, or low-level HTTP session manipulation). Standard business logic belongs in Services, not Java HTTP events. +4. **Response Handling**: + - **`type="view"`**: Use to render a UI page (Screen/Template). This is the final step in a request lifecycle where the response HTML is sent back. Do not use this if you need to run another event first. + - **`type="request"`**: Use for an internal server-side forward to another ``. **Crucial:** Request attributes (like error messages, form data, or queried entities) are kept and passed forward. The browser URL does *not* change. + - **`type="request-redirect"`**: Use for an HTTP 302 Redirect to another ``. The browser URL *does* change. **Crucial:** All request attributes are lost because it's a completely new HTTP request. Form parameters are appended to the URL as query params. Use this after a successful database update (PRG pattern: Post/Redirect/Get) to prevent double-submissions on browser refresh. + - **`type="request-redirect-noparam"`**: Like `request-redirect`, but explicitly strips all form parameters so they are not leaked in the resulting URL's query string. Essential for URLs containing sensitive data (e.g., passwords or tokens) after a form submission. + - **`name="error"` Handling**: Always include a `` to return the user to the input page (with their submitted data intact) if the event fails or throws validation errors. +5. **RESTful APIs, JSON, & AJAX**: + - To build API endpoints or handle AJAX requests, return pure JSON instead of an HTML view. + - Use `` (assuming a global `json` request exists in `common-controller.xml`) to serialize the `requestAttributes` into a JSON response. + - Alternatively, use ``. Use this when the Groovy/Java event explicitly writes to the `HttpServletResponse` output stream (e.g., when generating a custom JSON string or streaming a file download) so OFBiz does not attempt to render a view. +6. **View Definitions**: + - Map the `value` in the response to a ``. + - **`type="screen"`**: **Preferred for UI**. Renders an OFBiz Screen Widget (`page` points to a `component://.../Screens.xml#Name`). + - **`type="json"`**: Used inherently for API responses when returning data (though often handled implicitly by `request` chaining to a global `json` handler rather than an explicit view). + - **`type="url"`**: Direct redirect to an external URL or static asset. Set `page="https://..."` or an absolute server path. + +## Guardrails +- **Naming**: Request URIs should be camelCase (e.g., `updateExample`). +- **Chaining**: Avoid deep request chains; prefer direct redirects (`type="request-redirect"`). +- **Redundancy**: Check for global-requests and global-responses in standard OFBiz controllers to avoid duplication. +- **Event Anti-Pattern**: Do NOT use `type="java"` events to write standard business logic that extracts parameters from the `HttpServletRequest`. That logic belongs in a `Service` (which automatically maps parameters) or a `Groovy` script (if HTTP orchestration is required). +- **View Anti-Pattern**: Do NOT use `type="ftl"` in view-maps for new code. Always route UI rendering through Screen Widgets (`type="screen"`) to maintain consistent decorators, security, and context setup. +- **Security Check**: Be careful with `https="true"`. In modern OFBiz deployments behind an SSL-terminating proxy (like Nginx), setting this can cause infinite 302 redirect loops if `port.https.enabled` is not configured correctly in `url.properties`. +- **CSRF Protection**: For form submissions (POST requests), always ensure the request map is protected or utilizes OFBiz's built-in token mechanisms to prevent Cross-Site Request Forgery. + +## Examples +**Example: Standard Request with Service Event and View Mapping** +```xml + + + + + + + + +``` + +### JSON/AJAX API Endpoint (Standard OFBiz Way) +```xml + + + + + + + +``` + +### Advanced Routing: Preprocessors and Firstvisit +```xml + + + + + + + + + + + + + +``` + +### Custom Response Writing (Streaming or Custom JSON) +```xml + + + + + + + +``` diff --git a/ai-agent-skills/manage-data/SKILL.md b/ai-agent-skills/manage-data/SKILL.md new file mode 100644 index 000000000..82c4359c8 --- /dev/null +++ b/ai-agent-skills/manage-data/SKILL.md @@ -0,0 +1,124 @@ + + +--- +name: manage-data +description: Create and manage OFBiz data files (Entity Engine XML). +--- + +# Skill: manage-data +## Goal +Create and manage OFBiz data files (Entity Engine XML) to populate the database with valid seed, demo, or configuration data. This includes adding mandatory setup records, common type definitions (Seed/Seed-Initial), and optional transactional records for development environments (Demo). + +> [!TIP] +> Use this skill in conjunction with [manage-entities](../manage-entities/SKILL.md) and [manage-component](../manage-component/SKILL.md). + +## Triggers +**ALWAYS** read this skill when: +- Creating or updating XML files intended for data loading. +- Troubleshooting data-related startup errors or foreign key violations. +- Configuring entity data resources in `ofbiz-component.xml`. + +## Rules & Procedures + +### 1. File Structure & Validation +- **Encoding**: ALWAYS use `UTF-8` encoding. +- **Granularity**: Prefer small, logically focused data files (e.g., `ProductPriceData.xml`) over monolithic files for better maintainability. +- **Header**: ALWAYS include the correct XSI schema for IDE validation and framework parsing. +```xml + + + + +``` + +### 2. Data Readers & Loading Order +Data files **must** be registered in `ofbiz-component.xml` using ``. +| Reader | Technical Purpose | Content Type | +| :--- | :--- | :--- | +| `seed` | Mandatory configuration | Enums, StatusItems, UOMs, System Settings. | +| `seed-initial` | Loading during first install | Baseline setup, administrative users. | +| `ext` | External/Custom seed | Plugin-specific configuration data. | +| `demo` | Development/Testing | Orders, Invoices, Shipments, Sample Products. | + +**Loading Order**: Ensure foreign keys are satisfied. If `Product` refers to `ProductType`, the `ProductType` data must be loaded first (or be in the same file earlier). Standard reader sequence: `seed` -> `seed-initial` -> `ext` -> `demo`. + +### 3. Record Definition Patterns +- **Upsert Behavior**: Data loading is an "upsert" (create-or-store). Re-loading a file updates existing records based on Primary Keys. +- **Null Handling**: Omitted attributes are treated as `null`. Attributes with empty quotes (e.g., `attr=""`) are treated as **Empty Strings**. +- **Entity Grouping**: Group related entities using XML comments as headers (e.g., ``) for readability in large files. + +## Guardrails +- **Security**: **NEVER** include sensitive data (PII, actual passwords, PCI data) in seed or demo files. Use standard "ofbiz" hashes for demo users. +- **Entity Verification**: **NEVER** invent entity names. Always verify the entity exists in `entitymodel.xml` before creating data. +- **Unique Primary Keys**: Ensure all records have unique primary keys. For Seed/Ext data, use descriptive string IDs if possible. +- **Ordering**: Define parent entities BEFORE child entities to avoid foreign key violations. Referenced records (e.g., `statusId`) must exist in the same file or earlier seed files. +- **Composite Primary Keys**: Always populate **ALL** primary key fields defined in the model (e.g., `ProductPrice` requires `productId`, `productPriceTypeId`, etc.). +- **Temporal Patterns**: For entities using `fromDate`/`thruDate`, ensure `fromDate` is populated (often part of PK) and date ranges do not overlap for the same logical record. +- **Dates**: Use ISO timestamp: `YYYY-MM-DD HH:MM:SS` (milliseconds are optional and typically not required). +- **ID Generation**: Prefer descriptive/readable IDs for seed/demo data (e.g., `DEMO_STORE`, `PROD_100`) instead of arbitrary numeric sequences. +- **CDATA**: Wrap text containing XML special characters (e.g., descriptions with HTML) in ``. +- **Determinism**: Seed data must be **deterministic and environment independent**. Do not rely on environment-specific system variables. + +## Bad Practices & Anti-patterns + +### Anti-pattern: FK Ordering Trap +**Pitfall**: Defining a child record (like `OrderItem`) before its parent (`OrderHeader`). This triggers immediate loading failures. +- **❌ Bad**: `OrderItem` followed by `OrderHeader`. +- **βœ… Good**: Parent first, then children. Use `dependent-on` in the entity model and ensure referenced records (e.g., `statusId`) exist in the same XML file or in earlier reader files (e.g., `seed` before `demo`). + +### Anti-pattern: Reader Misuse +**Pitfall**: Putting transactional demo data (like Orders) into a `seed` file. This forces bloat into production environments. +- **❌ Bad**: Placing `` in a file registered as `reader-name="seed"`. +- **βœ… Good**: Use `reader-name="demo"` for transactional samples. + +### Anti-pattern: Timestamp Fragility +**Pitfall**: Using non-standard or localized date formats that fail on different server locales. +- **❌ Bad**: `Jan 1 2023 10:00 AM` +- **βœ… Good**: `2023-01-01 10:00:00` + +--- + +## Common Code Patterns (Examples) + +**Example: Comprehensive Seed Data (Types, Products, Relationships)** +```xml + + + + + + + + + + + + + + + + +``` diff --git a/ai-agent-skills/manage-dynamic-view-entities/SKILL.md b/ai-agent-skills/manage-dynamic-view-entities/SKILL.md new file mode 100644 index 000000000..50b3f05b2 --- /dev/null +++ b/ai-agent-skills/manage-dynamic-view-entities/SKILL.md @@ -0,0 +1,220 @@ + + +--- +name: manage-dynamic-view-entities +description: Programmatically build complex queries using the DynamicViewEntity API for runtime query variability. +--- + +# manage-dynamic-view-entities + +Use `DynamicViewEntity` when the join structure, selected aliases, or aggregation must be built at runtime. Prefer explicit aliases, add conditions only for aliases that exist in the dynamic view, and use group-by correctly when aggregate functions are present. + +Programmatically build complex queries using the `DynamicViewEntity` API. This is essential when query structures (joins, aliases) depend on runtime parameters that cannot be statically defined in `entitymodel.xml`. + +## Triggers +- Dynamic search screens with optional joins based on user input. +- Reporting tools that allow selecting arbitrary fields or grouping criteria at runtime. +- Scenarios requiring "self-joins" (aliasing the same entity multiple times). +- Projections or aggregations that vary based on logic. + +## Static vs. Dynamic View Entities + +| Feature | Static View Entity (XML) | Dynamic View Entity (Java/Groovy) | +| :--- | :--- | :--- | +| **Visibility** | Visible in Webtools; pre-parsed; cached | Scoped to logic; minor runtime overhead | +| **Flexibility** | Fixed join structure | Conditional joins/aliases based on input | +| **Reuse** | Highly reusable across services/screens | Ad-hoc, used and thrown away | +| **Preference** | **Primary Choice** for stable/reusable logic | Use only for **actual runtime variability** | + +## Best Practices +- **Resource Scoping**: Keep `DynamicViewEntity` objects within the method scope; they are designed for immediate use. +- **Explicit Aliases**: Prefer explicit `addAlias` calls over `addAliasAll` when joining multiple entities to avoid field name collisions and over-selection. +- **Minimal Joins**: Only join tables strictly necessary for the active logic path. +- **Alias Safety**: Always ensure that `EntityCondition` and `orderBy` clauses reference the **aliases** exposed by the view, not the underlying entity field names. + +## Procedure + +### 1. Initialize DynamicViewEntity +Instantiate the container. + +### 2. Add Member Entities +Use unique aliases for each member. You can add the same entity multiple times with different aliases (Self-Join). + +### 3. Add Aliases (Projections) +Explicitly select fields. Use `addAliasAll` only for the base entity when field overlap is not a concern. + +### 4. Create View Links (Joins) +The `relOptional` (Boolean) argument determines the join type: +- `Boolean.FALSE`: Inner Join (default behavior). +- `Boolean.TRUE`: Left Outer Join (preserves parent rows if related row is missing). + +Use `ModelKeyMap.makeKeyMapList("fieldId")` as a convenience for standard field-to-field mapping. + +### 5. Execute Query +Choose the correct result set handler: +- `queryList()`: For small to medium result sets. +- `queryIterator()`: For large results (streaming). **Must be closed** in a `finally` block or try-with-resources. + +## Guardrails +1. **Alias Safety**: Only reference active aliases in conditions and sorting. Reference by the name exposed in `addAlias`. +2. **Explicit Aliases**: Always prefer explicit aliases over `addAliasAll` when joining multiple entities. +3. **Aggregation Grouping**: When using aggregate functions (sum, count, etc.), every non-aggregated field must have `groupBy="true"`. +4. **Static Preference**: If the query structure is stable and reused, prefer a static `` in XML. +5. **Unique Member Aliases**: Use unique aliases for every member entity, especially for self-joins. +6. **Resource Management**: Always close `EntityListIterator` properly. +7. **No Caching**: Dynamic views are NOT cached by the entity engine. +8. **Distinct**: Use `.distinct()` on `EntityQuery` if your join results in duplicates. +9. **PK Mapping**: Ensure the `ModelKeyMap` accurately reflects the PK/FK relationship. + +## Anti-Patterns +- **❌ Cartesian Products**: Forgetting `addViewLink` between members causes a cross-join. +- **❌ Infinite Joins**: Adding too many member entities leads to massive, unperformant SQL. +- **❌ Dead Conditions**: Applying an `EntityCondition` on an alias that was not added to the `DynamicViewEntity`. +- **❌ Field Overwrites**: Using the same alias name for different fields without unique `name` parameters. + +## Examples + +### Positive Patterns (Good) + +#### 1. Standard Join with Alias Safety and Distinct +Covers: Procedure 1-5, Guardrails 1, 2, 8, 9. +```java +DynamicViewEntity dve = new DynamicViewEntity(); +dve.addMemberEntity("OH", "OrderHeader"); +dve.addMemberEntity("OT", "OrderType"); + +// Join using convenience method and proper PK/FK mapping +dve.addViewLink("OH", "OT", Boolean.FALSE, ModelKeyMap.makeKeyMapList("orderTypeId")); + +// Explicit aliases to avoid over-selection +dve.addAlias("OH", "orderId", "id", null, null, null, null); +dve.addAlias("OT", "description", "orderTypeDesc", null, null, null, null); + +// Condition references exposed ALIAS "id", not "orderId" +EntityCondition cond = EntityCondition.makeCondition("id", "10000"); + +List list = EntityQuery.use(delegator) + .from(dve) + .where(cond) + .distinct(true) + .queryList(); +``` + +#### 2. Conditional Query with Optional Joins +Covers: Guardrail 1 (logic safety) and Procedure 4 (`relOptional`). +```java +if (UtilValidate.isNotEmpty(partyId)) { + // Left Outer Join: Boolean.TRUE + dve.addMemberEntity("BILL_TO", "OrderRole"); + dve.addViewLink("OH", "BILL_TO", Boolean.TRUE, ModelKeyMap.makeKeyMapList("orderId")); + dve.addAlias("BILL_TO", "partyId", "billToPartyId", null, null, null, null); +} + +List conds = new ArrayList<>(); +// Best Practice: Only apply condition if the alias was actually added to the DVE +if (dve.getMemberModelMemberEntities().containsKey("BILL_TO")) { + conds.add(EntityCondition.makeCondition("billToPartyId", partyId)); + conds.add(EntityCondition.makeCondition("roleTypeId", "BILL_TO_CUSTOMER")); +} +``` + +#### 3. Self-Join (Multiple Aliases for Same Entity) +Covers: Guardrail 5 and Procedure 2. +```java +// Join OrderRole twice for different purposes +dve.addMemberEntity("SHIP_TO_ROLE", "OrderRole"); +dve.addMemberEntity("BILL_TO_ROLE", "OrderRole"); + +dve.addViewLink("OH", "SHIP_TO_ROLE", Boolean.FALSE, ModelKeyMap.makeKeyMapList("orderId")); +dve.addViewLink("OH", "BILL_TO_ROLE", Boolean.FALSE, ModelKeyMap.makeKeyMapList("orderId")); + +dve.addAlias("SHIP_TO_ROLE", "partyId", "shipToPartyId", null, null, null, null); +dve.addAlias("BILL_TO_ROLE", "partyId", "billToPartyId", null, null, null, null); +``` + +#### 4. Aggregation and Grouping +Covers: Guardrail 3. +```java +DynamicViewEntity dve = new DynamicViewEntity(); +dve.addMemberEntity("OI", "OrderItem"); + +// Every non-aggregated field MUST have groupBy=true +dve.addAlias("OI", "productId", "productId", null, null, Boolean.TRUE, null); +dve.addAlias("OI", "quantity", "totalQuantity", null, null, null, "sum"); + +List summary = EntityQuery.use(delegator).from(dve).queryList(); +``` + +#### 5. Complex Expressions (ComplexAlias) +```java +import org.apache.ofbiz.entity.model.ModelViewEntity.ComplexAlias; +import org.apache.ofbiz.entity.model.ModelViewEntity.ComplexAliasField; + +ComplexAlias lineTotal = new ComplexAlias("*"); +lineTotal.addComplexAliasMember(new ComplexAliasField("OI", "unitPrice", null, null)); +lineTotal.addComplexAliasMember(new ComplexAliasField("OI", "quantity", null, null)); +dve.addAlias(null, "lineTotal", null, null, null, null, null, lineTotal); +``` + +#### 6. Resource Management (Iterator) +Covers: Guardrail 6 and Procedure 5. +```java +try (EntityListIterator eli = EntityQuery.use(delegator).from(dve).queryIterator()) { + GenericValue value; + while ((value = eli.next()) != null) { + // process streaming results + } +} +``` + +### Negative Patterns (Bad) + +#### ❌ Cartesian Product (Missing Join) +```java +dve.addMemberEntity("OH", "OrderHeader"); +dve.addMemberEntity("OI", "OrderItem"); +// BUG: Missing addViewLink("OH", "OI", ...) causes DB crash on large tables +``` + +#### ❌ Dead Condition (Missing Member) +```java +// CRASH PROBABLE: "productId" alias doesn't exist if someFlag is false +if (someFlag) { + dve.addMemberEntity("OI", "OrderItem"); + dve.addAlias("OI", "productId"); +} +EntityCondition cond = EntityCondition.makeCondition("productId", "foo"); +List list = EntityQuery.use(delegator).from(dve).where(cond).queryList(); +``` + +#### ❌ Infinite Joins (Over-Joining) +```java +// BUG: Joining too many entities (e.g., 10+) leads to timeouts +dve.addMemberEntity("E1", "Table1"); +// ... add 9 more member entities ... +dve.addMemberEntity("E10", "Table10"); +// RECOMMENDATION: Materialize as Database View or break into multiple queries +``` + +#### ❌ Field Overwrite (Duplicate Alias) +```java +dve.addAlias("OH", "statusId"); +dve.addAlias("OT", "statusId"); // Overwrites OH.statusId; OH value becomes inaccessible +``` diff --git a/ai-agent-skills/manage-eca/SKILL.md b/ai-agent-skills/manage-eca/SKILL.md new file mode 100644 index 000000000..e6c2309c8 --- /dev/null +++ b/ai-agent-skills/manage-eca/SKILL.md @@ -0,0 +1,224 @@ + + +--- +name: manage-eca +description: Manage Service Event Condition Actions (SECA) and Entity Event Condition Actions (EECA) to implement event-driven logic in OFBiz. +--- + +# Skill: Manage Service and Entity ECAs (SECA / EECA) in Apache OFBiz + +## Goal +To implement event-driven logic in OFBiz by triggering services automatically when another service reaches a lifecycle event (SECA) or a database entity is modified (EECA). + +ECAs are powerful β€” but misused ECAs are one of the fastest ways to destabilize a production OFBiz system. + +> **Core Principle**: If removing the ECA breaks the main business flow, it should **NOT** be an ECA. + +## Triggers +- Implementing cross-cutting concerns (e.g., clearing caches, indexing). +- Triggering side effects (e.g., sending emails after order completion). +- Enforcing business rules that depend on data changes. +- Syncing data between different systems or components. + +## Rules & Procedures + +### Decision Tree: SECA vs EECA vs Explicit Chaining + +**Step 1: Is this logic part of the main business flow?** +Examples: "Order approval must reserve inventory", "Shipment creation must validate allocation", "Invoice must be generated or order is invalid". +- **YES** β†’ **Explicit chaining / orchestrator service** + - (Call the next service directly, or create a wrapper service like `processOrderApproval` that orchestrates steps using **Groovy** (**Cross-Reference**: `manage-groovy`) or **Service Groups** (**Cross-Reference**: `manage-service-groups`).) +- **NO** β†’ Go to Step 2 +*Rule: If removing it breaks the flow, it’s not an ECA.* + +**Step 2: What is the trigger source you truly want?** +Ask: "What event should cause this to happen?" +- **2A) Trigger is a service lifecycle event** + - Example: "After `storeOrder` completes, send an email", "After `createShipment` commits, push to ERP". + - **Choose SECA** + - Then go to Step 3 (event + mode) +- **2B) Trigger is a database row change** + - Example: "Whenever Product changes, reindex", "When OrderHeader.statusId becomes COMPLETED, notify". + - **Choose EECA** (only on physical entities) + - Then go to Step 3 (event + mode) +- *If neither is clear β†’ prefer explicit chaining (more traceable).* + +**Step 3: Does the triggered work need committed DB state?** +Ask: "Will the triggered service read data written by the triggering work?" +- **YES** β†’ Use post-commit trigger + - **SECA**: `event="commit"` + - **EECA**: prefer `event="return"` but ensure the consuming logic doesn’t require uncommitted visibility; if it must read committed state reliably, prefer SECA on commit of the creating/updating service (or pass required data directly). +- **NO** β†’ `return` is usually fine + - (SECA: `event="return"`, EECA: `event="return"`) +*Key: async is concurrent; commit matters when reads must see written data.* + +**Step 4: Is the action heavy / slow / failure-tolerant?** +Examples: external API call, email, indexing, analytics. +- **YES** β†’ `mode="async"` + - Use `persist="true"` only when job volume is controlled and reliability is required. + - *(See the [manage-async](../manage-async/SKILL.md) skill before choosing `mode="async"`!)* +- **NO** β†’ `mode="sync"` (keep it lightweight and deterministic) + +### Quick Rules of Thumb + +**Use Explicit Chaining when:** +- It’s core workflow logic +- Ordering matters strongly across multiple steps +- You need clear traceability and testing +- You want retries/compensation explicitly + +**Use SECA when:** +- Trigger is "after service X" +- You want to extend behavior without changing service code +- You can pick `return` vs `commit` intentionally + +**Use EECA when:** +- Trigger is "when entity row changes" +- You need cross-cutting reaction to DB writes from multiple entry points +- You can write precise conditions +- You are not targeting view entities and not using `find` + +### Implementation Procedures + +#### 1. Service ECAs (SECAs) +SECAs trigger a service when another service reaches a specific life-cycle event. + +- **Location**: Typically defined in `secas.xml` files within a component's `servicedef` directory. +- **Registration**: Register the SECA file in `ofbiz-component.xml`: + ```xml + + ``` + +#### SECA Pattern +```xml + + + + + + +``` + +#### Event Selection Rules +- **return**: Business logic completed, transaction not yet committed (most common). +- **commit**: Use ONLY when the triggered service must see committed data. +- **invoke**: Avoid "invoke" unless modifying input context is required. +- `auth`: Before authentication. +- `in-validate`: Before input validation. +- `out-validate`: Before output validation. + +--- + +#### 2. Entity ECAs (EECAs) +EECAs trigger a service when a database operation occurs on a specific entity. + +- **Location**: Typically defined in `eecas.xml` files within a component's `entitydef` directory. +- **Registration**: Register the EECA file in `ofbiz-component.xml`: + ```xml + + ``` + +#### EECA Pattern +```xml + + + + +``` + +#### Critical Constraints +- NEVER attach EECA to view entities. +- Avoid `operation="find"` (high performance risk). +- βœ” Prefer `store` + condition over `status-change` when possible. + +#### Event Rules +- **run**: Before DB operation (rare). +- **return**: After DB operation (most common). +- **status-change**: Use ONLY for explicit status-driven logic. + +**Common Operations**: `create`, `store` (update), `remove`. + +--- + +## Guardrails +- **Avoid Recursion**: Be extremely careful not to trigger a SECA/EECA that eventually calls the original service/entity operation, leading to an infinite loop (see Examples). +- **Transactional Impact**: Synchronous (`mode="sync"`) actions run in the same transaction. If the action fails, the main operation fails. +- **Condition Precision**: Always use conditions to ensure the action only triggers when strictly necessary. +- **Async Execution Warning**: Before configuring `mode="async"`, you **MUST** review the explicit rules in the `manage-async` skill to prevent JobSandbox explosions and system instability. + +## Examples: Good Patterns vs Anti-Patterns + +### 1. Order Completion SECA (Good Pattern for Live Traffic) +Triggering an email and resetting totals after an order is stored. +```xml + + + + + +``` +**Why this is good (for live traffic)**: It decouples the heavy network call (email) from the transaction, avoiding blocking the user during checkout. + +**ANTI-PATTERN: Leaving this enabled for bulk historical imports.** +This async + persist strategy is **WRONG** if: +- You are **bulk-importing historical orders** (JobSandbox explosion). +- The email must be sent **before** order completion is considered successful. +- The service modifies `OrderHeader` again (leading to transaction timing collisions). +- You are firing this for **every minor order update** (missing `` guard). + +### 2. Infinite Loop Recursion (EECA ANTI-PATTERN) +**NEVER** trigger an action that updates the exact same entity that triggered it, unless guarded by iron-clad status conditions. +```xml + + + +``` +**Why this is dangerous**: When `recomputeOrderHeader` executes, it internally stores ``. Because the operation is `store`, the EECA immediately fires a *second* time. This creates an infinite loop that instantly crashes the transaction thread. + +### 3. View Entity trigger (EECA ANTI-PATTERN) +**NEVER** attach an EECA to a View Entity. +```xml + + + + +``` +**Why this is wrong**: View Entities are virtual joins. The OFBiz Entity Engine does not fire database events (`create`, `store`, `remove`) on viewsβ€”it fires them on the underlying physical tables. An EECA on a View Entity will either never trigger, or will trigger inconsistently and cause deep system confusion. + +### 4. Find Operation (EECA ANTI-PATTERN) +**NEVER** attach an EECA to a `find` operation unless absolutely unavoidable and closely monitored. +```xml + + + + +``` +**Why this is dangerous**: Find operations are executed continuously by the system (UI lookups, internal service logic, batch processing). Intercepting every `find` operation on a core entity like `Product` adds massive latency to the system and will destroy database throughput. + +### 5. Product Keyword Indexing EECA +Automatically indexing keywords whenever a Product is created or updated. +```xml + + + + + + +``` diff --git a/ai-agent-skills/manage-email-services/SKILL.md b/ai-agent-skills/manage-email-services/SKILL.md new file mode 100644 index 000000000..b979e2a59 --- /dev/null +++ b/ai-agent-skills/manage-email-services/SKILL.md @@ -0,0 +1,223 @@ + + +--- +name: manage-email-services +description: Configure and implement email services in OFBiz. +--- + +# Skill: manage-email-services + +## Goal +Configure SMTP infrastructure and implement reliable, template-driven business notifications using OFBiz Screen Widgets, FreeMarker templates, and CommunicationEvent records. + +## Triggers +**ALWAYS** read this skill when: +- Creating new email notifications or modifying existing ones. +- Configuring SMTP settings in `general.properties`. +- Managing `ProductStoreEmailSetting` or `EmailTemplateSetting` entities. + +## Use when +- Sending automated business notifications. +- Designing email templates with consistent branding. +- Attaching PDF documents (e.g., invoices) to emails. + +## Procedure + +1. **SMTP Configuration**: + - Configure `framework/common/config/general.properties`: + ```properties + mail.notifications.enabled=Y + mail.smtp.relay.host=smtp.example.com + mail.smtp.port=465 + mail.smtp.auth=true + mail.smtp.auth.user=user@example.com + mail.smtp.auth.password=password + mail.smtp.starttls.enable=Y + mail.smtp.ssl.enable=true + ``` + - **Note**: `mail.smtp.starttls.enable` often requires `Y` in OFBiz, while other boolean flags use `true`. + - Use `mail.notifications.redirectTo` in development to intercept all outgoing mail. + +2. **Template Definition**: + - **Commerce Emails**: Prefer **`ProductStoreEmailSetting`** for order-to-cash flows. + - Examples: Order confirmations, Shipment notifications, Return confirmations. + - **System Emails**: Use **`EmailTemplateSetting`** for generic/administrative alerts. + - Examples: Password reset, User invitations, Administrative alerts. + - **Full Compatibility**: Use `altBodyScreenLocation` to provide a plain-text fallback for HTML emails. + - Example XML Data: + ```xml + + ``` + +3. **Store & WebSite Mapping**: + - `ProductStoreEmailSetting` relies on the **`WebSite`** entity (via `productStoreId`) to determine the base URL for links. + - Ensure your `WebSite` has `standardHostName` and `secureHostName` configured to avoid broken links in emails. + +4. **Screen Design**: + - Create a screen in your component's `widget/EmailScreens.xml`. + - Ensure all links and images use **absolute URLs**. + - **Pro-Tip**: Use `NotificationServices.setBaseUrl(delegator, webSiteId, bodyParameters)` in your logic before sending to populate `${baseUrl}` in FTL. + +5. **Service Invocation**: + - Use `sendMailFromScreen` for granular control and PDF attachments. + - Use `sendMailFromTemplateSetting` for simple entity-driven sending. + - **ALWAYS** use `runAsync` (asynchronous) for production mailing to prevent thread blocking. + +6. **Handling Attachments**: + - **PDF Generation**: Use `xslfoAttachScreenLocation` to render a Screen Widget as a PDF using Apache FOP. + - **General Files**: Use the `bodyParts` parameter (list of Maps) to attach existing files. + +7. **Bulk and High-Volume Mailing**: + - For high-volume notifications (e.g., shipment updates), use **Job Queuing**. + - **Pattern**: Iterate through your targets and schedule the mailing service via `dispatcher.schedule`. + - **NEVER** send thousands of emails in a single service execution or a single DB transaction. + +## CommunicationEvent Lifecycle + +In OFBiz, emails are not just "logged"β€”they are managed as **Communication Events**. This is a core architectural pattern that ensures every outbound email has a central source of truth. + +### Why it Matters +- **Customer Service Visibility**: Agents can see exactly what was sent to a customer from any module (Order, Marketing, SFA). +- **Business Audit Trail**: Emails are linked to business documents (e.g., `OrderHeader`) via `CommunicationEventOrder`. +- **Interaction History**: Provides a complete timeline of customer touchpoints. +- **Compliance**: Ensures legal and support records are archived within the database, not just on a mail server. + +### The Lifecycle Pattern +1. **Creation**: A service (e.g., `sendOrderNotificationScreen`) invokes `sendMailFromScreen`. +2. **Persistence**: The `sendMail` service family includes SECA (Service ECA) triggers that automatically create a `CommunicationEvent` record. +3. **Linkage**: The `communicationEventId` is then linked to the relevant business object (e.g., `OrderHeader`, `Shipment`, or `ContactList`). + +## Attachments and PDF Generation + +OFBiz excels at generating and attaching documents like **Invoices, Packing Slips, and Return Labels** directly within the mail services. + +### The PDF Pattern (`xslfoAttachScreenLocation`) +This is the most common pattern for business documents. You provide a screen location, and the service renders it as a PDF attachment. + +- **Service**: `sendMailFromScreen` +- **Parameter**: `xslfoAttachScreenLocation` (e.g., `component://accounting/widget/InvoiceScreens.xml#InvoicePDF`) +- **Expert Guidance**: For designing XSL-FO templates and report screens, refer to the [manage-pdf-export](../manage-pdf-export/SKILL.md) skill. +- **Attachment Name**: Pass `attachmentName` to set the filename (e.g., `Invoice_10000.pdf`). + +### Multi-part Pattern (`bodyParts`) +For non-PDF attachments (e.g., CSVs, images) or multiple files, use `sendMailMultiPart`. +- **Parameter**: `bodyParts` (A `List` of `Map` objects containing `content`, `type`, and `filename`). + +## Guardrails + +- **Transactional Integrity**: **CRITICAL.** Commit business transactions *before* triggering emails. Use `runAsync` or After-Commit SECAs to prevent SMTP hangs from impacting DB locks. +- **Fault Tolerance**: SMTP failures must **NEVER** break the main user workflow. Log errors, update `CommunicationEvent` status, but ensure primary actions succeed. +- **Modern Security**: Externalize secrets (Env vars/Vaults). Avoid plain-text passwords in `general.properties`. +- **Absolute Continuity**: Always provide plain-text fallbacks (`altBodyScreenLocation`) and pass `webSiteId` for correct absolute URL resolution. +- **Pattern Compliance**: **ALWAYS** create and link `CommunicationEvent` records for auditability and customer history. +- **Environment Safety**: Verify `mail.notifications.redirectTo` is set in dev/test. + +## Examples + +### Example: Custom Email Screen +```xml + +
+ + + + + + + + +
+
+``` + +### Example: Sending via Template (Groovy) +```groovy +// Sending an order confirmation asynchronously +run service: 'sendMailFromTemplateSetting', with: [ + emailTemplateSettingId: 'PRDS_ODR_CONFIRM', + sendTo: 'customer@example.com', + bodyParameters: [orderId: '10000', webSiteId: 'MyStore'] +] +``` + +### Example: Sending an Invoice PDF (Groovy) +```groovy +// Sending an invoice as a PDF attachment asynchronously +run service: 'sendMailFromScreen', with: [ + emailTemplateSettingId: 'INVOICE_NOTIFY', + sendTo: 'customer@example.com', + bodyParameters: [invoiceId: '10000'], + xslfoAttachScreenLocation: 'component://accounting/widget/InvoiceScreens.xml#InvoicePDF', + attachmentName: 'Invoice_10000.pdf' +] +``` + +### Example: Audit Trail Linking (Groovy) +```groovy +// Step 1: Send the email as usual +Map result = run service: 'sendMailFromScreen', with: [ + emailTemplateSettingId: 'PRDS_ODR_CONFIRM', + sendTo: 'customer@example.com', + bodyParameters: [orderId: '10000'] +] + +// Step 2: The service automatically creates a CommunicationEvent. +// Step 3: Link it to your business document for visibility. +String commEventId = result.communicationEventId; +run service: 'createCommunicationEventOrder', with: [ + communicationEventId: commEventId, + orderId: '10000' +] +``` + +## Anti-Patterns + +### 1. Synchronous Mailing in Transactions +**BAD**: If SMTP hangs, the order creation fails or hangs indefinitely. +```groovy +// Inside createOrder service +run service: 'createOrder', with: parameters +// ANTI-PATTERN: Sending synchronously inside the transaction +run service: 'sendOrderConfirmation', with: parameters +``` +**GOOD**: Decouple delivery from business logic. +```groovy +// Inside createOrder service +run service: 'createOrder', with: parameters +// Success: Return to caller. SECA or Post-Commit logic handles the email. +run service: 'sendOrderConfirmation', as: 'async', with: parameters +``` + +### 2. Relative URLs in Templates +**BAD**: Images won't load in Gmail/Outlook. +```html + +``` +**GOOD**: Use absolute URLs (e.g., `https://example.com/images/company-logo.png`). + +### 3. Hardcoding HTML in Java +**BAD**: Frustrating to maintain and style. +```java +String body = "

Hello " + name + "

"; // ANTI-PATTERN +``` +**GOOD**: Use Screen Widgets and FreeMarker templates. diff --git a/ai-agent-skills/manage-entities/SKILL.md b/ai-agent-skills/manage-entities/SKILL.md new file mode 100644 index 000000000..76464e8c2 --- /dev/null +++ b/ai-agent-skills/manage-entities/SKILL.md @@ -0,0 +1,218 @@ + + +--- +name: manage-entities +description: Manage OFBiz entity definitions (Data Model). Use when creating/modifying entities, debugging DB errors, or adding views. +--- + +# Skill: manage-entities +## Goal +Define and maintain the OFBiz Data Model using XML entity definitions. This includes creating new database tables (entities), defining joins (view-entities), adding indexes, and extending core framework entities to support custom business requirements safely. + +> [!TIP] +> Use this skill in conjunction with [manage-data](../manage-data/SKILL.md) and [manage-component](../manage-component/SKILL.md). + +## Triggers +**ALWAYS** read this skill when: +- Creating or modifying `servicedef/entitymodel.xml` (entities) or `servicedef/entitymodel_view.xml` (views). +- Extending core OFBiz entities using ``. +- Troubleshooting database sync errors, foreign key violations, or SQL performance issues. +- Designing complex data relationships and aggregations. + +## Rules & Procedures + +### 1. Entity Definition +- **Location**: Defined in `entitydef/entitymodel.xml`. +- **Requirements**: Always include a descriptive `title` and a `package-name` (e.g., `org.apache.ofbiz.order`). +- **Primary Keys**: Every entity MUST have at least one ``. +- **Optimistic Locking**: Use `enable-lock="true"` for entities with high concurrency (e.g., `OrderHeader`, `Shipment`). +- **Dependent Ordering**: Use `dependent-on="[EntityName]"` to ensure correct load and delete ordering for related entities. + +### 2. Field Types & Constraints +- **Standard Types**: Use standard OFBiz field types defined in `fieldtypemodel.xml` to ensure database independence: + - `id`: For primary/foreign keys (usually VARCHAR(20)). + - `id-long`: For longer IDs. + - `name`: For short names/labels. + - `description`: For longer descriptive text. + - `currency-amount`: For financial values (fixed precision). + - `date-time`: For full timestamps. + - `indicator`: For boolean-style flags ('Y' or 'N'). +- **Sequencing**: Primary keys of type `id` or `id-long` are typically generated via the OFBiz Sequencer. +- **Default Values**: Use `default-value="..."` for fields that should auto-initialize (e.g., `statusId="ACTIVE"`). +- **Hard Constraints**: Use `not-null="true"` for mandatory database-level fields. + +### 3. Relationships & Foreign Keys +- **type="one"**: Represents a **Database Foreign Key** constraint. Target must exist. + - Syntax: `` +- **type="one-nofk"**: Logical relationship without a physical database constraint. Use when target might be missing or managed externally. +- **type="many"**: Represents a **Logical Relationship** for navigation (no database FK created). + - Syntax: `` +- **Naming**: Use a consistent naming convention for `fk-name` (e.g., `[EntityShort]_[FieldShort]`). Use `title` if multiple links to the same entity exist. +- **Entity Verification**: **ALWAYS** use the `entity-name` (as defined in `entitymodel.xml`), NOT the physical database table name, for `rel-entity-name`. +- **Keys**: Ensure all primary key fields of the related entity are mapped in the ``. + +### 4. Registration +Every entity and view-entity resource MUST be registered in `ofbiz-component.xml`: +```xml + +``` + +### 5. View Entities (Joins & Functions) +- **Goal**: Define database joins and aggregations directly in XML. +- **Alias Strategy**: Use `` for convenience, but define explicit `` entries when joining entities with overlapping fields. +- **Join Direction**: Usually defined from the **Child** (containing FK) to the **Parent** (containing PK). +- **Conditions**: Use `` and `` for pre-filtered views (e.g., only active records). +- **Functions**: Use `function="..."` (e.g., `sum`, `count`) and `group-by="true"` for aggregations. + +### 6. Entity Extensions +- **Strategy**: NEVER modify framework entities directly. Use ``. +- **Namespacing**: **ALWAYS** prefix custom fields (e.g., `extField` or `customField`) to avoid naming collisions with future framework updates. + +### 7. Temporal Data & History +- **Effective Dates**: Always use `fromDate` (often part of Primary Key) and `thruDate` to manage history. +- **Audit Fields**: OFBiz automatically adds `createdStamp` and `lastUpdatedStamp`. Don't define these manually. + +### 8. Indexes +- **Rule**: Add indexes for fields frequently used in search/joins (e.g., `partyId`, `statusId`) if they aren't part of a PK. +- **When to Avoid**: Do not index low cardinality fields (unless part of a composite index) or high-write tables where overhead is costly. +- **Judicious Use**: Avoid redundant indexes on PKs. Don't add indexes during initial design; wait for query performance patterns. + +### 9. Status View Entities +- **Join**: Always join with `StatusItem` on `statusId`. +- **Aliasing**: Alias `StatusItem.description` to `statusDescription` to avoid name collisions. + +## Guardrails +- **Naming**: Use **CamelCase** for entities and fields (e.g., `ProductPrice`, `productId`). +- **Check Existing**: **ALWAYS** check existing entity definitions (via `entitymodel.xml` or WebTools Entity Engine) before creating new entities to avoid duplication. +- **Complexity**: Avoid view-entities with more than **5-6 joins**. If complexity grows, consider service-level logic. +- **Audit**: Enable `enable-audit-log="true"` for sensitive PII or financial fields. +- **Integrity**: Parental entities MUST exist before children (both in data load and relation definition). +- **Cache**: Use `useCache=true` in find operations for static data (Types, Enums) to boost performance. + +## Bad Practices & Anti-patterns + +### Anti-pattern: Snake_Case Fields +- **❌ Bad**: `` +- **βœ… Good**: `` (OFBiz standard is CamelCase). + +### Anti-pattern: Missing Namespacing in Extensions +- **❌ Bad**: Extending `Product` with a field named `internalId` (high collision risk). +- **βœ… Good**: Use `extInternalId` or `customInternalId`. + +### Anti-pattern: Over-Indexing +- **❌ Bad**: Creating an index on every field "just in case." This kills `INSERT`/`UPDATE` performance. +- **βœ… Good**: Index only after identifying performance bottlenecks. + +### Anti-pattern: Physical Table Name Reference +- **❌ Bad**: Using `rel-entity-name="product_price"` or table names in code. +- **βœ… Good**: ALWAYS use the entity name: `rel-entity-name="ProductPrice"`. + +### Anti-pattern: Missing Primary Key +- **❌ Bad**: Defining an entity without a ``. This causes persistent caching and loading errors. +- **βœ… Good**: Every entity MUST have at least one primary key field. + +### Anti-pattern: Hardcoded/Nondescript FK Names +- **❌ Bad**: ``. +- **βœ… Good**: Use a descriptive name: ``. + +### Anti-pattern: Hardcoding IDs +- **❌ Bad**: Literal strings like "COMPLETED" in code. +- **βœ… Good**: Use `Enumeration` or `StatusItem` and refer to constant IDs. + +### Anti-pattern: Business Logic in Entity Definitions +- **❌ Bad**: Adding calculation or validation logic in the entity model. +- **βœ… Good**: Entities should be pure data structures; logic belongs in Services. + +### Anti-pattern: Redundant Fields +- **❌ Bad**: Duplicating data that can be retrieved via a join. +- **βœ… Good**: Keep data normalized unless strictly required for a performance optimization. + +### Anti-pattern: Circular View Entities +- **❌ Bad**: View A joins View B, which joins View A. +- **βœ… Good**: Maintain a strict hierarchy; avoid cycles which cause stack overflows during initialization. + +## Common Code Patterns (Examples) + +**Example: Standard Entity with Constraints & Locking** +```xml + + + + + + + + + + +``` + +**Example: Filtered View Entity (with Conditions)** +```xml + + + + + + + + + + + + +``` + +**Example: Status View Entity (Aliasing Pattern)** +```xml + + + + + + + + + +``` + +**Example: Advanced View Entity with Aggregation** +```xml + + + + + + + + + + + +``` + +**Example: Entity Extension with Namespacing** +```xml + + + + +``` + diff --git a/ai-agent-skills/manage-forms/SKILL.md b/ai-agent-skills/manage-forms/SKILL.md new file mode 100644 index 000000000..2059ba759 --- /dev/null +++ b/ai-agent-skills/manage-forms/SKILL.md @@ -0,0 +1,120 @@ + + +--- +name: manage-forms +description: Define and maintain Form and Grid widgets using the OFBiz Form Widget XML. +--- + +# Skill: manage-forms +## Goal +Define and maintain data input forms and data display grids using the OFBiz Form Widget XML. + +## Triggers +**ALWAYS** read this skill when: +- Creating or modifying XML files in `widget/` directory (e.g., `*Forms.xml`). +- Registering form resources in `ofbiz-component.xml`. +- Defining new forms/grids or extending existing ones. + +## Use when +- Creating single-record update forms or multi-record list grids. +- Implementing AJAX-based UI updates using `on-event-update-area`. +- Reusing form structures via component inheritance. + +## Procedure +1. **Inheritance & Reuse**: + - Use `extends="..."` to inherit fields from another form. + - Use `extends-resource="..."` to specify the location of the parent form. +2. **Form Types**: + - `single`: For single record input/edit. + - `list` or `grid`: For multiple records. Use `grid` (modern) over `form type="list"`. +3. **Register**: Ensure the widget XML is registered in `ofbiz-component.xml`: + ```xml + + ``` +3. **Data Binding**: + - Use `auto-fields-service` or `auto-fields-entity` to generate fields automatically. + - Use `` within the grid to perform complex finds (e.g., calling `performFind` service). +4. **AJAX & Events**: + - Use `` for partial page updates. +5. **Field Elements (Advanced)**: + - **Drop-downs**: Use ``. + - **Lookups**: Use ``. + - **Displays**: Use ``. + - **Actions**: Use `` for navigation and `` for form submission. +6. **Styling**: + - Use `odd-row-style`, `header-row-style`, and `default-table-style` for grids. + - Use `alt-row-style` for row-level conditional styling. +7. **Autocompleters**: + - Use `` for standard autocompleting lookups. + - For multi-select autocompleters, use `` with `asmselect` CSS class if available in theme. +8. **Pagination**: + - Use `paginate-target` on `` to specify the request for fetching next pages. + - Set `view-size` to control items per page. + - Use `` for AJAX pagination. + +## Guardrails +- **Naming**: Form names should be PascalCase (e.g., `EditExample`). +- **Separation**: Keep labels in UI label files, referenced via `${uiLabelMap.LabelName}`. +- **DTD Compliance**: Ensure compliance with `widget-form.xsd`. +- **Targeting**: Specify the `target` attribute for forms to define the submission request. + +## Examples +**Example: Grid with Service Search and AJAX Pagination** +```xml + + + + + + + + + + + + + + + + +``` + +**Example: AJAX Autocompleter (Dependent Drop-down)** +```xml + + + + + + + + + + + + + + + + + + +``` + diff --git a/ai-agent-skills/manage-groovy/SKILL.md b/ai-agent-skills/manage-groovy/SKILL.md new file mode 100644 index 000000000..474d082fe --- /dev/null +++ b/ai-agent-skills/manage-groovy/SKILL.md @@ -0,0 +1,226 @@ + + +--- +name: manage-groovy +description: | + Write Groovy logic for OFBiz services and scripts. Use when + - Writing business logic for OFBiz services using Groovy. + - Creating UI/API data preparation scripts for Screen Widgets. + - Implementing modern entity logic using Groovy DSL. +--- + +## Goal +Implement business logic, complex data transformations, and data preparation scripts in Groovy using modern OFBiz DSL patterns. + +## Triggers +**ALWAYS** read this skill when: +- Creating or modifying `.groovy` files. +- Implementing core business logic for services with `engine="groovy"`. +- Preparing data for screens via `