Ctrl K
ComunidadGuías…

AGENTS.md

Rama develop · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Copilot Instructions for Frappe Helpdesk

## Skills

For Frappe development tasks, reference the frappe-dev skill:
- **Location**: `~/.agents/skills/frappe-dev/`
- **Usage**: When working on DocType, controllers, whitelisted APIs, background jobs, permissions, or frontend tasks, read the relevant skill reference files:
  - `doctype.md` — Creating/modifying DocTypes and fields
  - `controllers.md` — Document lifecycle and server logic
  - `api.md` — REST endpoints with `@frappe.whitelist()`
  - `database.md` — `frappe.db`, queries, raw SQL
  - `background-jobs.md` — `frappe.enqueue`, scheduled jobs
  - `permissions.md` — Roles, DocType permissions
  - `frontend-desk.md`, `frontend-vue.md`, `frontend-portal.md` — Frontend references

## Project Overview

Frappe Helpdesk is an open-source ticket management tool built on the [Frappe Framework](https://github.com/frappe/frappe) (Python backend) and [Frappe UI](https://github.com/frappe/frappe-ui) (Vue.js frontend). It provides agent/customer portals, SLAs, assignment rules, a knowledge base, and saved replies.

## Tech Stack & Architecture

- **Backend**: Frappe Framework with Python
- **Frontend**: Vue 3 + TypeScript SPA with Vite dev server
- **Database**: MariaDB with structured doctypes
- **Real-time**: WebSockets via Socket.IO for live updates
- **UI Library**: frappe-ui for consistent design components
- **Styling**: Tailwind CSS with semantic design tokens

## Architecture

- **Backend (Python):** Located in `helpdesk/`.
  - API endpoints: `helpdesk/api/`
  - Business logic: `helpdesk/utils.py`, `helpdesk/search.py`, etc.
  - Extensibility: `helpdesk/extends/`, `helpdesk/overrides/`
- **Frontend (Vue.js):** Located in `desk/`.
  - Main entry: `desk/src/main.js`, `desk/src/App.vue`
  - Components: `desk/src/components/`
  - State: `desk/src/stores/`
  - Routing: `desk/src/router/`
  - Styles: Tailwind via `desk/index.css`, config in `desk/tailwind.config.js`
- **Customer portal and knowledge base (Studio app):** Located in `studio/helpdesk/`, served at `/help`. Read `studio/README.md` and `studio/KNOWLEDGE_BASE.md` before working on them.
- **Shared frontend code:** `shared/src`, imported as `@helpdesk/shared` by the desk and the portal.

# Frontend: Vue 3 Development Standards

## Frontend Project Context

- `desk/src/` contains the main Vue 3 frontend source code
- Vue 3.x with Composition API as default approach
- TypeScript for type safety and better development experience
- Single File Components (`.vue`) with `<script setup lang="ts">` syntax preferred
- Vite as the build tool for fast development and optimized builds
- Pinia for state management (unlike gameplan which avoids state libraries)
- frappe-ui for UI components and data fetching utilities

## Development Standards

### Architecture & Component Design

- Favor the Composition API (`setup` functions and composables) over the Options API
- Organize components and composables by feature or domain for scalability
- Separate UI-focused components (presentational) from logic-focused components (containers)
- Use PascalCase for component names and file names
- Keep components small and focused on one concern
- Use `<script setup lang="ts">` syntax for brevity and performance
- Favor slots and scoped slots for flexible composition

### TypeScript Integration

- TypeScript is enabled but not in strict mode (as per actual tsconfig.json)
- Use `<script setup lang="ts">` with `defineProps` and `defineEmits`
- Leverage `PropType<T>` for typed props and default values
- Use interfaces or type aliases for complex prop and state shapes
- Define types for event handlers, refs, and `useRoute`/`useRouter` hooks

### Styling Guidelines

- Always prefer Tailwind CSS for styling
- Use utility classes for layout and spacing
- Use semantic class names wherever possible:
  - Background colors: `bg-surface-white`, `bg-surface-gray-1` through `bg-surface-gray-9`, `bg-surface-black`
  - Text colors: `text-ink-white`, `text-ink-gray-1` through `text-ink-gray-9`, `text-ink-black`
  - Fill colors: `fill-ink-*`
  - Placeholder colors: `placeholder-ink-*`
  - Border colors: `border-outline-white`, `border-outline-gray-1` through `border-outline-gray-5`, `border-outline-black`
  - Font sizes: `text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`
  - Multiline text: `text-p-xs`, `text-p-sm`, `text-p-base`, `text-p-lg`, `text-p-xl`, `text-p-2xl`
- Always use gray shades for everything, never use color shades even for primary states
- Implement mobile-first, responsive design with CSS Grid and Flexbox
- Ensure styles are accessible (contrast, focus states)

### Data Fetching with frappe-ui

- Use `createResource`, `createListResource`, and `createDocumentResource` from frappe-ui for data fetching
- Handle loading, error, and success states explicitly
- These are the older but stable composables used throughout the project

When working with a list of documents:

```ts
const tickets = createListResource({
  doctype: "HD Ticket",
  filters: { status: "Open" },
  fields: ["name", "subject", "modified"],
  limit: 20,
  auto: true,
});

// Access data
tickets.data; // Array of ticket objects
tickets.loading; // Boolean loading state
tickets.error; // Error object if any

// Operations
tickets.reload(); // Refresh the list
tickets.update({ name: "<id>", subject: "Updated Subject" }); // Update item
tickets.insert({ subject: "New Ticket" }); // Add new item
tickets.delete("<id>"); // Delete item
```

When working with a single document:

```ts
const ticket = createDocumentResource({
  doctype: "HD Ticket",
  name: "<ticket-id>",
  auto: true,
});

// Access data
ticket.doc; // Document object
ticket.loading; // Boolean loading state
ticket.error; // Error object if any

// Operations
ticket.get(); // Fetch/refresh document
ticket.setValue("status", "Resolved"); // Update field
ticket.save(); // Save changes
ticket.delete(); // Delete document
```

For API calls:

```ts
const apiCall = createResource({
  url: "helpdesk.api.ticket.assign_ticket_to_agent",
  onSuccess(data) {
    // Handle success
  },
  onError(error) {
    // Handle error
  },
});

// Make the call
apiCall.submit({ ticket_id: "<id>", agent_id: "<agent>" });
```

### Icons

- **Primary icon system**: Lucide icons via unplugin-icons for consistency and modern design
- **Secondary**: FeatherIcon component from frappe-ui (legacy usage only)
- **Rule**: Never introduce `FeatherIcon` in new code. New components must use Lucide
  icons (`<LucideInfo />`, `<LucidePlus />`, …) — no exceptions, including small
  helper icons like tooltip/info glyphs.
- Use Lucide icons for all new components. They are globally auto-registered
  (see `desk/components.d.ts`), so no import is needed when used as a template tag:
  ```vue
  <template>
    <LucidePlus class="size-4" />
  </template>
  ```
- For script usage, import Lucide icons like this:
  ```ts
  import LucidePlus from "~icons/lucide/plus";
  import LucideTicket from "~icons/lucide/ticket";
  ```
- Only use FeatherIcon for maintaining existing components:
  ```vue
  <template>
    <FeatherIcon name="plus" class="h-4 w-4" />
  </template>
  ```

### State Management

- Use Pinia stores for complex shared state
- For simple local state, use `ref` and `reactive` within `setup`
- Use `computed` for derived state
- Keep state normalized for complex structures

### Performance & Accessibility

- Apply `v-once` and `v-memo` for static or infrequently changing elements
- Avoid unnecessary watchers; prefer `computed` where possible
- Use semantic HTML elements and ARIA attributes
- Manage focus for modals and dynamic content
- Ensure keyboard navigation for interactive components

# Backend: Frappe Framework Development Standards

## Backend Project Context

- Frappe Framework provides full-stack capabilities with ORM, permissions, and background jobs
- MariaDB database with structured DocTypes for business entities
- Redis for background workers and caching
- Socket.IO for real-time updates

## Critical Development Workflows

**Local Development Setup**:

- Backend runs via `bench start` from frappe-bench directory
- Python web server: Assume server is already started on port 8000
- Frontend dev server: `cd desk && yarn dev` (typically runs on port 8080)
- Site-specific commands: `bench --site helpdesk.test <command>`

**Data Query Patterns**:

- Always prefer `frappe.get_list()` over `frappe.get_all()` for new code. It handles perms out of the box and is more flexible.
- `frappe.get_all()` is fine for child tables (e.g. `Has Role`, `HD Customer Member`), which have no permissions of their own.
- When `frappe.get_all()` is used on a parent DocType, make sure the caller may see the result some other way, for example a `frappe.has_permission(...)` check first, or `@agent_only` / `@agent_manager_only` (`helpdesk/utils.py`) on the endpoint.
- Use `frappe.qb.get_query(..., ignore_permissions=False)` when permission checks are needed
- Example query patterns from helpdesk context

**Debugging Workflow**:

- Create debug files like `./helpdesk/debug.py` with `def execute():` function
- Run with `bench --site helpdesk.test execute helpdesk.debug.execute`
- Use `print()` statements for console output during debugging

## DocType Architecture Patterns

- Follow Frappe's DocType conventions for business entities
- Implement custom permission logic in `has_permission` hooks
- Use proper field types and validation in DocType definitions
- Leverage DocType methods for business logic encapsulation

## Controller Code Structure

All controller logic must follow this structure strictly:

**Rule: Lifecycle hooks call methods. Methods are defined below on the class.**

```python
class HDFoo(Document):
    # 1. Lifecycle hooks at the top — each hook calls methods, no inline logic
    def after_insert(self):
        self.do_a()
        self.do_b()

    def on_update(self):
        self.do_a()

    # 2. Methods below — one responsibility each
    def do_a(self):
        pass

    def do_b(self):
        pass


```

**Rules:**

- Lifecycle hooks (`after_insert`, `on_update`, `before_save`, `on_trash`, `after_rename`, etc.) contain **no inline logic** — they only call `self.method()`.
- All logic lives in methods on the class, not in module-level helper functions.
- Methods that mutate a related document (e.g. an Assignment Rule) receive that doc as an argument and mutate it in memory. The **caller** is responsible for the final `doc.save()` — this keeps saves to a minimum (one save per hook).
- Never fetch the same document twice in one hook. Fetch once, pass the doc through the call chain.
- `@staticmethod` is allowed for pure transformations (e.g. building a condition string) that don't touch `self` or any Frappe doc.
- If there is an issue in framework/ui or frappe-ui or frappe framework, dont do a workaround. Instead, raise a blocker in the spec and wait for a fix. Do not implement workarounds that will be removed later. If possible, raise a PR to fix the issue in the framework instead of implementing a workaround in helpdesk.

**Save discipline:**

- Mutate all fields on a document before calling `.save()` once.
- Never call `.save()` inside a helper method — save in the hook or the method that owns the full mutation.
- Exception: if a method truly owns a complete document lifecycle (e.g. `create_assignment_rule` creates and fully initialises a new doc), it may save internally.
Take inspiration from "helpdesk.doctype.hd_team.hd_team.HDTeam" for examples of this pattern in practice.

## Conventions & Patterns

- **API Design:** Python modules in `helpdesk/api/` follow RESTful patterns. Extend via `helpdesk/extends/`.
- **Frontend:** Vue 3 + Vite with TypeScript. Use Pinia for state management. Components auto-imported via `desk/components.d.ts`.
- **Testing:** Follow Frappe's conventions for backend tests.
- **Localization:** Add translations in `helpdesk/locale/`.
- **Custom Logic:** Use `helpdesk/overrides/` for customizations.

## Utilities and Composables

- @vueuse/core is available for common Vue utilities
- Prefer vueuse composables over custom implementations where applicable
- Common composables: `useLocalStorage`, `useDebounce`, `useElementSize`
- Always use frappe-ui's data fetching composables (`createResource`, `createListResource`, `createDocumentResource`), never `useFetch`

## Error Handling & Forms

- Use global error handlers for uncaught errors
- Wrap risky logic in `try/catch` with user-friendly messages
- Build forms with controlled `v-model` bindings
- Validate on blur or input with debouncing for performance
- Ensure accessible labeling and error announcements

## Integration Points

- **Frappe Framework:** All backend logic integrates with Frappe ORM, permissions, and hooks (`helpdesk/hooks.py`).
- **Frappe UI:** Frontend uses Frappe UI for consistent design components and data fetching.
- **Real-time Updates:** WebSockets via Socket.IO for live ticket updates.
- **Crowdin:** Translation sync via `crowdin.yml`.

## Examples

### Adding a New API Endpoint

1. Create a Python file in `helpdesk/api/`
2. Add `@frappe.whitelist()` decorator to functions
3. Register in `helpdesk/hooks.py` if needed
4. Use `frappe.qb.get_query()` for database queries

### Adding a Frontend Component

1. Create Vue component in `desk/src/components/` or `desk/src/pages/`
2. Use `<script setup lang="ts">` syntax
3. Follow Tailwind semantic class conventions
4. Use frappe-ui composables for data fetching
5. Add route in `desk/src/router/` if it's a page component

### Styling Example

```vue
<template>
  <div class="bg-surface-white border border-outline-gray-2 rounded-lg p-4">
    <h2 class="text-lg text-ink-gray-9 font-semibold mb-2">Ticket Details</h2>
    <p class="text-p-sm text-ink-gray-7">{{ ticket.doc.subject }}</p>
    <LucideTicket class="size-4 text-ink-gray-6" />
  </div>
</template>

<script setup lang="ts">
import { createDocumentResource } from "frappe-ui";
import LucideTicket from "~icons/lucide/ticket";

const ticket = createDocumentResource({
  doctype: "HD Ticket",
  name: props.ticketId,
  auto: true,
});
</script>
```

## Key Files & Directories

### Backend

- `helpdesk/api/` — Backend API endpoints with @frappe.whitelist() decorators
- `helpdesk/utils.py` — Shared backend utilities and helper functions
- `helpdesk/hooks.py` — Frappe hooks
- `helpdesk/overrides/` — Custom logic and extensions

### Frontend

- `desk/src/` — Main Vue 3 frontend source code
- `desk/src/components/` — Reusable Vue components
- `desk/src/pages/` — Page-level components and routes
- `desk/src/stores/` — Pinia stores for state management
- `desk/tailwind.config.js` — Tailwind CSS configuration with semantic tokens
- `desk/components.d.ts` — Auto-generated component type definitions

### Development

- `docker/` — Docker setup for containerized development

## Code Quality & Standards

- Follow Vue's official style guide and best practices
- Use ESLint with Vue 3 recommended rules and Prettier for consistency
- Write meaningful commit messages and maintain clean git history
- Document complex logic with JSDoc/TSDoc comments
- Keep a comment to 2 lines at most. If it needs more to explain, simplify the code instead
- Keep dependencies updated and audit for security vulnerabilities

## References

- [README.md](../README.md) — Full setup and feature list
- [Frappe Docs](https://frappeframework.com/docs/) — Framework documentation
- [Frappe Helpdesk Docs](https://docs.frappe.io/helpdesk) — Project-specific docs
- [Vue 3 Style Guide](https://vuejs.org/style-guide/) — Vue.js best practices
- [Tailwind CSS](https://tailwindcss.com/docs) — Utility-first CSS framework

---

## Agent Working Rules

These rules apply to all agents working in this codebase. Follow them without exception.

### 1. Site Data — Read Before You Write

When a Frappe site is referenced in the conversation (e.g. `erp-hd.localhost`, `hd-tests`),
treat it as the **source of truth for current data state**.

- Before assuming anything about existing records, custom fields, settings, or DocType state —
  query the site first using the bench venv Python or `bench execute`.
- **Never write data to a site unless the user explicitly asks you to.**
  Querying is always safe. Mutations (insert, update, delete, migrate, patch) require explicit
  user instruction.
- If you need to verify a fix worked, re-query the site — do not assume success from code
  inspection alone.

```python
# Safe pattern for querying a site
import sys, os
sys.path.insert(0, 'apps/frappe')
os.chdir('sites')
import frappe
frappe.init(site='<site-name>', sites_path='.')
frappe.connect()

# ... read-only queries here ...

frappe.destroy()
```

Run via: `cd /path/to/frappe-bench && env/bin/python /tmp/your_script.py`

---

### 2. Spec-Driven Development — Keep the Spec Current

When a feature has a spec document (e.g. `docs/erpnext-customer-sync.md`), the spec is the
**living source of truth** for that feature. It must be kept in sync with the actual
implementation at all times.

**Rules:**

- **Update the spec in the same session as the code change.** Never defer spec updates to a
  later session.
- **The spec reflects what is implemented, not what was originally planned.** If a decision
  changes mid-build (e.g. removing a scheduler job, changing how a field is set), update the
  spec immediately after the code change.
- **Removed features must be removed from the spec.** Do not leave stale sections, blockers, or
  file manifest entries for things that no longer exist.
- **New features must be added to the spec.** If a new API, component, or behaviour is
  introduced, add a corresponding section.
- **Decisions and their rationale belong in the spec.** If something was done a specific way to
  avoid a bug or framework limitation (e.g. not setting `customer_group` to avoid the group-node
  error), document that in the relevant Blocker section.
- When in doubt about whether a spec update is needed — update it.

---

### 3. Test Utilities — Always Use `helpdesk/test_utils.py`

All backend test helpers must live in `helpdesk/test_utils.py` and be imported from there.
Never define helper functions (factories, enable/disable toggles, fixture builders) directly
inside individual test files.

**Rules:**

- **Before writing a helper in a test file**, check `helpdesk/test_utils.py` first — it may
  already exist.
- **If a helper doesn't exist**, add it to `helpdesk/test_utils.py` and import it in the test
  file. Do not leave it inline.
- **If you write helpers inline during development**, move them to `test_utils.py` before
  finishing the task.
- Helper functions in `test_utils.py` must have a docstring explaining what they create or do. Only if the function is completely self-explanatory (e.g. `enable_erpnext_sync`) can the docstring be omitted.
- Naming conventions:
  - Factories: `make_<doctype>(...)` — e.g. `make_hd_customer`, `make_ticket`, `make_team`
  - Toggle helpers: `enable_<feature>()` / `disable_<feature>()` — e.g. `enable_erpnext_sync`
  - Query helpers: descriptive verb — e.g. `get_latest_ticket_communication`

**For updates, merge new conventions here. If anything is unclear or missing, ask for clarification.**

**In the end your code will be reviewed by Codex, but following these rules will help ensure a smooth review process and a high-quality codebase.**