This repository contains the UNA PHP application and the NEO frontend monorepo as neo/ subfolder.
/
├── ... # UNA PHP application
├── tests/ # UNA PHP unit and integration tests
├── modules/ # UNA modules
├── tools/ # Agent MCP tools (see tools/AGENTS.md)
├── ...
└── neo/ # NEO frontend monorepo
├── apps/
│ ├── expo/ # Expo / React Native mobile application
│ └── next/ # Next.js web frontend
├── packages/ # Shared frontend packages
├── package.json
└── ...
These apply to UNA PHP (inc/, modules/, studio/, template/, and install or update SQL). They do not apply to neo/.
strlen, substr, strpos, strrpos, strtolower, strtoupper, substr_replace) on it. Use get_mb_len, get_mb_substr, get_mb_replace, bx_mb_strpos, and bx_mb_substr_replace from inc/utils.inc.php.CREATE, ALTER, or other schema change that runs when a page or service loads.*Db or *Query class. Do not put queries in a module, template, form, page, grid or other classes.*.html file and is rendered with parseHtmlByName. Do not build markup as strings in PHP.BxDol*, BxBase*, BxTempl*) are autoloaded. Do not guard them with class_exists, bx_import, or require. Custom modules classes need to be explicitly loaded with bx_import.BxDolModuleQuery.BxDolModule::getInstance('bx_posts'), BxDolService::call('bx_posts', ...), new BxPostsModule) without checking if module is installed BxDolModuleQuery::getInstance()->isEnabledByName('bx_posts').getParam only with a name that exists in sys_options. Declare the option in that module's install SQL before reading it.upgrade/files/. That folder records past releases. Do not put new migrations there.active_api in modules/system/install/sql/enable-app-pages.sql (page blocks, including their config_api) and modules/system/install/sql/enable-app-menus.sql (menu items) for core, for modules use modules/boonex/*/install/sql/enable-app.sql files. Do not set it in install.sql, enable.sql, or other common install and enable scripts.Before adding or changing a launcher tile (studio/template/images/icons/wi-*.svg, modules/**/template/images/icons/std-icon.svg), read .agents/skills/studio-icons/SKILL.md.
Run UNA PHPUnit inside the php service from docker compose. That container is on the unanet network and reaches MariaDB at the host name stored in the installed site (mysql). PHPUnit is plugins/bin/phpunit after composer install (dev dependencies included). The site must already be installed (inc/header.inc.php present). Start the stack with docker compose up -d first.
From the repository root:
Unit tests:
docker compose exec -w /opt/una php ./plugins/bin/phpunit -c tests/phpunit.xml --testsuite Units
Integration tests:
docker compose exec -w /opt/una php ./plugins/bin/phpunit -c tests/phpunit.xml --testsuite Integration
One test class or method (--filter matches the class or method name):
docker compose exec -w /opt/una php ./plugins/bin/phpunit -c tests/phpunit.xml --filter TestName
Integration tests read tests/.env when that file exists (cp tests/.env.example tests/.env). Otherwise they use the installer defaults. A case skips an account that is not installed. JUnit output is written to logs/junit.xml.
These apply to changes in UNA PHP (inc/, modules/, studio/, template/, tests/, and install or update SQL). They do not apply to a PR that only changes neo/.
Before opening the pull request:
query tool in tools/db.php (see tools/AGENTS.md) before opening the pull request.The pull request description must include the database migration SQL when the change has one. When it has none, say that there is no database migration.
neo/)neo/ is NEO, the Next.js and Expo client for UNA, kept here as a git subtree. Before changing anything under neo/, read neo/AGENTS.md. Claude Code loads it through neo/CLAUDE.md when it opens a file there.
neo/, not from the UNA root.master and open the PR here. Start the title of a NEO-only PR with Neo:..github/workflows/sync-neo.yml pushes on every push to master, and client projects fork it.neo/. Run yarn typecheck and yarn lint in neo/ before you push.una-ci Railway project: service una (UNA) and service neo (the NEO web client, built from neo/ with scripts/railway/neo/). A PR gets pr-<n>.unacms.app (NEO) and api-pr-<n>.unacms.app (UNA); master deploys production. See .github/workflows/ci.yml and scripts/railway/.neo/.agents/skills/una-api/SKILL.md.