infocyph / foundation
Illuminate-style integration foundation for the Infocyph PHP ecosystem.
Requires
- php: >=8.4
- infocyph/console: ^1.0.1
- infocyph/webrick: ^3.2.2
Requires (Dev)
- infocyph/cachelayer: ^2.0.1
- infocyph/dblayer: ^3.0.3
- infocyph/epicrypt: ^1.1.1
- infocyph/otp: ^5.04
- infocyph/pathwise: ^2.5.3
- infocyph/phpforge: dev-main@dev
- infocyph/reqshield: ^2.4.3
- infocyph/talkingbytes: ^1.0.0
- web-auth/webauthn-lib: ^5.3.5
Suggests
- infocyph/cachelayer: Adds Foundation cache stores and CacheLayer-backed authentication.
- infocyph/dblayer: Adds database services, database validation, and persistent authentication storage.
- infocyph/epicrypt: Adds Foundation cryptography and Epicrypt-backed authentication.
- infocyph/otp: Adds OTP-backed multi-factor authentication.
- infocyph/pathwise: Adds the full filesystem service; core application paths work without it.
- infocyph/reqshield: Adds request and application validation services.
- infocyph/talkingbytes: Adds communication and notification services.
- web-auth/webauthn-lib: Adds WebAuthn passkey authentication.
This package is auto-updated.
Last update: 2026-08-01 07:27:30 UTC
README
Foundation is the Infocyph application integration layer.
It does not replace the standalone packages. It gives a host project one place to bootstrap config, providers, routing, auth, cache, database, validation, filesystem paths, and runtime wiring.
Install
composer require infocyph/foundation
The core installation contains Foundation, Console, and Webrick. Feature libraries are direct, optional project dependencies: Foundation does not install unused database, cache, cryptography, filesystem, validation, communication, identifier, OTP, or WebAuthn packages.
Install a feature through the Foundation console:
php infbyte module:install db php infbyte module:install cache php infbyte module:install session php infbyte module:list
These commands install the existing package directly; no Foundation-prefixed
bridge package is created. A successful install also publishes that module's
documented Foundation config from vendor/infocyph/foundation/resources/config
into the host config/ directory. Existing project config is never
overwritten, and the compiled config cache is invalidated after publication.
| Module | Composer package | Published configuration |
|---|---|---|
cache |
infocyph/cachelayer |
config/cache.php |
communication |
infocyph/talkingbytes |
config/communication.php, config/notifications.php |
crypto |
infocyph/epicrypt |
config/security.php |
db |
infocyph/dblayer |
config/database.php |
filesystem |
infocyph/pathwise |
config/filesystem.php |
logging |
Built into Foundation | config/logging.php |
messaging |
Built into Foundation | config/messaging.php |
otp |
infocyph/otp |
None |
passkeys |
web-auth/webauthn-lib |
None |
resources |
Built into Foundation | config/responses.php |
session |
Built into Foundation | config/session.php |
validation |
infocyph/reqshield |
config/validation.php |
Cryptographic policy and adapter options live under security.*; the
configuration filename and keys describe application capabilities rather than
the implementation library. The installed provider supplies its secure
cryptographic profile; Foundation exposes only settings with meaningful
application choices. Authentication remains under auth.*, including
auth.token_secret, while Webrick route signing remains under
router.signed_urls.*. Foundation does not create parallel secrets or URL-
signing configuration.
infocyph/uid is already part of the runtime core through Console. Foundation
still activates identifier services only when the application requests them or
selects a UID-backed identifier driver.
The equivalent direct Composer command remains valid, for example
composer require infocyph/dblayer; use module:install when config should be
published automatically. Remove a direct module with
php infbyte module:remove db. Removal deliberately retains project config
because it may contain application-owned changes.
Expected Project Structure
Your main app should look like this:
project-root/
app/
bootstrap/
providers.php
config/
app.php
auth.php
ids.php
router.php
# Optional module config is published here when installed.
database/
public/
index.php
resources/
routes/
web.php
api.php
auth.php
console.php
schedule.php
workers.php
storage/
cache/
logs/
sessions/
uploads/
tests/
composer.json
Foundation already knows these paths by default:
app/bootstrap/config/database/public/resources/routes/storage/storage/cache/storage/logs/storage/sessions/storage/uploads/
Basic Bootstrap
In public/index.php:
<?php declare(strict_types=1); use Infocyph\Foundation\Foundation; require dirname(__DIR__) . '/vendor/autoload.php'; $app = Foundation::local([ 'base_path' => dirname(__DIR__), ]); // Then hand off to your HTTP entry flow.
Use one of these entry modes:
Foundation::local([...])Foundation::production([...])Foundation::api([...])Foundation::web([...])Foundation::console([...])
Foundation loads .env and .env.local from the project root before evaluating config/*.php, so host apps do not need an external dotenv package just to make $_ENV values available.
Config
Foundation loads configuration in this order:
- Foundation defaults
- preset defaults
config/*.php- inline config passed at boot
That means your app config files override the preset, and inline config overrides both.
Environment files are loaded earlier as part of boot preparation:
.env.env.localconfig/*.php- inline config passed at boot
You can disable env loading or replace the file list with inline app config:
Foundation::web([ 'base_path' => dirname(__DIR__), 'app' => [ 'load_env' => true, 'env_files' => ['.env', '.env.testing'], ], ]);
Example config/app.php:
<?php return [ 'name' => 'My App', 'env' => 'local', 'debug' => true, ];
Example config/auth.php:
<?php return [ 'drivers' => [ 'storage' => 'memory', 'cache' => 'array', 'passwords' => 'native', // native|security 'tokens' => 'simple', // simple|security 'notifications' => 'collect', 'passkey' => 'memory', ], ];
Authentication services are typed and lazy: resolving $app->auth() does not
construct password reset, MFA, passkey, token, authorization, or notification
graphs until their corresponding accessor is called. See
Authentication and authorization for lifecycle,
driver, authorization, and persistent-worker guidance.
Runtime Modes
Choose the runtime explicitly at the entry point:
$web = Foundation::web(['base_path' => __DIR__]); $console = Foundation::console(['base_path' => __DIR__]);
The mode is not inferred from PHP_SAPI, because tests and worker processes can
legitimately execute web behavior under the CLI SAPI.
The web runtime eagerly registers paths, routing, logging, and HTTP services and loads configured route files when booted. The console runtime eagerly registers only filesystem paths. A command activates its optional providers on demand; for example, route-cache commands activate routing without registering the HTTP kernel or loading project routes through the normal web boot sequence.
Calling http() or handle() on a console application fails immediately.
Console integrations likewise require an application created by
Foundation::console().
Console applications receive an explicit command route map:
$manifestPath = $basePath . '/bootstrap/cache/console/commands.php'; $manifest = is_file($manifestPath) ? $manifestPath : null; $commands = $manifest === null ? require $basePath . '/routes/console.php' : []; $console = FoundationConsole::create( applicationFactory: static fn (?string $profile) => Foundation::console([ 'base_path' => $basePath, 'env' => $profile ?? 'local', ]), commands: $commands, commandManifest: $manifest, );
routes/console.php maps command names to command classes. Foundation does not
scan command directories or register application commands implicitly.
When the compiled command manifest exists, the CLI entry point does not load
the project command route file during preflight or dispatch.
Foundation's operational commands, including config:*, route:*,
schedule:*, worker:*, create:*, module:*, migrate:*, db:*,
queue:*, auth:schema:*, session:*, and app:ready, are predefined by
Foundation and must not be redeclared in the application route map.
php infbyte list presents every Foundation-owned command under System.
Application commands are grouped by the first namespace segment in their route
name, so reports:daily appears under reports; an unnamespaced application
command appears under Application. Listing remains a preflight operation and
does not boot Foundation or construct commands.
Foundation keeps its application stubs in the package and writes an artifact only when its generator is invoked:
php infbyte create:controller Admin/User php infbyte create:command Reports/Daily php infbyte create:service Billing php infbyte create:job SendReceipt php infbyte create:middleware EnsureTenant php infbyte create:policy Invoice php infbyte create:provider Billing php infbyte create:repository User php infbyte create:repository Reporting/Person --table=reporting.people php infbyte create:worker Queue php infbyte create:event UserRegistered php infbyte create:listener SendWelcomeEmail php infbyte create:enum OrderStatus php infbyte create:exception BillingFailed php infbyte create:interface BillingGateway php infbyte create:trait FormatsMoney php infbyte create:class Services/ReportBuilder php infbyte create:test Http/UserAccess
Browser Sessions
Browser sessions are built into Foundation but are not enabled globally. First publish the documented configuration:
php infbyte module:install session
Select the web preset for session plus CSRF protection, or add session
alone when CSRF is not applicable:
use Infocyph\Foundation\Session\BrowserSession; use Infocyph\Webrick\Response\Response; use Infocyph\Webrick\Router\Facade\Router; Router::group( middleware: ['session', 'csrf'], callback: static function (): void { Router::post('/preferences', static function (BrowserSession $session): Response { $session->put('theme', 'dark'); return Response::json(['saved' => true]); }); }, );
The array, file, cache, and database stores are supported. Cache-backed
storage and locking require the CacheLayer module; database storage and schema
commands require DBLayer:
php infbyte session:schema:install php infbyte session:schema:status php infbyte session:prune --limit=1000
Stateless routes do not construct the session provider, manager, store, lock, or CSRF middleware. See Browser sessions for the security model and full lifecycle.
Names may use / or \ namespace separators. Conventional suffixes are added
once, so both User and UserController produce UserController.php.
Repositories extend Foundation's thin DBLayer bridge, infer a plural
snake_case table (UserRepository becomes users), and accept --table for
an explicit table or schema-qualified identifier. The DB module must be
installed before repository generation.
Jobs and listeners are plain invokable application classes; Foundation does not
impose a queue backend or event dispatcher on them.
Generators reject absolute paths and traversal, preserve existing files by
default, and accept --force for an explicit atomic replacement. Generated
commands, providers, and workers still require explicit registration in
routes/console.php, bootstrap/providers.php, and routes/workers.php
respectively; generators do not silently change application composition.
Scheduled commands are defined only in routes/schedule.php, which returns a
Schedule or a callable receiving one. schedule:run, schedule:work,
schedule:list, schedule:cache, and schedule:clear are built in.
optimize compiles the schedule when that route file exists, and
optimize:clear removes it.
use Infocyph\Console\Scheduling\Schedule; return static function (Schedule $schedule): void { $schedule ->command('reports:daily') ->arguments(['--tenant=acme']) ->dailyAt('02:00') ->onOneServer(leaseSeconds: 180) ->withoutOverlap(leaseSeconds: 180) ->timeout(120) ->memoryLimit(256); };
Dynamic worker definitions live in routes/workers.php as
name => WorkerProvider::class. A provider supplies a safe argv command,
WorkloadProbe, and WorkerOptions; worker:run <name> supervises it and
worker:list inspects the map without autoloading its providers. Locks are
resolved lazily through CacheLayer only for locked schedule entries, supervised
workers, or command execution policies with overlap controls. File, Redis,
Valkey, Memcached, and PDO (including SQLite's file-backed fallback) use one
common locking path.
Providers
Register extra app providers in bootstrap/providers.php:
<?php return [ 'common' => [ App\Providers\SharedServiceProvider::class, ], 'web' => [ App\Providers\WebServiceProvider::class, ], 'console' => [ App\Providers\ConsoleServiceProvider::class, ], ];
Each provider must implement Foundation's ServiceProviderInterface.
common providers run in both modes; use it only for services genuinely needed
by both paths. Flat provider lists are not accepted: every provider must be
assigned deliberately to common, web, or console.
Routes
Foundation auto-loads these files when present:
routes/web.phproutes/api.phproutes/auth.php
Inside a route file, use the injected $router.
Example routes/web.php:
<?php $router->get('/', fn () => 'Hello from Foundation');
Runtime Directories
Your app should have these writable runtime directories:
storage/storage/cache/storage/logs/storage/sessions/storage/uploads/
Local preset can auto-create them. Production should create them ahead of time with correct permissions.
What To Configure First
For a new app, usually start in this order:
base_pathconfig/app.phpconfig/auth.php- Install required modules so their config is published
bootstrap/providers.phproutes/*.php
Production Notes
- Do not keep memory auth storage in production.
- Do not keep simple token drivers in production.
- Configure real database connections before using
dblayer. - Configure real cache stores before using
cachelayer. - Configure
notifications.auth.transportbefore using thetalkingbytesnotification driver. - If you use WebAuthn, set
auth.webauthn.rp_idandauth.webauthn.origin. - Set a unique
auth.token_secretof at least 32 bytes. - Install the auth schema before enabling DBLayer-backed authentication:
$app->boot()->db()->authSchema()->install();
Use the built-in report as part of deployment health checks. It validates the production configuration and reports cache, database, auth-schema, and runtime directory issues without exposing secrets:
$report = $app->boot()->readinessReport(); if (!$report['production_ready']) { throw new RuntimeException('Foundation is not ready for production.'); }
DBLayer diagnostics remain opt-in. Enable telemetry only where query-shape aggregation is required, and use native execution plans explicitly:
DB::enableTelemetry(); $plan = DB::explain('SELECT * FROM users WHERE id = ?', [$id]); $shapes = DB::queryShapeReport(minimumMs: 5.0, limit: 20);
EXPLAIN ANALYZE executes the query; leave analyze false unless runtime
execution is intentional. QueryBuilder also exposes DBLayer's joinSub(),
leftJoinSub(), rightJoinSub(), and explain() methods directly.
Integrated Capabilities
Foundation remains an integration layer: the standalone packages own their domain behavior while Foundation supplies application configuration, container registration, facades, and HTTP-aware composition.
- ArrayKit: environment, array-shape, and data helpers
- CacheLayer: local, database, Redis, Valkey, Memcached, SQLite, and tiered caches
- DBLayer: connections, repositories, execution plans, query-shape telemetry, and auth-schema installation
- Epicrypt: production password, token, and encryption-backed auth services
- Intermix: application container, providers, scopes, and invocation
- Omnibus and Console: events, queues, retries, scheduled messages, commands, schedules, and bounded worker supervision
- OTP and WebAuthn: TOTP, HOTP, OCRA, recovery codes, MFA, and passkeys
- Pathwise and Webrick: filesystem operations, uploads, ranged/conditional downloads, HTTP responses, routing, and route caches
- ReqShield: request schemas and database-backed validation rules
- TalkingBytes: email, HTTP, gRPC, signatures, inbound processing, and DKIM helpers
- UID: UUID, ULID, Snowflake, and related identifier generation
Documentation
Start with the Foundation documentation index. The guides cover lifecycle and package ownership, configuration, authentication, browser sessions, migrations and seeding, Omnibus integration, JsonDispatch resources, logging, testing, modules, and deployment operations.
The files under resources/config/ are the canonical configuration reference:
every publishable key is documented beside its default with its type,
predefined values, and an example for open-ended values.
Release Process
Run the release guard before tagging a release:
composer ic:release:guard
Foundation follows semantic versioning. Release tags are the public package
versions; update CHANGELOG.md, run the guard in CI, then create the signed
tag and publish from that immutable commit.
See SECURITY.md for private vulnerability reporting and CONTRIBUTING.md
for the development workflow.
Quick Start Goal
The intended flow is simple:
- Require
infocyph/foundation - Create the standard app folder structure
- Point Foundation at your project root with
base_path - Add config files
- Add providers
- Add route files
- Boot the app from
public/index.php
That is the main host-project shape Foundation expects.