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

8.7 KiB

name, description
name description
crm-package-development 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:

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:

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, newest version first, and use exactly this shape:

## **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:

## **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.