ubixsys / ubixcore-skeleton
Skeleton host project for uBixCore: composer create-project ubixsys/ubixcore-skeleton <name>
Package info
github.com/ubixsys/ubixcore-skeleton
Language:Shell
Type:project
pkg:composer/ubixsys/ubixcore-skeleton
Requires
- php: ^8.5
- ubixsys/ubixcore: ^0.2
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.2
- rector/rector: ^2.1
- slevomat/coding-standard: ^8.19
- squizlabs/php_codesniffer: ^3.13
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
The starting point for a project built on uBixCore: thin entry points, one example app, the quality gate wired to the rules that ship in the framework, and nothing from the framework committed in your repo.
composer create-project ubixsys/ubixcore-skeleton acme cd acme php bin/ubix list # the uBixCore CLI, plus any App\Console\Command\* you add APP_NAME=HelloApi php -S 127.0.0.1:8080 -t public curl 127.0.0.1:8080/health # {"status":"ok","app":"HelloApi"} php bin/ubix code:review # phpcs + phpstan (level max) + phpunit
Layout
composer.json / composer.lock requires ubixsys/ubixcore - commit the lock, it pins the framework your images are built from
bin/ubix CLI entry point (yours; lists the command namespaces to scan)
public/index.php web entry point (yours; serves app/<APP_NAME>)
app/HelloApi/src/ Dependencies.php (PHP-DI), Middleware.php, Routes.php - one folder per deployable app
app/HelloJs/ React Router v8 frontend template (React 19 + TypeScript) - see its own README
php/App/ your code, PSR-4 root App\ (rename: composer.json autoload + the namespace)
tests/ App\Tests\ - every concrete class needs a test case (tests/PhpunitTestCasesTest.php enforces it)
templates/default/ Latte templates
sql/migrations/ bin/ubix migrate:*
phpcs.xml phpstan.neon phpunit.xml point at the rules in vendor/ubixsys/ubixcore
Dockerfile / Dockerfile_Test runtime image (APP_NAME per Deployment) and the lint-and-test image layered on it
.gitlab-ci.yml bin/deploy.sh bin/promote.sh bin/lib/notify.sh the pipeline: build → lint-and-test → deploy → promote → notify
bin/vault-ci-setup.sh one-time uBixVault setup for the pipeline; docs/ci-setup.md lists every variable and secret
.env.example copied to .env on create-project; never commit .env
Ubix\ is the framework's namespace: never put code there. Your namespace is
whatever composer.json maps (App\ by default); the framework finds your
commands, apps and tests through that map.
Secrets: use uBixVault
uBixCore is built to take its credentials from uBixVault,
the uBix family's secrets manager, not from files in the repo. The framework's
bootstrap resolves database credentials from Vault on every start when
VAULT_ADDR is set and exports them to the environment before the SQL layer
reads them; the .env file is a local-development fallback only and is never
committed.
VAULT_ADDR=https://vault.example.com # turns the hook on
VAULT_TOKEN=... # local dev / CI - or, in Kubernetes:
VAULT_K8S_ROLE=acme-api # service-account auth, no token on disk
VAULT_DB_KV_PATH=app/db # KV v2 secret holding read_/write_username + _password
VAULT_TEST_DB_KV_PATH=app/test-db # KV v2 secret holding the unit-test connection
The secret's keys read_username, read_password, write_username,
write_password become MYSQL_READ_* / MYSQL_WRITE_*. CI tokens, webhooks
and API keys follow the same pattern: store them in Vault, read them in the
pipeline with a read-only token, and keep .env empty of anything you would
not paste into a chat.
VAULT_TEST_DB_KV_PATH does the same for the PHPUnit connection, and its secret
carries the whole connection — host, port, database, username,
password — not just the credentials. A test database's host and name are not
sensitive, but splitting them across Vault and a file is how the password ends up
back in the file "to keep them together". With it set, vendor/bin/phpunit needs
no TEST_MYSQL_* values on disk at all; without it, the .env fallback still
works for a machine with no Vault access. Vault is read after .env and wins, so
a stale local value cannot quietly outrank it.
CI/CD
The pipeline is included. Before its first green run it needs a runner, read
access to the private uBixCore registry, three GitLab CI variables and a few
uBixVault secrets — all listed, in order, in docs/ci-setup.md.
Adding things
- An endpoint: a controller under
php/App/Controller/extendingUbix\Controller\AbstractController(alias itController), one line inapp/<App>/src/Routes.php, a test undertests/Controller/. - A CLI command:
php/App/Console/Command/<Name>Command.phpextendingUbix\Console\Command\AbstractCommand;bin/ubixalready scansApp\Console\Command. - A second PHP app: copy
app/HelloApiand deploy it with its ownAPP_NAME. - A frontend: copy
app/HelloJs, change every identity field its README lists, and add it toJS_APPSin.gitlab-ci.yml. Deleteapp/HelloJsif this project has no frontend. - Upgrading uBixCore:
composer update ubixsys/ubixcore, commit the lock.
Developing against a local uBixCore checkout
While hacking on the framework and your project together, point Composer at the checkout instead of GitLab (symlinked, so edits are live):
composer config repositories.ubixcore path ../ubixcore
composer require "ubixsys/ubixcore:*@dev"
Do not commit that repositories entry; drop it (and re-require the released
constraint) before pushing.