Workflow & Versioning
Full Workflow
Generate an Auth Token
./index.js token \
--baseUrl=https://demo.phpreaction.com \
--devUsername=admin \
--devPassword=demo \
--bundleCrud=phprCrudToken is saved to config/token.txt and used automatically by all subsequent commands.
Fetch API Metadata (JSON v0)
./index.js gen:json \
--entity=AccountingBundle/Account \
--bundleCrud=phprCrud \
--baseUrl=https://demo.phpreaction.com/open-api/v3Creates:
config/versioned/json/AccountingBundle/Account/v0/
├── data.json ← raw metadata from API
└── changes.json ← empty customization templateCustomise changes.json
Open the generated changes.json and edit your field selections. See the changes.json Reference for all options.
Preview before generating:
./index.js preview:changes \
--entity=AccountingBundle/Account \
--version=v0Validate that all field names exist in the API data:
./index.js validate:changes \
--entity=AccountingBundle/Account \
--version=v0(Optional) Match Legacy Scraper Data
./index.js match:scraper --entity=AccountingBundle/Account
# Preview without writing
./index.js match:scraper --entity=AccountingBundle/Account --dryRunGenerate TSX Configuration
./index.js gen:tsx \
--entity=AccountingBundle/Account \
--bundleCrud=phprCrudCreates: config/versioned/tsx/AccountingBundle/Account/v0/index.tsx
Pin to a specific JSON version:
./index.js gen:tsx \
--entity=AccountingBundle/Account \
--jsonVersion=v1 \
--bundleCrud=phprCrudValidate
./index.js validate --entity=AccountingBundle/AccountChecks JSON–TSX consistency, resource names, and field mappings.
Export to Frontend Project
./index.js exportEntity \
--entity=AccountingBundle/Account \
--destination=../my-crud-frontend/src/entities/Incremental Generation
When the API schema changes, create a new JSON version that inherits your customizations instead of starting from scratch.
# Create v1 based on v0 — re-fetches API data, merges your changes.json
./index.js gen:json \
--entity=AccountingBundle/Account \
--bundleCrud=phprCrud \
--baseUrl=https://demo.phpreaction.com/open-api/v3 \
--fromVersion=v0What happens internally:
- Loads
v0/data.jsonandv0/changes.json - Fetches fresh metadata from the API
- Merges your
v0customizations into a newv1/changes.json - Writes updated raw metadata to
v1/data.json
Custom field selections, ordering, validation rules, and all other changes.json settings are preserved automatically across versions. Only fields that no longer exist in the API are removed.
Version Management
List Versions
# JSON versions
./index.js listJsonVersions --entity=AccountingBundle/Account
# TSX versions
./index.js listTsxVersions --entity=AccountingBundle/AccountPin to a Specific JSON Version
./index.js gen:tsx \
--entity=AccountingBundle/Account \
--jsonVersion=v1 \
--bundleCrud=phprCrudCheck What Changed Between Versions
./index.js check:json \
--entity=AccountingBundle/Account \
--version=v1Preview & Validate Changes
Always preview and validate before generating TSX.
Preview
Shows what each changes.json section will produce without writing any files:
./index.js preview:changes \
--entity=AccountingBundle/Account \
--version=v0Example output:
LISTING FIELDS
✔ selected: id, name, status, createdAt (4 fields)
✖ hidden: internalId, slug
FORM FIELDS
General: name, description, type (3 fields)
Pricing: price, priceSpecial (2 fields)
✖ excluded (MANY_TO_MANY): tags, categories
FILTER FIELDS
✔ defaults: status, createdAt
✔ range: createdAt, priceValidate
Checks every field name in changes.json against the actual API data:
./index.js validate:changes \
--entity=AccountingBundle/Account \
--version=v0Reports invalid references:
✖ formFields.sections.General → "nonExistentField" not found in API data
✖ filterFields.all → "oldFieldName" removed from API
✔ listingFields: all 4 fields validCache Management
Cache Locations
config/
├── fields/{Bundle}/{Entity}.json ← form/all fields
├── showFields/{Bundle}/{Entity}.json ← detail page fields
├── listingFields/{Bundle}/{Entity}.json ← list view fields
└── requiredFields/{Bundle}/{Entity}.json ← required constraintsCache Modes
Cache flags are mutually exclusive — use only one per command.
# Always fresh — fetch from API even if cache exists
./index.js gen:json --entity=Bundle/Entity --generateFromApi ...
# Smart — use cache if available, fallback to API
./index.js gen:json --entity=Bundle/Entity --generateFromCache ...
# Cache only — update cache files, skip generation
./index.js gen:json --entity=Bundle/Entity --generateCacheOnly ...Clear Cache
# Clear everything
rm -rf config/fields/* config/showFields/* config/listingFields/* config/requiredFields/*
# Clear one bundle
rm -rf config/fields/AccountingBundle/Error Logs
Batch operations write structured logs automatically:
config/logs/
├── errorLogs/
│ ├── error-summary.log ← quick overview
│ └── {Entity}-error.json ← full detail per entity
└── successLogs/
└── success-summary.log# View summary
cat config/logs/errorLogs/error-summary.log
# Find errors for a specific bundle
grep "AccountingBundle" config/logs/errorLogs/error-summary.logAfter batch operations the terminal prints:
================================================================================
PROCESSING SUMMARY
================================================================================
✅ Successfully processed: 145 entities
❌ Failed: 5 entities
- BillBundle/Bill Connection timeout
- InvoiceBundle/Invoice API error 500
📁 Detailed logs: ./config/logs/errorLogs/
================================================================================