Single-app Pinoox project for Pinoox. Your project root is the app — no apps/ folder, no manager.
composer create-project pinoox/app my-shop
cd my-shop
pinx migrate
pinx devWhile pinx dev is running, open /~inspector on the same local server for Pinx Inspector. Inspector is installed from Packagist as pinoox/pinx-inspector in require-dev and is not needed in production.
New projects include a minimal .env:
APP_ENV=development
DB_CONNECTION=devdbUse .env.example as the full reference when you want to override defaults or connect MySQL/PostgreSQL/SQLite.
DevDB is installed from Packagist as pinoox/devdb in require-dev, so local projects can run migrations and models immediately without setting up a database server. For production, set a real database connection and install dependencies without dev packages.
The template ships with default identity com_pinoox_app / Pinoox App so it runs immediately after install. To use your own package name, run pinx init --package=com_vendor_app --force or edit app.php, platform/, namespaces under Controller/ / Router/, and routes/.
Or with global pinx CLI:
composer global require pinoox/pinx-cli
pinx new my-shop --package=com_acme_shop| Command | Description |
|---|---|
pinx setup |
Migrate platform + app, run seeders |
pinx sync |
Add missing single-app support files |
pinx repair |
Repair this folder so it runs as a Pinx single-app project |
pinx dev |
Local HTTP server (and Vite when configured) |
pinx inspector |
Standalone local browser dashboard for database tables, schema, routes, logs, and runtime health |
pinx migrate |
App migrations |
pinx build |
Build ~pinx/export/{package}/*.pinx for platform install |
pinx release |
Bump version + build signed-ready package |
pinx doctor |
Check PHP, paths, and layout |
my-shop/
├── app.php ← package name & pinx settings
├── Controller/ Model/ routes/ theme/
├── resource/ ← app icon & static assets (default icon included)
├── platform/ ← local host + deploy layer (excluded from .pinx build)
│ ├── apps.config.php
│ ├── app-router.config.php
│ ├── domain.config.php
│ ├── pinoox.config.php
│ └── launcher/ ← bootstrap + dev server router
├── config/ ← app-level config only (app.config.php, services, …)
├── bin/pinx
└── vendor/pinoox/pincore
| Layer | Path | Examples |
|---|---|---|
| Pincore (framework) | vendor/pinoox/pincore/config/ |
database, paths — read-only |
| Project deploy + dev host | platform/ |
apps.config.php, app-router.config.php, domain.config.php, launcher/ |
| Your app | config/ |
app.config.php, query_route.config.php, custom *.config.php |
platform/ is not included in pinx build output — it is only for local development and routing on a single-app checkout. Production installs use the full Pinoox platform's own config.
PINOOX_PROJECT_CONFIG_PATH=platform in .env points pincore at this folder (default when platform/ exists).
pinx buildorpinx release --sign- Upload the
.pinxfile to a full Pinoox installation - Install via Manager → Applications
pinx build packages your app for installation on a full Pinoox platform. It applies system defaults automatically (excludes vendor/, bin/, .env, dev tooling, …) and bundles only third-party Composer requires when present. Override in app.php only when needed:
'build' => [
'exclude' => ['my-private-notes/'], // extra paths only
'composer' => false, // opt out of composer bundling
],When working inside the pinoox/pinoox repository:
cd packages/app
composer config repositories.pinx-cli path ../pinx-cli
composer require pinoox/pinx-cli:@devThis template includes .github/workflows/release.yml. When you publish a GitHub Release, CI builds a .pinx install package and attaches it to that release.
Release asset name: {repo-name} v{version}.pinx — for example app v1.0.0.pinx on pinoox/app. If version-name in app.php already starts with v, it is not duplicated.
Suggested flow:
# 1. Bump version locally (optional)
pinx release --yes
# 2. Commit app.php version change
git add app.php
git commit -m "chore: release 1.0.1"
# 3. Tag and push
git tag v1.0.1
git push origin main --tags
# 4. GitHub → Releases → PublishMake sure version-name in app.php matches the release before you tag. CI does not bump versions — it builds from the tagged commit.
Pinoox signs .pinx packages with Ed25519 (PHP sodium). A signed build adds signature.json inside the archive. On install, the platform can verify integrity and block updates from a different publisher.
php vendor/bin/pincore pinx:sign-keygen com_pinoox_app
# optional: --key-id=pinoox:appDefault key path for this layout:
pinx/sign.key.json ← never commit this file
Add to .gitignore:
/pinx/sign.key.json
Publish the public key (from sign.key.json) in your README or docs. Keep the secret key local and in CI secrets only.
'pinx' => [
'type' => 'app',
'minpin' => 3,
'sign' => [
'enabled' => true,
'key' => 'pinx/sign.key.json',
'key_id' => 'pinoox:app',
'require' => false,
],
],Then build locally:
pinx build --sign --yes
# or
pinx release --sign --yesStore the full contents of sign.key.json as repository secret PINX_SIGN_KEY, then extend the release workflow:
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: zip, mbstring, sodium
- name: Prepare signing key
if: ${{ secrets.PINX_SIGN_KEY != '' }}
run: |
mkdir -p pinx
printf '%s' "${{ secrets.PINX_SIGN_KEY }}" > pinx/sign.key.json
- name: Build pinx package
run: php bin/pinx build --yes --sign --output=${{ steps.meta.outputs.artifact }}If pinx.sign.enabled is true in app.php, --sign is optional — the build signs automatically when the key file exists.
| Level | Setting | Meaning |
|---|---|---|
| Default | PINX_VERIFY=true |
Verify signature when signature.json is present |
| Official market | trusted_keys in pinx.config.php |
Only allow known publisher public keys |
| Strict | PINX_REQUIRE_SIGNATURE=true |
Reject unsigned packages |
Example for a trusted publisher on a full Pinoox platform:
// vendor/pinoox/pincore/config/pinx.config.php
'trusted_keys' => [
'com_pinoox_app' => 'BASE64_PUBLIC_KEY_FROM_sign.key.json',
],- Integrity — manifest and payload were not tampered with after signing.
- Publisher continuity — updates must come from the same key (stored in
.pinx/identity.jsonon the installed app).
Without trusted_keys, anyone can ship a signed package with their own key. For official releases, publish your public key and register it on target platforms.
- Commit
pinx/sign.key.jsonto a public repository. - Put
secret_keyinapp.php,.env, or workflow logs. - Rotate signing keys without documenting the new
key_idand fingerprint in release notes.