# Cost Calculator Builder - Cursor AI Rules
This is a WordPress plugin: **Cost Calculator Builder** (Free version v3).
## 🏗️ Project Architecture
**Hybrid Architecture** - Migrating from Vue2 + jQuery to Vue3 + TypeScript:
- **Frontend**: `frontend/vue3/src/admin/` - Vue3 + TypeScript + Pinia + Vue Flow
- **Backend**: `includes/classes/` - PHP 7.4+ with WordPress hooks and namespaces
- **Database**: WordPress tables (wp_posts, wp_postmeta, wp_options) + custom tables
- **Build**: Webpack + Laravel Mix
## 📋 Core Concepts
### Calculator Structure (3 levels)
1. **Calculator** (Post Type: `cost-calc`)
- Pages (Page Breaks)
- Sections
- Fields (Range, Checkbox, Toggle, etc.)
### Data Storage
- **wp_posts**: Calculator as post (`post_type = 'cost-calc'`)
- **wp_postmeta**: Fields (`stm-fields`), Conditions (`stm-conditions`), Formula (`stm-formula`)
- **wp_options**: Settings per calculator (`stm_ccb_form_settings_{id}`)
- **Custom tables**: Orders, Forms, Promocodes, Analytics
### State Management (Pinia Stores)
- `useBuilderStore` - Fields, Pages, Sections management
- `useConditionsStore` - Conditions Editor (Vue Flow based)
- `useCalculatorStore` - Calculator data, Settings, Forms
## 🎨 Frontend Rules (Vue3 + TypeScript)
### Mandatory Patterns
```typescript
// ✅ ALWAYS use Composition API with script setup
```
### Naming Conventions
- **Components**: PascalCase (`CalculatorField.vue`)
- **Stores**: camelCase with `use` prefix (`useBuilderStore.ts`)
- **Types**: Interface with `I` prefix (`IField`, `ICalculator`)
- **Variables/Functions**: camelCase
### Import Order
1. Vue & core libraries
2. External libraries
3. Stores
4. Types
5. Components
6. Utils
7. Styles
**Full Frontend Rules**: See `.cursor/rules/vue3-frontend.md`
## 🔧 Backend Rules (PHP)
### Mandatory Patterns
```php
// ✅ ALWAYS use CCB prefix for classes
namespace cBuilder\Classes;
class CCBCalculators {
// ✅ ALWAYS specify visibility
public function getCalculatorData($id) {}
// ✅ ALWAYS verify nonce and capabilities in AJAX
public static function saveCalcAction() {
check_ajax_referer('ccb_save_calculator', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error('Not authorized');
}
// ✅ ALWAYS sanitize input
$calc_id = absint($_POST['id']);
$title = sanitize_text_field($_POST['title']);
// ✅ ALWAYS escape output
echo esc_html($title);
wp_send_json_success($data);
}
}
```
### Security (CRITICAL)
- **Nonce**: `check_ajax_referer()` in every AJAX handler
- **Capability**: `current_user_can()` check
- **Sanitization**: `sanitize_text_field()`, `absint()`, `wp_kses_post()`
- **Escaping**: `esc_html()`, `esc_attr()`, `esc_url()`
- **SQL**: ALWAYS use `$wpdb->prepare()`
**Full PHP Rules**: See `.cursor/rules/php-backend.md`
## 🔄 API Communication
### Pattern
```typescript
// Frontend (TypeScript)
const response = await axios.post(ajaxurl, {
action: 'calc_get_calculator',
nonce: window.ccb_nonces.get_calculator,
id: calculatorId
});
```
```php
// Backend (PHP)
add_action('wp_ajax_calc_get_calculator', [CCBCalculatorsHandler::class, 'getCalcAction']);
public static function getCalcAction() {
check_ajax_referer('ccb_get_calculator', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error('Not authorized');
}
$calc_id = absint($_POST['id']);
$data = self::getCalculatorData($calc_id);
wp_send_json_success($data);
}
```
**Full API Rules**: See `.cursor/rules/api-structure.md`
## 🎨 SCSS/CSS Rules (BEM + CCB Prefix)
### Mandatory Patterns
```scss
// ✅ ALWAYS use ccb- prefix with BEM naming
.ccb-calculator {} // Block
.ccb-calculator__field {} // Element
.ccb-calculator--dark {} // Modifier
.ccb-calculator__field--disabled {} // Element + Modifier
// ✅ ALWAYS scope styles to avoid theme conflicts
.ccb-calculator-wrapper {
.ccb-field {
// Your styles
}
}
// ✅ Override theme styles with explicit classes
input.ccb-input {} // NOT just input {}
button.ccb-button {} // NOT just button {}
a.ccb-link {} // NOT just a {}
```
### Rules
- **Prefix**: ALL classes with `ccb-`
- **BEM**: Use `.ccb-block__element--modifier` pattern
- **Specificity**: Avoid deep nesting (max 2 levels)
- **Scope**: Always wrap in plugin root to avoid theme conflicts
- **Overrides**: Use `.ccb-class` on elements, not global selectors
**Full SCSS Rules**: See `.cursor/rules/scss-bem-ccb-prefix.mdc`
## 📚 Detailed Documentation
When you need detailed information, reference these files:
### Architecture & Structure
- **`.cursor/docs/architecture.md`** - Complete system architecture, tech stack, file structure
- **`.cursor/PROJECT-STATUS.md`** - Current project status, migration progress, technical debt
### Data & API
- **`.cursor/docs/database-schema.md`** - All tables, schemas, models, query examples
- **`.cursor/docs/api-endpoints.md`** - All API endpoints with request/response examples
### Features & Systems
- **`.cursor/docs/field-types.md`** - All calculator field types, options, implementation guide
- **`.cursor/docs/conditions-system.md`** - Conditions Editor (Vue Flow), nodes, edges, execution
### Migration & Guidelines
- **`.cursor/docs/vue2-to-vue3-migration.md`** - Migration guide, patterns, differences
## 🎯 Skills & Tutorials
For step-by-step guides:
### Adding Features
- **`.cursor/skills/add-calculator-field.md`** - Complete guide: Add new field type (Vue + TS + PHP)
### Debugging
- **`.cursor/skills/debug-store.md`** - Debug Pinia stores with Vue DevTools, logging, snapshots
- **`.cursor/skills/work-with-conditions.md`** - Work with Conditions system (Vue Flow)
## 🚨 Common Pitfalls
### Vue3 Frontend
- ❌ **Don't** destructure store state directly: `const { field } = store` (loses reactivity)
- ✅ **Do** use `storeToRefs`: `const { field } = storeToRefs(store)`
- ❌ **Don't** use Options API: `export default { data() {} }`
- ✅ **Do** use Composition API: `