Release Notes
Support Policy
Sukarix is currently supported for PHP 8.4+.
Released versions
- Unreleased
- v0.5.0 - 2026-09-14
- v0.4.0 - 2026-08-16
- v0.3.2 - 2026-08-04
- v0.3.1 - 2026-07-18
- v0.2.0 - 2025-01-20
- v0.1.0 - 2024-06-14
Unreleased
Nothing yet.
v0.5.0
🚀 Features & Improvements
- Version Number: 0.5.0
- Release Date: 2026-09-14
- General Overview: Adds JSON API building blocks (stateless routes,
ApiAction, CORS, health probes, capability tokens), request correlation with structured JSON logging, encryption at rest for stored secrets, AMQP messaging, a session contract applications can implement themselves, environment-variable configuration overrides, and privilege discovery from the action directory — alongside CSRF, database, mail and PHP 8.5 compatibility fixes. The release is additive — no existing API changed, so upgrading from v0.4.0 requires no application changes.
🐛 Bug Fixes
- CSRF Validation: Could not succeed for
PUT,DELETEandPATCHrequests, nor for any request sending a JSON body. See CSRF. - Records blank after an insert (
sukarix):Model::insert()now reads the record back when the insert left it blank. PostgreSQL identity columns carry nonextvaldefault, so Fat-Free does not recognise them as auto increment; the reload Cortex runs itself then filters on the identifier the record held before the insert, matches nothing, and leaves the whole record empty in memory — defaults and timestamps included. Any schema created for PostgreSQL 10 or later is affected. See Databases & Cortex. smtpSend()return type (sukarix): The method declaredbooland returned the message id on success, which understrict_typesthrows aTypeErrorin any caller that reaches a successful send. It returns a boolean, assend()already promised. The framework’s own suite never caught it because no test reached the success path; one was added.- Stateless prefixes could not be turned off (
sukarix):SECURITY.stateless.prefixesfell back to the/apidefault whenever it was declared empty, because an.inientry with nothing after the equals sign reads asnulland the lookup used?:. An application whose API relies on the session — one authenticating with a JWT session, for instance — had no way to say so. A declared key now wins even when empty. See Session. - Test suite aborted part-way (
sukarix): The test bootstrap registered no injector aliases, so the first scenario constructing anActiondied resolvingaccessand took the rest of the run with it. Two of the three test groups never executed: the suite reported 71 passing tests where 165 existed. - MailSender date format (
sukarix): Thedatetemplate variable usedstrftime()-style specifiers, whichdate()doesn’t support, so emails rendered literal%A/%d/%Binstead of a date. Fixed. - Pluggable session at boot (
sukarix):Boot::$sessionwas typed against the concreteSessionclass, so an application registering its ownSessionInterfaceimplementation failed with aTypeErrorbefore the first request. It is typed against the interface now. - Error pages (
sukarix): The defaultONERRORhandler includedtemplates/error/*.phtmlrelative to the working directory; it now resolves them through theUIsearch paths, so error pages render whatever directory the process was started from.
Changes
- CSRF Token Transport (
sukarix): The token is now read from theX-Csrf-Tokenheader, then fromREQUEST, and compared withhash_equals(). It was read from the verb hive, which Fat-Free populates forGET,POSTandCOOKIEonly, so the other verbsAction::beforeroute()enforces were always rejected. - CSRF Token Lifetime (
sukarix): The token stays valid untilcsrf.expiryinstead of being consumed on first use, andgenerateToken()reuses a live one, so pages holding several forms or issuing successive writes keep working. Thecsrf_usedsession key is gone. - CSRF Exemptions (
sukarix): New$csrfExemptproperty onSukarix\Actions\Actionfor endpoints reached by external systems, which hold no session and must authenticate their caller by their own means. - Data & Filesystem Helpers (
sukarix): NewSukarix\Utils\DataUtils,Sukarix\Utils\FileSystemUtilsandSukarix\Utils\CommandExecutor, extracted from duplicated code in bbb-lb and BBBAnalytiX. See Data & Filesystem Helpers. - Session Contract (
sukarix): NewSukarix\Core\SessionInterface, declaring what the framework itself requires of a session —cleanupOldSessions(),set(),get(),isLoggedIn(),getRole()andvalidateToken().Sukarix\Core\Sessionimplements it andHasSessiontypes its property against it, so an application can register its own implementation under thesessionalias without inheriting the database-backed one, and without its own static analysis reporting every call as undefined. The contract is deliberately the framework’s requirement rather than the full surface of the shipped session; a test asserts that every method Sukarix calls on a session is declared in it, so the two cannot drift. See Session. - Uniqueness Checks (
sukarix): NewModel::excludeId(), adding an identifier exclusion to a filter and dropping the clause when there is no identifier to exclude. Written by hand,... and id != ?with a null identifier evaluates toNULLin SQL, which makes the whole condition unsatisfiable — so the uniqueness check passes for every record while one is being created, and duplicates are accepted. See Databases & Cortex. - Query Return Type (
sukarix):Model::find()declaresDB\CortexCollection|false. Cortex documents an array, socastAll()and the other collection methods read as errors in static analysis and in an editor. - Sender Identity (
sukarix): The configuredmailer.from_nameis now put on the message. A relay such as Postal authenticates as one identity and sends as another, so the account, the address and the name beside it are three separate settings; without the name the mail arrived showing a bare address. See Emails. - Unreachable SMTP Servers (
sukarix):MailSenderchecks that the server accepts a connection before handing the message to the transport, logs the failure and returnsfalse. The transport aborts the whole request when the server cannot be reached — not an exception the application can catch — so a mail server outage took the request with it. The wait is configurable withmailer.smtp.timeout, two seconds by default. - Exception Reports (
sukarix): Reports are sent undermailer.debugger_name, which defaults toApplication Debugger, so an inbox receiving reports from several applications can tell them apart. The snooze marker moved frommd5toxxh128and no longer relies on suppressed filesystem calls. - Environment Variables (
sukarix): New[environment]configuration section mapping a variable name to the setting it stands in for, applied after the configuration is loaded. A setting that differs per host — and especially a secret — no longer has to live in a committed file. A variable that is unset or empty leaves the configured value alone. See Configuration. - Declared Privileges (
sukarix): NewSukarix\Utils\PrivilegeUtils, reading the privileges an application declares from the action classes that carry them. A privilege is the first two namespace segments below the root, so classes nested deeper share the privilege of the group above them. It reads the directory rather than the composer class map, where an action added after the autoloader was dumped is missing — and its privilege then silently disappears from the role matrix, leaving a route nobody can be granted. See Authorisation System. - ORM Deprecations (
sukarix):ikkez/f3-cortexstill callsReflectionProperty::setAccessible(), which PHP 8.5 deprecates and Tracy escalates into a fatal error on every ORM query. The bootstrap now dropsE_DEPRECATEDfrom the forced error level after Fat-Free and Tracy have set theirs. Setorm.mask_deprecations = falseonce Cortex is fixed. - Staging Environment (
sukarix): AddedEnvironment::STAGING, recognised alongsidedevelopmentandproduction. See Framework Variables. - Request Correlation & JSON Logging (
sukarix):Bootmints or forwards anX-Request-Idheader and stamps every log line with it.log.jsonswitchesLogWriterto structured JSON output. See Logging. - Building JSON APIs (
sukarix): NewApiActionbase class,Corshelper andHealth\Probeendpoints, plus Bearer auth and form-encoded body support onAction. See Building JSON APIs. - Capability Tokens (
sukarix): NewSukarix\Security\CapabilityToken::issue()/verify()for HMAC-signed, short-lived Bearer tokens. See Building JSON APIs. - CSRF Bounce Message (
sukarix): A failed CSRF check now also sets acsrf_bouncesession message. See CSRF. - Secrets at Rest (
sukarix): NewSukarix\Security\SecretBox, a libsodium secretbox wrapper for encrypting credentials before they’re stored. See Encrypting Secrets at Rest. - Mail Tracking Hooks (
sukarix): NewSukarix\Mail\Track, theon.failure/on.ping/on.jumpcallbackssmtp.iniwires into delivery-failure and open/click tracking. See Emails. - AMQP Messaging (
sukarix): NewSukarix\Messaging\CommandPublisherinterface with anAmqpPublisher(RabbitMQ) and aRecordingPublisherfor tests. See Messaging. - Uploads & Locale Negotiation (
sukarix): NewReceiver::uploadImageBase64()andReceiver::upload()with MIME sniffing and size limits, andI18n::negotiateLocale()forAccept-Languageheaders. See File Upload and Translation / i18n. - Tooling (
sukarix,statera): PHPStan 2, Rector 2 and PHPInsights 2.14 with a cleancomposer check; Statera runs on php-code-coverage 14 and declares it as a runtime requirement, socomposer coverageworks out of the box. The unusedrespect/validationand the retiredphpddare gone. - CLI Toolbox (
cli):sukarix.shfollowsAPP_ENVandstaging, detects the installed PHP-FPM service, and cleans sessions through the framework’sSessionsCleanaction. See CLI toolbox. - Skeleton Application (
application): The landing page shows the 0.5.0 features, gradient titles and a comparison with Fat-Free, Slim, Laravel and Symfony, in all 16 languages. - Documentation: Rewrote the CSRF page. Added Data & Filesystem Helpers, Building JSON APIs, Encrypting Secrets at Rest and Messaging. Expanded Databases & Cortex with the insert read-back, uniqueness checks and the query return type; Session with the session contract and session-free routes; Emails with sender identity, unreachable servers and exception reports; Configuration with the
[environment]section and the new settings; Authorisation System with privilege discovery; Logging with request correlation and structured JSON logging; File Upload with the new receiver methods; and Translation / i18n with locale negotiation. Refreshed the feature list, the CLI toolbox page and the stale claims a release audit turned up.
v0.4.0
🚀 Features & Improvements
- Version Number: 0.4.0
- Release Date: 2026-08-16
- General Overview: Adds a Redis-backed queue service for pipeline workloads, a
HasQueuebehaviour to consume it, and optional coloured console logging. The release is additive — no existing API changed, so upgrading from v0.3.2 requires no application changes.
Changes
- Queue Service (
sukarix): NewSukarix\Queuenamespace providingQueueService, a Redis-backed FIFO queue for passing work between pipeline stages. It adds membership-based deduplication (pushing an already-queued payload is a no-op) and per-item attempt counters on top of a Redis list. Enqueue and dequeue are executed as Redis Lua scripts, so a worker terminated mid-operation can never leave the list and the membership set disagreeing — an item is either fully queued and tracked, or neither. The queue counts attempts but intentionally owns no retry policy: deciding when a failing item is retried or parked stays with the application. See Queues. - Queue Logging (
sukarix): NewQueueProgressLoggeremitting structured queue events (start, progress, completion, throughput, batch progress, per-item add/remove, warnings and errors) with a machine-parsable context array. Item previews are generic by design — an array is reported asarray[3], never with its values — so payload contents never leak into logs. Applications can route queue telemetry elsewhere by registering a subclass under thequeue.progress_loggerInjector alias; a service that does not extendQueueProgressLoggeris rejected with an\UnexpectedValueException. - HasQueue Behaviour (
sukarix): New behaviour trait exposing the resolved queue service as a typed$queueServiceproperty. Resolution is strict by design: constructing a consumer without a registeredqueueservice throws a\LogicExceptionnaming the class, and a service that does not extendQueueServiceis rejected with an\UnexpectedValueException. This surfaces a misconfiguration at boot rather than at the first queue call, where a null member access would point at the wrong place. - Console Logging (
sukarix):LogWritergained an optional standard-output handler enabled withlog.console = true, intended for CLI applications. Whenbramus/monolog-colored-line-formatteris installed the output is coloured per level, otherwise a plain stream is used. The file handler remains active, so console output is added rather than substituted. See Logging. - Redis Connection Timeout (
sukarix): The queue honoursredis.timeout(default 2 seconds) and throws\RedisExceptionwhen the connection cannot be established, so a misconfigured worker fails immediately instead of part-way through a run. - Documentation: Added a Queues page. Rewrote the Behaviours page to list every available trait with the property it injects and its visibility, documenting that
HasAccessandHasEventsexpose aprivateproperty that subclasses cannot read. Corrected its example, which called a non-existent$this->log->write()instead of the$this->loggerMonolog instance theLogWritertrait actually provides. Expanded Logging with the logger API,log.leveland the newlog.consolesetting. Added Queues to the feature list.
v0.3.2
🐛 Bug Fixes
- Version Number: 0.3.2
- Release Date: 2026-08-04
- General Overview: Bug-fix release addressing cache, JSON encoding, and documentation accuracy issues found via static analysis.
Changes
- HasCache::remember() (
sukarix):Cache::get()returnsfalseboth on a cache miss and when the stored value is legitimatelyfalse, soremember()could never recognise a cached falsy value as a hit and recomputed it on every call. Switched toCache::exists()to distinguish a real hit from a miss. The accompanyingResponseTestwas rewritten to exercise the trait directly (the previous test asserted hardcoded literals against themselves) and a regression test for the falsy-value case was added. - Model::__construct() PHPDoc (
sukarix): Corrected the@paramtags, which inaccurately claimed$db,$tableand$fluidmust always benull. They mirror Cortex’s constructor and acceptobject,stringandboolrespectively; the wrong annotations caused PHPStan to flag the subsequent null-check as dead code. - TestScenario::postJsonData() (
statera): The method declared astringreturn type butjson_encode()can returnfalseon failure, which understrict_typeswould throw aTypeErrorinstead of a clear JSON error. Now passesJSON_THROW_ON_ERROR, matching the convention already used elsewhere in the class. - TestScenario::run() cleanup (
statera): Removed an orphaned@var CodeCoverage $coveragedocblock and its accompanyingusestatement left over from a prior refactor; they no longer corresponded to any variable in the method.
v0.3.1
🚀 Features & Improvements
- Version Number: 0.3.1
- Release Date: 2026-07-18
- General Overview: Statera migration, trait initialization refactor, cursor-based pagination, cache helpers, and open-source readiness.
Changes
- PHPUnit Removal: Dropped
phpunit/phpunitandphpunit/php-code-coveragefromrequire-devand removedphpunit.xml.dist. The framework’sInjectorTestwas converted from a PHPUnitTestCaseto a StateraTestScenariousingexpect()assertions. Code coverage is now provided transitively by Statera’s ownphpunit/php-code-coveragedependency. - Statera Dependency: Added
sukarix/stateratorequire-devso the framework uses its own testing kit for its test suite. Statera remains an optional, standalone package for applications. - Test Runner: Added
tools/statera.phpand test infrastructure (tests/src/Test/,tests/src/Suite/) to run the framework’s tests via Statera. - Statera Package: Declared the previously-undeclared
sukarix/sukarixruntime dependency insukarix/statera’scomposer.json(Statera usesSukarix\Utils\CliUtilsandSukarix\Utils\Time). - Trait Initialization: Moved
Processor::initialize()fromTailored::instance()to class constructors. EachTailoredsubclass must now callProcessor::instance()->initialize($this)in its constructor. TheHelperbase class does this automatically. - LogWriter: Added
initLogger()backward-compatible alias forinitLogWriter(). - TestCase: Removed
finalkeyword to allow subclassing in application test suites. - Action: Added
Processorimport. Made$view,$argv,$headerAuthorization, and$templatesDirnullable to prevent uninitialized typed property errors. - MailSender:
smtpSend()andgenerateId()changed fromprivatetoprotectedfor extensibility. - Assets: Constructor now calls
parent::__construct()for proper trait initialization. - TestScenario:
loadResult()handles missing template files gracefully. - Cursor Pagination: Added
Response::cursor()for cursor-based API pagination — stable under concurrent inserts, efficient on large datasets. Returns{ field, limit, has_more, next }structure. - Cache Remember: Added
HasCache::remember()for get-or-set cache pattern andHasCache::forget()for invalidation. - Paginate Fix:
Response::paginate()now castspagestoint(wasfloatfromceil()). - Open Source: Added
AGENTS.mdwith contribution guidelines and AI usage transparency across all repositories.
v0.2.0
🚀 Features
- Version Number: 0.2.0
- Release Date: 2025-01-20
- General Overview: Added CSRF protection, enhanced session management, and improved validation.
v0.1.0
🚀 Introduction
- Version Number: 0.1.0
- Release Date: 2024-06-14
- General Overview: First version of the Sukarix Framework.