Files
upstream-mirror 135ffdb085
Some checks failed
Admin | Playwright Tests / Admin | Playwright Tests | Shard 1 Of 6 (push) Failing after 37s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 2 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 4 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 6 Of 6 (push) Failing after 6s
Linting Tests / PHP 8.3 test on ubuntu-latest (push) Failing after 5s
CI / PHP 8.3 test on ubuntu-latest (push) Failing after 6s
Skills Consistency / validate-skills (push) Successful in 10s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 3 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 5 Of 6 (push) Failing after 6s
snapshot of https://github.com/krayin/laravel-crm.git (2.2, 2026-09-18; blobs > 131072B omitted)
2026-09-18 04:37:41 +05:00

223 lines
8.7 KiB
Markdown

---
name: crm-package-development
description: Use when creating a new Krayin CRM package or module, extending CRM functionality via a package, or adding custom business logic without modifying core files. Also use for any translation work — adding or moving lang files, adding a locale, or deciding whether a package gets its own Resources/lang directory — and whenever a fix or feature needs a CHANGELOG.md entry. Covers Laravel package structure, service providers, migrations, models, repositories, routes, controllers, views, localization, changelog entries, config, ACL, and menus.
---
# Skill: CRM Package Development (Krayin CRM)
## Purpose
This skill guides the AI agent to design and develop a new CRM package
(module) for Krayin CRM in a clean, upgrade-safe, and maintainable way.
---
## When to Activate
Activate this skill when the user wants to:
- Create a new CRM package/module
- Extend CRM functionality via a package
- Add custom business logic without modifying core files
- Add, move, or delete translation (lang) files, or add a new locale
- Fix a bug or ship a feature — the change needs a `CHANGELOG.md` entry
---
## Project Context
- Framework: Laravel
- Product: Krayin CRM
- Krayin CRM is already installed and running
- The package must integrate seamlessly with existing CRM modules
---
## Development Rules
- Follow Krayin CRM architecture and conventions
- Do NOT modify core Krayin files unless explicitly required
- Use Laravel package-based structure
- All database changes must be done using migrations
- Ensure backward compatibility and safe upgrades
---
## Package Structure Guidelines
A CRM package should follow this structure:
```text
packages/
└── Webkul/
└── PackageName/
├── src/
│ ├── Providers/
│ │ └── PackageServiceProvider.php
│ ├── Models/
│ ├── Contracts/
│ ├── Repositories/
│ ├── Http/
│ │ ├── Controllers/
│ │ └── Requests/
│ ├── Routes/
│ │ ├── admin.php
│ │ └── api.php
│ ├── Database/
│ │ └── Migrations/
│ ├── Resources/
│ │ ├── views/ # only if the package renders its own Blade
│ │ └── lang/ # ONLY if views/ exists — see Localization
│ └── Config/
│ ├── package.php
│ ├── menu.php
│ ├── core_config.php
│ └── acl.php
└── composer.json
```
---
## Localization (Translations)
### The rule
A package owns a `Resources/lang/` directory **only if it also owns
`Resources/views/`** — that is, only if it renders its own Blade templates.
Every other package ships **zero** translation files; its strings live in the
**Admin** package under `admin::app.*`.
Before creating any lang file, ask:
> Does this package have `src/Resources/views/` with Blade templates?
- **Yes** → give it `Resources/lang/<locale>/app.php` and register its own
namespace with `loadTranslationsFrom()` in the service provider.
- **No** → do **not** create a lang directory and do **not** call
`loadTranslationsFrom()`. Put the keys in the Admin package and reference them
as `admin::app.…`.
Current state of the repo — preserve this invariant:
| Owns views | Packages | Translations live in |
|---|---|---|
| Yes | `Admin`, `Installer`, `WebForm` | the package itself (`admin::`, `installer::`, `web_form::`) |
| No | everything else (`Core`, `DataTransfer`, `Lead`, `Contact`, `Quote`, `User`, …) | `Admin` (`admin::app.*`) |
"Backend-only" strings are still translations and follow the same rule —
validation-rule messages, importer error maps, and `title` values referenced
from `Config/*.php` all belong in Admin when the package has no views.
### Where keys go for a view-less package
Nest them under the Admin key that already owns that domain so one feature's
strings stay together. Established precedent:
| Before | After |
|---|---|
| `core::app.validations.code` | `admin::app.validations.message.code` |
| `data_transfer::app.importers.persons.title` | `admin::app.settings.data-transfer.importers.persons.title` |
| `data_transfer::app.validation.errors.system` | `admin::app.settings.data-transfer.validation.errors.system` |
When you move keys out of a package, finish the job: rewrite every reference,
delete the package's `Resources/lang/`, and remove its `loadTranslationsFrom()`
call so the provider does not point at a path that no longer exists.
### Working with Admin lang files
- Admin ships one `app.php` per locale: `ar`, `en`, `es`, `fa`, `ko`, `pt_BR`,
`tr`, `vi`, `zh_CN`. **Add every new key to all of them in the same change** —
a key present only in `en` renders as the raw key string in other locales.
- If a real translation is unavailable, use the English text as the value. Never
omit the key, and never leave the key name as its own value.
- Preserve placeholders exactly: `:attribute`, `:days`, `:count` (Laravel) and
`%s` (importer messages formatted with `sprintf`).
- Pint enforces a **single space** around `=>` (`pint.json` →
`binary_operator_spaces`). Do not align `=>` into columns.
- Name the file `app.php` in every locale directory. A misnamed file (e.g.
`ar/ar.php`) is never loaded and the locale silently falls back to English.
### Adding a new locale
1. Create `<locale>/app.php` in each package that owns a lang directory
(`Admin`, `Installer`, `WebForm`), mirroring the `en` key structure exactly.
2. Register it in `config/app.php` → `available_locales`. This drives both the
admin locale dropdown (via `Core@locales`) and the web installer.
3. Add it to `$locales` in
`packages/Webkul/Installer/src/Console/Commands/Installer.php` so the CLI
installer offers it.
4. If the script is right-to-left, add it to the `['fa', 'ar']` checks in the
Admin layout Blade files.
### Verifying
Confirm parity with `en` — same key set, same placeholders — then check that
keys actually resolve:
```bash
php artisan tinker --execute='app()->setLocale("<locale>"); echo trans("admin::app.<your.key>");'
./vendor/bin/pint --test packages/Webkul/<Package>
```
A key that resolves to its own name (`admin::app.foo.bar`) is missing.
---
## Changelog
### The rule
**Every bug fix and every feature gets a `CHANGELOG.md` entry, in the same
change.** Do not leave it for someone else and do not treat it as optional
follow-up work — a fix that is not in the changelog is invisible to the release
notes.
Add an entry when the change is user-visible or operator-visible: a bug fix, a
new feature, an enhancement, a security fix, a configuration option, or a
convention that affects how the product is built. Skip it only for changes with
no observable effect at all — a typo in a code comment, a pure test refactor.
### Format
Entries live at the top of [CHANGELOG.md](../../../CHANGELOG.md), newest version
first, and use exactly this shape:
```markdown
## **v2.2.5 (Upcoming)**
* #2601[fixed] Fixed lead value not saved when the currency is changed.
* #2604[feature] Added Chinese (Simplified) translation.
```
- One blank line between every entry — the file is read as rendered markdown.
- No space between the issue number and the tag: `#2601[fixed]`, not `#2601 [fixed]`.
- Write the description as a complete sentence ending in a period, phrased from
the user's point of view, not the implementation's.
Valid tags, and when each applies:
| Tag | Use for |
|---|---|
| `[fixed]` | Something was broken and now works. |
| `[feature]` | New capability that did not exist before. |
| `[enhancement]` | Existing behaviour improved, refactored, or made faster. |
| `[security]` | Vulnerability fix. Reference the CVE when one exists. |
### Which version section
Add to the topmost section if it is still unreleased. If the top section is
already tagged `*Release*`, open a new one above it:
```markdown
## **v<next patch version> (Upcoming)**
```
Replace `(Upcoming)` with the real date in the release commit — the existing
released headings show the expected style: `## **v2.2.4 (20th of July 2026)** *Release*`.
### Two things not to do
- **Never invent an issue or PR number.** They point at real GitHub PRs, so a
guessed number creates a false reference. If the PR does not exist yet, omit
the `#NNNN` prefix and leave the tag, then fill the number in once it is
opened.
- **Do not bump the version constant as part of a feature or fix.**
`KRAYIN_VERSION` in `packages/Webkul/Core/src/Core.php` is incremented in the
release commit, together with dating the changelog heading — not per change.