snapshot of https://github.com/krayin/laravel-crm.git (2.2, 2026-09-18; blobs > 131072B omitted)
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
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
This commit is contained in:
51
.github/skills/README.md
vendored
Normal file
51
.github/skills/README.md
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# Skills Standard
|
||||
|
||||
## Canonical Source
|
||||
|
||||
All workspace skills are maintained in:
|
||||
|
||||
- `.github/skills/<skill-name>/SKILL.md`
|
||||
|
||||
This is the single source of truth for every AI coding agent in this repository.
|
||||
|
||||
## Agent Runtime Links
|
||||
|
||||
The following paths are **symlinks** to `.github/skills` so each agent runtime
|
||||
auto-discovers the same skills:
|
||||
|
||||
| Path | Agent |
|
||||
|------|-------|
|
||||
| `.ai/skills` | Generic / `.ai` convention |
|
||||
| `.claude/skills` | Claude Code |
|
||||
| `.codex/skills` | OpenAI Codex |
|
||||
| `.cursor/skills` | Cursor |
|
||||
| `.kilocode/skills` | Kilo Code |
|
||||
|
||||
> Symlinks are committed to git (mode `120000`). On a Windows checkout without
|
||||
> symlink support they may materialize as plain files — clone with symlink
|
||||
> support enabled (`git config core.symlinks true`).
|
||||
|
||||
## Available Skills
|
||||
|
||||
| Skill | Use when |
|
||||
|-------|----------|
|
||||
| `crm-package-development` | Creating a new Krayin CRM package/module or extending CRM functionality without touching core files. |
|
||||
| `pest-testing` | Writing or debugging Krayin CRM unit/feature tests with Pest. |
|
||||
|
||||
## Authoring Rules
|
||||
|
||||
- Add or update skills **only** in `.github/skills` (never edit through a symlink target name as if it were a separate copy).
|
||||
- Keep `name` and `description` in the YAML frontmatter of every `SKILL.md`.
|
||||
- `name` must be lowercase, hyphen-separated, and **match the skill's directory name**.
|
||||
- Use explicit "Use when..." trigger language in descriptions so agents match them reliably.
|
||||
- Do not maintain duplicate `SKILL.md` files in agent-specific folders.
|
||||
|
||||
## Validation
|
||||
|
||||
Validate frontmatter and naming with the Agent Skills reference tool:
|
||||
|
||||
```bash
|
||||
skills-ref validate .github/skills/<skill-name>
|
||||
```
|
||||
|
||||
See the [Agent Skills specification](https://agentskills.io/specification) for the full format.
|
||||
222
.github/skills/crm-package-development/SKILL.md
vendored
Normal file
222
.github/skills/crm-package-development/SKILL.md
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
---
|
||||
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.
|
||||
144
.github/skills/pest-testing/SKILL.md
vendored
Normal file
144
.github/skills/pest-testing/SKILL.md
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
---
|
||||
name: pest-testing
|
||||
description: Use when writing or updating Krayin CRM tests (unit or feature), debugging test failures, using datasets, mocks or custom expectations, writing architecture tests, or when the user mentions test, spec, TDD, expects, assertion, or coverage. Uses the Pest PHP framework (v3) with Laravel 12.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: webkul
|
||||
---
|
||||
|
||||
# Pest Testing in Krayin CRM
|
||||
|
||||
## When to Apply
|
||||
|
||||
Activate this skill when:
|
||||
- Creating or updating tests (unit or feature)
|
||||
- Debugging test failures
|
||||
- Using datasets, mocks, or custom expectations
|
||||
- Writing architecture or convention tests
|
||||
- The user mentions test, spec, TDD, expects, assertion, coverage, or verifying behavior
|
||||
|
||||
## Krayin Testing Structure
|
||||
|
||||
### Test Locations
|
||||
|
||||
Krayin tests are stored in the root `tests/` directory:
|
||||
|
||||
```
|
||||
/tests
|
||||
├── Feature/
|
||||
├── Unit/
|
||||
├── Pest.php
|
||||
├── TestCase.php
|
||||
└── CreatesApplication.php
|
||||
```
|
||||
|
||||
### Available Test Suites
|
||||
|
||||
Defined in `phpunit.xml`:
|
||||
|
||||
| Test Suite | Location | Command |
|
||||
|------------|----------|---------|
|
||||
| Unit | `tests/Unit` | `php artisan test --testsuite="Unit"` |
|
||||
| Feature | `tests/Feature` | `php artisan test --testsuite="Feature"` |
|
||||
|
||||
## Pest.php Configuration
|
||||
|
||||
`tests/Pest.php` binds the base test case for feature tests:
|
||||
|
||||
```php
|
||||
uses(\Tests\TestCase::class)->in('Feature');
|
||||
```
|
||||
|
||||
It also defines helper functions you can reuse, such as:
|
||||
- `getDefaultAdmin()`
|
||||
- `actingAsSanctumAuthenticatedAdmin()`
|
||||
- `getFirstName($fullName)`
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Run All Tests
|
||||
|
||||
```bash
|
||||
php artisan test --compact
|
||||
```
|
||||
|
||||
### Run a Specific Test Suite
|
||||
|
||||
```bash
|
||||
php artisan test --testsuite="Feature"
|
||||
php artisan test --testsuite="Unit"
|
||||
```
|
||||
|
||||
### Run a Specific Test File
|
||||
|
||||
```bash
|
||||
php artisan test --compact tests/Feature/ExampleTest.php
|
||||
```
|
||||
|
||||
### Run with Filter
|
||||
|
||||
```bash
|
||||
php artisan test --compact --filter=testName
|
||||
```
|
||||
|
||||
## Creating New Tests
|
||||
|
||||
### Create Feature Test
|
||||
|
||||
```bash
|
||||
php artisan make:test --pest ExampleFeatureTest
|
||||
```
|
||||
|
||||
### Create Unit Test
|
||||
|
||||
```bash
|
||||
php artisan make:test --pest --unit ExampleUnitTest
|
||||
```
|
||||
|
||||
## Basic Test Structure
|
||||
|
||||
```php
|
||||
it('passes basic assertion', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
|
||||
it('returns successful response', function () {
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertSuccessful();
|
||||
});
|
||||
```
|
||||
|
||||
## Assertions
|
||||
|
||||
Prefer specific response helpers:
|
||||
|
||||
| Use | Instead of |
|
||||
|-----|------------|
|
||||
| `assertSuccessful()` | `assertStatus(200)` |
|
||||
| `assertNotFound()` | `assertStatus(404)` |
|
||||
| `assertForbidden()` | `assertStatus(403)` |
|
||||
|
||||
## Datasets
|
||||
|
||||
```php
|
||||
it('has valid emails', function (string $email) {
|
||||
expect($email)->toContain('@');
|
||||
})->with([
|
||||
'james' => 'james@krayin.com',
|
||||
'john' => 'john@krayin.com',
|
||||
]);
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Forgetting to use `assertSuccessful()` and other specific helpers
|
||||
- Skipping `--pest` when creating tests
|
||||
- Ignoring helper utilities already available in `tests/Pest.php`
|
||||
|
||||
## Testing Best Practices
|
||||
|
||||
- Cover happy paths, failure paths, and edge cases
|
||||
- Keep tests isolated and focused
|
||||
- Use factories where available
|
||||
- Follow existing test patterns in the repository
|
||||
Reference in New Issue
Block a user