Laravel 12 + Inertia + React (TypeScript) ERP/SaaS platform. Core business logic (auth, settings, billing, the Media Library, etc.) lives in this repo; every feature module is a separate Composer package.
| Module | Alias | Repository | Composer package |
|---|---|---|---|
| account | Accounting | zerp-pk/account | zerp/account |
| aiassistant | AI Assistant | zerp-pk/aiassistant | zerp/aiassistant |
| budget-planner | Budget Planner | zerp-pk/budget-planner | zerp/budget-planner |
| calendar | Calendar | zerp-pk/calendar | zerp/calendar |
| contract | Contract | zerp-pk/contract | zerp/contract |
| double-entry | Double Entry | zerp-pk/double-entry | zerp/double-entry |
| form-builder | Form Builder | zerp-pk/form-builder | zerp/form-builder |
| goal | Financial Goal | zerp-pk/goal | zerp/goal |
| google-captcha | Google Captcha | zerp-pk/google-captcha | zerp/google-captcha |
| google-meet | Google Meet | zerp-pk/google-meet | zerp/google-meet |
| hrm | HRM | zerp-pk/hrm | zerp/hrm |
| jitsi | Jitsi Meet | zerp-pk/jitsi | zerp/jitsi |
| landing-page | CMS | zerp-pk/landing-page | zerp/landing-page |
| lead | CRM | zerp-pk/lead | zerp/lead |
| paypal | Paypal | zerp-pk/paypal | zerp/paypal |
| performance | Performance | zerp-pk/performance | zerp/performance |
| pos | POS | zerp-pk/pos | zerp/pos |
| product-service | Product & Service | zerp-pk/product-service | zerp/product-service |
| quotation | Quotation | zerp-pk/quotation | zerp/quotation |
| recruitment | Recruitment | zerp-pk/recruitment | zerp/recruitment |
| slack | Slack | zerp-pk/slack | zerp/slack |
| stripe | Stripe | zerp-pk/stripe | zerp/stripe |
| support-ticket | Support Ticket | zerp-pk/support-ticket | zerp/support-ticket |
| taskly | Project | zerp-pk/taskly | zerp/taskly |
| telegram | Telegram | zerp-pk/telegram | zerp/telegram |
| timesheet | Timesheet | zerp-pk/timesheet | zerp/timesheet |
| training | Training | zerp-pk/training | zerp/training |
| twilio | Twilio | zerp-pk/twilio | zerp/twilio |
| webhook | Webhook | zerp-pk/webhook | zerp/webhook |
| zoom-meeting | Zoom Meeting | zerp-pk/zoom-meeting | zerp/zoom-meeting |
Each module is referenced in this repo's composer.json as a local
path repository pointing at a sibling directory (see "Get the
module packages" below) — composer install symlinks them into
vendor/zerp/<module>/.
- PHP 8.2+ (tested with 8.5) with the
pdo_mysqlextension enabled - Composer
- Node.js + npm
- MySQL/MariaDB server running
Check pdo_mysql is enabled:
php -m | grep pdo_mysqlIf missing, enable it in /etc/php/php.ini (or your distro's
conf.d) with extension=pdo_mysql, or pass it ad hoc:
php -d extension=pdo_mysql artisan ....
The CLI memory_limit also needs to be reasonably high (this app's
class map is large) — 512M is safe:
php -d memory_limit=512M artisan ....
Every module in the table above needs to be cloned as a sibling
of this repo, matching the layout its composer.json path
repositories expect:
some-folder/
├── zerp/ (this repo)
└── ZerpPackages/
├── hrm/
├── account/
├── pos/
└── ... (one directory per module, matching composer.json)
This is required for every installation method below, including Docker.
Pick one of three ways to get a running instance.
The fastest path: one command runs migrations, seeds the database, and walks you through which modules to enable.
composer install
npm install
cp .env.example .env # if .env doesn't already existSet your database credentials in .env (DB_HOST, DB_DATABASE,
DB_USERNAME, DB_PASSWORD) and make sure APP_URL matches the port
you'll serve on (e.g. http://localhost:8000). Generate a key if
.env doesn't already have one: php artisan key:generate.
php artisan app:install --force
php artisan storage:linkapp:install prompts for a module preset (Full Suite, HR Only,
Sales & CRM, or a Custom selection picker) — see
config/module-presets.php for the bundle definitions. For scripted/
non-interactive installs, skip the prompt with --preset=<name> or
--modules=account,hrm,pos (comma-separated package_name slugs); with
neither flag and no TTY it defaults to installing everything.
app:install runs migrate:fresh, which drops all tables.
Only run it on a fresh/disposable database.
Then skip to "Run the app" below.
Same as Option A up through generating APP_KEY, then run the steps
app:install would otherwise do yourself — useful if you already have
data and don't want migrate:fresh to wipe it:
php artisan migrate
php artisan db:seed --force # also registers every module into add_ons via PackageSeeder
php artisan storage:link
touch storage/installed # marks the app as installed, skips the /install wizardNo local PHP/Composer/Node/MySQL setup needed — everything runs in
containers. Still requires the sibling ZerpPackages/ layout above,
since the image is built with the parent directory as build
context (so both zerp/ and ZerpPackages/ are visible to
composer install inside the container).
cp .env.example .env
docker compose up -d --build
docker compose exec app php artisan app:install --force
docker compose exec app php artisan storage:linkAdd -it to the exec command above (docker compose exec -it app ...)
to get the interactive module picker; without it, app:install has no
TTY and installs every module by default. To choose modules without a
TTY, pass --preset=<name> or --modules=account,hrm,pos instead.
The app is served at http://localhost:8000. MySQL and Redis run as
their own containers (db, redis); docker-compose.yml wires
.env's DB_HOST/REDIS_HOST to the container service names
automatically.
(Skip this if you used Option C — Docker already runs everything.)
Backend (Laravel):
php artisan serve --port=8000Frontend (Vite, HMR dev server):
npm run devVisit http://localhost:8000.
Default seeded company/super-admin account:
- Email:
company@example.com - Password:
1234
could not find driveron any DB command —pdo_mysqlisn't loaded; see Prerequisites above.Allowed memory size exhaustedrunningartisan tinkeror other commands — bump CLI memory limit:php -d memory_limit=512M artisan ....- Redirected to
/installin the browser after already installing — thestorage/installedmarker file is missing; either re-runphp artisan app:install --forceor, if the DB is already migrated/seeded and you just need to skip the wizard,touch storage/installed(only do this if you're sure the DB is in a complete, installed state, including module registration). - Plans page shows no features for any plan —
db:seed(whichapp:installruns) registers every module found underpackages/local/*andvendor/zerp/*into theadd_onstable viaPackageSeeder. If it's still empty, confirm the module packages are actually present undervendor/zerp/(see "Get the module packages" above —composer installsymlinks them from the siblingZerpPackages/directory; if that directory is missing, nothing gets installed) and re-runphp artisan db:seed --forceorphp artisan app:install --force.
See CONTRIBUTING.md.
See SECURITY.md for how to report a vulnerability.
MIT.