118 lines
7.7 KiB
Markdown
118 lines
7.7 KiB
Markdown
# Contributing to boboko-core
|
|
|
|
This is a Composer library, not a runnable app — you can't `php artisan serve` it directly. To develop and verify changes, you need a consumer app wired to a local checkout via a Composer path repository, plus a real database, since a large part of this package (Lunar models, migrations, Filament panel resources) can only be meaningfully verified against a live Lunar install.
|
|
|
|
## Local dev setup
|
|
|
|
This works against any consumer app that follows the same convention — `boboko-test`, `boboko-starter`, `boboko-3dealer`, etc. — checked out next to this repo:
|
|
|
|
```
|
|
RadicalElements/
|
|
├── boboko-core/ (this repo)
|
|
└── boboko-test/ (or boboko-starter, boboko-3dealer, ... — consumer app, Docker-based)
|
|
```
|
|
|
|
Each of these consumer apps ships a `bin/dc-core.sh` helper that wraps the Docker Compose overlay needed to bind-mount a local `boboko-core` checkout into the app container:
|
|
|
|
```bash
|
|
./bin/dc-core.sh exec app <command>
|
|
```
|
|
|
|
This is shorthand for `docker compose -f docker-compose.dev.yml -f docker-compose.core-dev.yml exec app <command>`. Use `./bin/dc-core.sh` for everything below instead of typing the full compose invocation.
|
|
|
|
1. **Path repository.** In the consumer app's `composer.json`, the `repositories` array needs a path entry pointing at `../boboko-core`. If it only exists in a disabled block (e.g. `_repositories`), move it into the live array.
|
|
2. **Relaxed version constraint.** The consumer app's `composer.json` should require `"boboko/core": "0.*"` (not a tight `^0.0.1` caret) — otherwise Composer rejects newer `0.0.x` versions resolved from the path repo.
|
|
3. **Bind mount.** The consumer app's `docker-compose.core-dev.yml` overlays `../boboko-core` into the container at `/var/www/boboko-core`, matching where the path repo resolves it relative to `/var/www/html`.
|
|
4. **Re-resolve after every change.** Composer's path repo does not hot-reload — after editing anything in `boboko-core` (including adding new files, which need autoload discovery), the container needs to re-run `composer update boboko/core`. In `boboko-test`, the entrypoint does this automatically on every dev boot (see `docker/entrypoint.sh`), so `./bin/dc-core.sh up` alone picks up local core changes. If a consumer app's entrypoint doesn't do this yet, run it manually:
|
|
|
|
```bash
|
|
./bin/dc-core.sh exec app composer update boboko/core --with-all-dependencies
|
|
```
|
|
|
|
Skipping this step is the most common cause of "my change isn't showing up."
|
|
|
|
## JS/CSS: no separate npm package
|
|
|
|
This package's JS (Stimulus controllers) and CSS ship as plain source files under `resources/js/` and `resources/css/`, read directly by a consumer app's own Vite build — there is no separate `@boboko/core` npm package, and no `npm install`/`file:` dependency step of any kind.
|
|
|
|
The reason: Composer already gives every environment one single, unconditional path — `vendor/boboko/core` — whether that resolves to a real symlink into `../boboko-core` (local path repo) or a real installed copy (tagged VCS release). A consumer's `vite.config.js` and JS entry point just read straight from that path, so there is nothing to toggle on the JS side — whatever Composer resolved is exactly what Vite sees, automatically, in both dev and prod.
|
|
|
|
**Stable entry point.** A consumer imports from [resources/js/index.js](resources/js/index.js) only — never from a path reaching into a specific module's internals (e.g. `resources/js/checkout/index.js` directly). That barrel file re-exports whatever a consumer needs (currently just `registerCheckout`), so this package's internal file layout can change without breaking every consumer's own entry point:
|
|
|
|
```js
|
|
// consumer app's resources/js/app.js
|
|
import { registerCheckout } from "../../vendor/boboko/core/resources/js/index.js";
|
|
registerCheckout(application);
|
|
```
|
|
|
|
```php
|
|
{{-- consumer app's layout --}}
|
|
@vite(['vendor/boboko/core/resources/css/checkout.css', 'resources/css/app.css', 'resources/js/app.js'])
|
|
```
|
|
|
|
**What a consumer's `vite.config.js` needs**, because `vendor/boboko/core` is a symlink in local path-repo dev (not a real directory):
|
|
|
|
```js
|
|
export default defineConfig({
|
|
server: {
|
|
watch: {
|
|
// vendor/boboko/core is a symlink into ../boboko-core in local
|
|
// path-repo dev. Vite/chokidar don't follow symlinks for watched
|
|
// files by default, so edits to core's source wouldn't otherwise
|
|
// trigger HMR. No-op against a real installed copy (tagged VCS
|
|
// release) in production — there's no symlink to follow, and
|
|
// production only ever runs a one-shot `npm run build`, which
|
|
// doesn't watch anything regardless.
|
|
followSymlinks: true,
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
Bare imports inside this package's own JS (`leaflet`, `@hotwired/stimulus`) resolve against the *consumer's* `node_modules` — Node's normal upward `node_modules` resolution walks from `vendor/boboko/core/resources/js/...` up through `vendor/boboko/`, `vendor/`, to the consumer app's root, where `node_modules` lives. This works with zero extra config as long as `vendor/boboko/core` sits inside the consumer's own directory tree (true for both the symlink and the real-copy case) — a consuming app's `vite`-equivalent Docker service just needs the same bind mount PHP containers already get, landing at the same path:
|
|
|
|
```yaml
|
|
# consumer app's docker-compose.core-dev.yml
|
|
services:
|
|
vite:
|
|
volumes:
|
|
- ../boboko-core:/app/vendor/boboko/core
|
|
```
|
|
|
|
(Match whatever the consumer's Vite container's working directory actually is — `/app` above, `/var/www/html` for the PHP containers in `boboko-test`'s convention.)
|
|
|
|
## Verifying changes against a real database
|
|
|
|
There is no automated test suite for this package — too much of Lunar's behavior (table prefixing, nested sets, translatable attributes, Filament panel filters) only breaks in combination, against real Postgres, in a way that's impractical to fake in isolation. Instead, verify changes directly against a consumer app's live database. The practical workflow used throughout this package's `MigrateImport` feature:
|
|
|
|
**One-off checks**, via `php artisan tinker --execute="..."` in the consumer app's container:
|
|
|
|
```bash
|
|
./bin/dc-core.sh exec app php artisan tinker --execute="
|
|
use Modules\Core\MigrateImport\Shopify\Resolvers\ProductTypeResolver;
|
|
\$type = (new ProductTypeResolver())->resolve('Test Type');
|
|
echo \$type->name . PHP_EOL;
|
|
"
|
|
```
|
|
|
|
**Multi-step scripts** (creating related records, checking round-trips), via a raw PHP script bootstrapped like an Artisan command — this avoids tinker's persistent-session quirks and more closely matches how code actually runs in a queued job:
|
|
|
|
```bash
|
|
./bin/dc-core.sh exec app php -r "
|
|
require 'vendor/autoload.php';
|
|
\$app = require 'bootstrap/app.php';
|
|
\$kernel = \$app->make(Illuminate\Contracts\Console\Kernel::class);
|
|
\$kernel->bootstrap();
|
|
|
|
// ... your verification code ...
|
|
"
|
|
```
|
|
|
|
**Always clean up fixtures** created this way — either via `DB::statement('DELETE FROM ...')` in the same script (respecting foreign key order — Lunar has cascading relations like `lunar_customer_group_product` that block naive deletes), or leave them if they're harmless and the DB is a disposable dev/test instance.
|
|
|
|
Non-obvious Lunar bugs/traps hit while building against it are documented in [docs/lunar.md](docs/lunar.md#gotchas), not here — check there before debugging something that looks like a Lunar quirk.
|
|
|
|
## Code organization
|
|
|
|
Feature work lives under `src/<Feature>/`, with models in a `Models/` subdirectory (see `src/Auth/Models`, `src/Customer/Models`, `src/MigrateImport/Models`). Source-specific importer logic is grouped by source name (e.g. `src/MigrateImport/Shopify/`), with resolver classes (one responsibility each — resolve-or-create a single Lunar entity) grouped further under `Resolvers/`.
|