|
| 1 | +# ObjectStack Plugin Standards (OPS) |
| 2 | + |
| 3 | +To facilitate **AI-Driven Development** and Human Code Review, all plugins in the ecosystem generally follow the "ObjectStack Plugin Standard" (OPS). |
| 4 | + |
| 5 | +> **🎯 Goal:** Ensure an AI agent can instantly understand the project structure and know exactly where to create or modify files without searching. |
| 6 | +
|
| 7 | +--- |
| 8 | + |
| 9 | +## 1. Directory Structure: "Domain-First" |
| 10 | + |
| 11 | +We recommend organizing code by **Business Domain (Module)** rather than technical file type. This keeps related logic (Schema, UI, Automation) co-located, fitting neatly into an AI's context window. |
| 12 | + |
| 13 | +### Recommended Layout |
| 14 | + |
| 15 | +```text |
| 16 | +my-plugin/ |
| 17 | +├── package.json |
| 18 | +├── objectstack.config.ts # Plugin Entry Point |
| 19 | +├── src/ |
| 20 | +│ ├── main.ts # Logic Entry (Exports) |
| 21 | +│ │ |
| 22 | +│ └── [module-name]/ # e.g., "project-management" |
| 23 | +│ ├── [object].object.ts # Database Schema |
| 24 | +│ ├── [object].trigger.ts # Backend Logic Hook |
| 25 | +│ ├── [object].client.ts # Frontend Logic |
| 26 | +│ ├── [object].view.ts # UI Layouts (Grid, Forms) |
| 27 | +│ ├── [object].action.ts # Custom Buttons/Actions |
| 28 | +│ ├── [process].flow.ts # Automation Flows |
| 29 | +│ └── permissions.ts # Module-specific permissions |
| 30 | +``` |
| 31 | + |
| 32 | +### Example: CRM Plugin |
| 33 | + |
| 34 | +```text |
| 35 | +plugins/crm/ |
| 36 | +├── package.json |
| 37 | +├── src/ |
| 38 | +│ ├── leads/ |
| 39 | +│ │ ├── lead.object.ts # "lead" Object definition |
| 40 | +│ │ ├── lead.trigger.ts # "beforeInsert" logic |
| 41 | +│ │ └── lead.view.ts # "All Leads" grid view |
| 42 | +│ │ |
| 43 | +│ ├── sales/ |
| 44 | +│ │ ├── opportunity.object.ts |
| 45 | +│ │ ├── opportunity.view.ts |
| 46 | +│ │ └── quote.object.ts |
| 47 | +│ │ |
| 48 | +│ └── analytics/ |
| 49 | +│ └── sales-dashboard.dashboard.ts |
| 50 | +``` |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +## 2. File Naming Conventions |
| 55 | + |
| 56 | +We use **Semantic Suffixes** to tell the AI exactly what a file contains. |
| 57 | +Format: `snake_case_name.SUFIX.ts` |
| 58 | + |
| 59 | +| Suffix | Purpose | Content Type | |
| 60 | +| :--- | :--- | :--- | |
| 61 | +| `*.object.ts` | **Data Schema** | `Data.ObjectSchema` (Zod) | |
| 62 | +| `*.field.ts` | **Field Extensions** | `Data.FieldSchema` | |
| 63 | +| `*.trigger.ts` | **Backend Logic** | Function Hooks (Before/After) | |
| 64 | +| `*.app.ts` | **App Definition** | `UI.AppSchema` (Navigation) | |
| 65 | +| `*.view.ts` | **UI Views** | `UI.ViewSchema` (Grid/Form) | |
| 66 | +| `*.page.ts` | **Custom UI** | `UI.PageSchema` | |
| 67 | +| `*.dashboard.ts` | **Analytics** | `UI.DashboardSchema` | |
| 68 | +| `*.flow.ts` | **Automation** | `Automation.FlowSchema` | |
| 69 | +| `*.router.ts` | **Custom API** | Express/Router definitions | |
| 70 | + |
| 71 | +--- |
| 72 | + |
| 73 | +## 3. Implementation Rules for AI |
| 74 | + |
| 75 | +### Rule #1: One Thing Per File |
| 76 | +Ideally, define **one primary resource per file**. |
| 77 | +* ✅ `lead.object.ts` exports `LeadObject`. |
| 78 | +* ❌ `crm.ts` exports `LeadObject`, `ContactObject`, and `DealObject`. |
| 79 | + |
| 80 | +*Why? It prevents huge files that get truncacted in AI context, and makes file-search reliable.* |
| 81 | + |
| 82 | +### Rule #2: Explicit Typing |
| 83 | +Always strictly type your exports using the `spec` definitions. |
| 84 | + |
| 85 | +```typescript |
| 86 | +import { ObjectSchema } from '@objectstack/spec/data'; |
| 87 | + |
| 88 | +// ✅ GOOD: AI knows exactly what this is |
| 89 | +export const ProjectObject: ObjectSchema = { |
| 90 | + name: 'project', |
| 91 | + fields: { ... } |
| 92 | +}; |
| 93 | +``` |
| 94 | + |
| 95 | +### Rule #3: The `index.ts` Barrier |
| 96 | +Each module folder should have an `index.ts` that exports its public artifacts. This allows the manifest loader to simply import the module. |
| 97 | + |
| 98 | +```typescript |
| 99 | +// src/leads/index.ts |
| 100 | +export * from './lead.object'; |
| 101 | +export * from './lead.trigger'; |
| 102 | +export * from './lead.view'; |
| 103 | +``` |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +## 4. Context Tags (JSDoc) |
| 108 | + |
| 109 | +To help AI understand the "intent" of a file, use a standard JSDoc header. |
| 110 | + |
| 111 | +```typescript |
| 112 | +/** |
| 113 | + * @domain CRM |
| 114 | + * @object Lead |
| 115 | + * @purpose Defines the structure of a Sales Lead and its status lifecycle. |
| 116 | + */ |
| 117 | +export const LeadObject = ... |
| 118 | +``` |
0 commit comments