Configuration
Application、Database、Execution、Journal、Logging、Diagnostics、Retentionの設定責務を確認する。
Installed Applicationは責務別のPHP Configをconfig/に置きます。Frameworkは存在する既知Fileだけを読み、各Fileは配列、またはEnvironmentを受け取って配列を返すClosureを返します。
| File | Responsibility |
|---|---|
app.php |
Build Artifact、Application Service Provider、Application Command |
auth.php |
Optional Session Authentication ConfigurationとService Provider |
database.php |
Default/Named Doctrine DBAL ConnectionとFramework Store |
operations.php |
Build-time Discovery RootとOptional Operation Provider |
execution.php |
Worker ID、Lease、Heartbeat、Grace、Supervision |
journal.php |
Observed JSONL JournalのPathとDelivery Mode |
logging.php |
Application/Framework相関LogのJSONL Backend |
diagnostics.php |
Local Diagnostics ViewerのEnable GateとLoopback Address |
frontend.php |
Generated TypeScript ESMのApplication Root内Output |
middleware.php |
Global PSR-15 HTTP Middlewareの登録順 |
retention.php |
Payload、Journal、Outcome、Dead Letter、Idempotency Recordの保持期間、Policy、Actor |
Environment
既定のSkeleton/Installed Applicationはbootstrap/app.phpでwithEnvironmentFile()を明示し、FrameworkがProcess Environmentを優先してOptional .envを一度だけSnapshotします。Applicationが独自LoaderやSecret Managerを使う場合は解決済み文字列をwithEnvironment($environment)へ渡し、そのPackageをApplication Direct Dependencyとして管理します。
SecretをConfig Sourceへ直書きせず、Process Manager、Container Runtime、Deployment PlatformからEnvironmentとして渡してください。Productionは.env Fileを必須としません。
ConfigではGlobalな$_ENVやgetenv()を直接読みません。Readonly Snapshotから必要な値だけを型付きで取得します。
use BlackOps\Application\Environment;
return static fn (Environment $env): array => [
'name' => $env->string('APP_NAME', 'BlackOps App'),
'port' => $env->positiveInt('APP_PORT', 8080),
'debug' => $env->bool('APP_DEBUG', false),
'optional_label' => $env->optionalString('APP_LABEL'),
];
string()、int()、positiveInt()、bool()は値が未定義でDefaultもない場合に起動を拒否します。整数はCanonicalな10進表現、Booleanは大文字小文字を区別しないtrue/falseと1/0だけを受理します。定義済みの不正値をDefaultへ置き換えません。ErrorにはVariable名と期待型だけを含め、Raw Valueを表示しません。
Config DirectoryはwithConfiguration()で検証します。File読込とClosure評価はcreate()まで遅延し、全Closureへ同じ最終Environment Snapshotを一度だけ渡します。したがってwithEnvironment()とwithConfiguration()はどちらを先に呼んでも同じ結果です。Environment自体はCompiled ContainerやManifestへ保存されません。
Operations
return [
'discovery' => [dirname(__DIR__) . '/app/Feature'],
'providers' => [],
];
Discovery Rootは存在する絶対Directoryです。Application-aware BuildとOperation ListだけがSourceを探索します。Composer PackageやApplication外Sourceを追加する場合だけOperation Providerを使います。
Status参照PolicyはOperation DiscoveryではなくApplication ServiceとしてBindingします。
use App\Security\ApplicationOperationStatusAuthorizer;
use BlackOps\Status\OperationStatusAuthorizer;
$services->autowire(
OperationStatusAuthorizer::class,
ApplicationOperationStatusAuthorizer::class,
);
Bindingがない場合、Frameworkは常にDenyする実装を使い、GET /operations/{operationId}をSafe 404にします。QuickstartのSame-origin実装はLocal Exampleです。ProductionではTenant/Resource PolicyをApplicationが所有します。
Build Artifact
use BlackOps\Application\Environment;
return static fn (Environment $env): array => [
'build' => [
'application_build_id' => $env->string('APP_BUILD_ID', 'local'),
'operation_manifest' => dirname(__DIR__) . '/var/build/operations.php',
'http_manifest' => dirname(__DIR__) . '/var/build/http.php',
'frontend_manifest' => dirname(__DIR__) . '/var/build/frontend.php',
'command_manifest' => dirname(__DIR__) . '/var/build/commands.php',
'container' => dirname(__DIR__) . '/var/build/container.php',
'container_class' => 'CompiledContainer',
'container_namespace' => 'App\\Generated',
],
];
Operation Manifest、HTTP Manifest、Frontend Contract Manifest、Command Manifest、Containerは同じBuild IDで作成します。Command Manifest Schema 2はSymfony Application Commandのcommandsと、#[ConsoleCommand] Operationのoperation_commandsを分離して保持します。command_manifestを省略した既存Applicationでは、Containerと同じDirectoryのcommands.phpを使います。Production HTTP/Worker RuntimeはFrontend/Command Contractを読みません。ProductionはBackend Artifact不足、Format不正、Build ID不一致時に起動を拒否し、Source DiscoveryへFallbackしません。
Application Command
return [
'command_discovery' => [dirname(__DIR__) . '/app'],
'services' => [App\ApplicationServiceProvider::class],
'commands' => [],
];
command_discoveryは存在する絶対DirectoryのListです。欠落または空Listでは自動Discoveryを行いません。重複する実Pathは一度だけ走査し、Application Rootやvendor/を暗黙に追加しません。走査はbuild:compileだけで実行し、HTTP、Worker、通常のlistではSourceへ戻りません。
Symfony #[AsCommand]付きの具象Commandだけを発見します。Command ConstructorはBuild時に実行せず、Compiled ContainerへAutowired Public Serviceとして登録します。Interface DependencyはservicesのService ProviderでBindingしてください。Providerが同じService IDを明示登録した場合は、その定義が自動登録より優先されます。
commandsは従来どおりCommand Instanceまたは引数なしで生成できるClassを明示追加します。Discoveryと明示登録が同じClassなら明示登録を優先します。Framework、Discovery、明示登録のCanonical Name/Alias衝突はCase-sensitiveに拒否します。旧blackops:*名はFramework予約ではありません。
Session Authentication
php blackops make:authが生成するOptional config/auth.phpも同じEnvironment Snapshotを一度だけ受け取ります。Registration有効化、Session TTL、Touch Intervalを型付きで検証し、auth.servicesをapp.servicesの後へMergeします。FileがないApplicationではSession Capabilityを登録しません。KeyとDefaultは環境を設定するを参照してください。
Frontend Generation
use BlackOps\Application\Environment;
return static fn (Environment $env): array => [
'output' => dirname(__DIR__) . '/resources/js/blackops',
];
config/frontend.phpはOptionalで、欠落時も上記Pathを使います。OutputはApplication Root配下の絶対Directoryだけを許可し、Application Root自身、Filesystem Root、Repository外Path、Symlinkを拒否します。設定できるのはOutputだけで、Credential、Base URL、Authentication、CSRF Token、Runtime Fetchはここへ保存しません。
frontend:generateとfrontend:checkはBuild済みFrontend Contractを読みます。GenerateはNon-marker Directoryを上書きせず、Temporary Treeを検証後にAtomic Replaceします。CheckはRead-onlyで、Fresh 0、Missing/Drift 1、Invalid 2を返します。Generated resources/js/blackops/はApplication Sourceではなく、Quickstartでは.gitignore対象です。
生成Root index.tsはcreateBlackOpsClient()と全Operation/型をExportします。FactoryへBase URL、SvelteKit Server event.fetchまたはGlobal Fetch、Default Header、Credential Modeを一度Bindingし、各HTTP Operationをblackops.CreateOrder.fetch()の形で呼べます。Call単位にはHeader、Credential、Abort Signalを渡し、Mutationの.fetch()/.toRequest()だけは専用idempotencyKeyも受理します。
Base URL、Credential、Fetch、Abort Signal、DeadlineはPHP ConfigやGenerated Manifestへ保存しません。FactoryはServer Requestごとに作り、Browser向けGlobal Singletonにしないでください。MutationのIdempotency Keyは検証済みHeaderとして送信され、Backendは認証・認可後にKeyのScope/FingerprintをClaimして同じ副作用の再実行を抑止します。
Database
use BlackOps\Application\Environment;
return static fn (Environment $env): array => [
'default' => 'app',
'connections' => [
'app' => [
'driver' => 'pdo_pgsql',
'host' => $env->string('POSTGRES_HOST'),
'port' => $env->positiveInt('POSTGRES_PORT'),
'dbname' => $env->string('POSTGRES_DB'),
'user' => $env->string('POSTGRES_USER'),
'password' => $env->string('POSTGRES_PASSWORD'),
],
'analytics' => [
'driver' => 'pdo_pgsql',
'url' => $env->string('ANALYTICS_DATABASE_URL'),
],
],
'framework' => [
'connection' => 'app',
'schema' => $env->string('BLACKOPS_SCHEMA', 'blackops'),
],
];
defaultとframework.connectionはconnections内のNameを参照します。通常のRepositoryはDefault Doctrine\DBAL\ConnectionをConstructor Injectionできます。複数Databaseを選ぶServiceはBlackOps\Database\DatabaseManagerをConstructor Injectionし、$databases->connection('analytics')で明示的に選びます。ConnectionはNameごとに生成され、同じNameは同じInstanceを再利用します。
#[Transactional]のDefaultとNamed ConnectionもこのSnapshotに対してBuild時に検証します。この検証はConnection Nameだけを使い、Databaseへの接続やCredentialのBuild Artifactへの保存を行いません。AOP Proxyはbuild.containerと同じDirectoryのaop/へ自動生成されるため、利用者向けの追加Config Keyはありません。
After Commit Callbackの失敗通知をApplication監視基盤へ送る場合は、BlackOps\Database\AfterCommitFailureReporterをService Providerで登録します。未登録時はFramework Default ReporterがPSR-3/Monolog経由で標準ErrorへService、Method、存在するOperation/Attempt/Correlation/Causation IDだけを記録します。Callback引数、Throwable Message/Trace、Database CredentialはDefault Logへ展開しません。
HTTP、Worker、Migration、Outcome、Retentionはframework.connectionと安全なPostgreSQL Identifierであるframework.schemaを使用します。Framework StoreとDefaultが同じNameならApplication ServiceとFramework Storeは同じConnection Instanceを共有します。Build ArtifactにはConnection ParameterやCredentialを保存せず、Build CommandもDatabaseへ接続しません。
従来の単一Connection形式も互換Shorthandとして受理し、一つのDefault/Framework Connectionへ正規化します。
return [
'connection' => ['driver' => 'pdo_pgsql'],
'schema' => 'blackops',
];
Deferred Worker
use BlackOps\Application\Environment;
return static fn (Environment $env): array => [
'worker' => [
'id' => $env->string('BLACKOPS_WORKER_ID', 'worker-1'),
'lease_seconds' => $env->positiveInt('WORKER_LEASE_SECONDS', 30),
'heartbeat_seconds' => $env->positiveInt('WORKER_HEARTBEAT_SECONDS', 10),
'grace_seconds' => $env->positiveInt('WORKER_GRACE_SECONDS', 20),
'continue_after_handler_failure' => $env->bool('WORKER_CONTINUE_AFTER_HANDLER_FAILURE', false),
],
];
execution.worker.idはClaimのLease Ownerと、Journalへ記録するWorker System Actorの両方に使います。Actor TypeはFrameworkがsystemへ固定します。同じProcess内のMain ConnectionとHeartbeat ConnectionはWorker IDを共有しますが、DBAL Connection Instanceは分離されます。
Deferred Operationの受付ActorはTransport Contextへ維持されます。WorkerがAttemptを開始すると、origin/authorization Actorは受付時のまま、execution Actorだけがexecution.worker.id/systemへ置き換わります。Worker用の別Actor設定はありません。
Framework WorkerのOperation Retryは固定既定値です。最大3 Attempt、初期1秒、倍率2.0、最大60秒、Jitter 20%で、config/execution.phpに回数やBackoffを変更するKeyはありません。変更が必要な場合だけCustom Worker AdapterへSupervisionPolicy実装を構成します。outbox_relay.max_attemptsはOutbox再配送の上限であり、Operation Retryとは別の契約です。
Observed Journal
return [
'jsonl' => [
'enabled' => true,
'path' => dirname(__DIR__) . '/var/log/journal.jsonl',
'delivery' => 'best_effort',
],
];
enabled=trueでは絶対Path、書込可能な既存Parent Directory、best_effortまたはrequiredを指定します。FrameworkはDirectoryを作らず、Sensitive Projection後のRecordだけをJSONLへ追記します。
Application Logging
return [
'backend' => [
'driver' => 'jsonl',
'stream' => dirname(__DIR__) . '/var/log/application.jsonl',
'channel' => 'blackops',
'minimum_level' => 'info',
],
];
Canonical Keyはdriver、stream、channel、minimum_levelです。Phase 14のDriverはjsonlだけで、Fileがない場合はphp://stderr/blackops/infoを使います。streamはphp://stderr、php://stdout、絶対Local File Pathのみを受け付け、Relative Path、任意PHP Wrapper、Network URIを拒否します。
FrameworkはConfigをHTTP/Worker Process構成時に一度だけ検証し、RequestやLog RecordごとにFileや$_ENVを再読込しません。無効なDriver/Stream/Levelは起動時にFail-fastします。起動後のOpen/Write FailureはBest-effortで吸収し、元のOperation、Journal、HTTP Response、Worker Loopを変えません。Directory作成、Permission、Rotation、Disk Capacity、RetentionはApplication/運用の責務です。
Local Diagnostics Viewer
return [
'viewer' => [
'enabled' => true,
'bind' => '127.0.0.1',
'port' => 8082,
],
];
Framework既定はenabled=false、127.0.0.1:8082です。QuickstartはLocal利用のためだけtrueにします。Commandの明示実行とEnable Gateの両方が必要で、Non-loopback Bindは設定エラーです。ViewerはCanonical Storeをそのまま表示せず、operation:inspectと同じSafe Diagnostics Projectionを使います。
HTTP Middleware
return [
'http' => [
App\UserInterface\Http\Middleware\RequestIdMiddleware::class,
BlackOps\Http\Authentication\AuthenticationMiddleware::class,
],
];
httpはPSR-15 MiddlewareのService IDまたはClass名を、外側から内側の順で並べたListです。同じEntryを複数回登録できません。Frameworkは順序を変更せず、数値Priorityも使用しません。
ClassがService Providerで未登録の場合、Build時にPSR-15 Middlewareであることを検証してAutowired Public Serviceへ登録します。Constructor InterfaceのBindingや具象Instanceが必要なMiddlewareは、app.phpのService Providerで同じService IDを登録してください。Providerの明示登録が自動登録より優先されます。
File欠落または空Listでは、Operation HTTP Handlerを直接実行します。存在しないService IDやPSR-15でないServiceはBuildまたはHTTP Runtime起動時に安全なErrorとして拒否します。
QuickstartはApplicationServiceProviderでApplication固有AuthenticatorをPublic ContractへBindingし、Framework MiddlewareをGlobal Pipelineへ登録します。
// config/app.php
return [
'services' => [App\ApplicationServiceProvider::class],
];
// config/middleware.php
return [
'http' => [BlackOps\Http\Authentication\AuthenticationMiddleware::class],
];
QuickstartのSampleTokenAuthenticatorはSAMPLE_API_TOKENをConstructorで一度だけ読み、RequestごとにはEnvironmentを参照しません。未設定、空文字、空白だけの値はRuntime構成Errorとして拒否し、既知のDefault TokenへFallbackしません。Local値は.env.exampleだけで提供します。Production Applicationは認証方式とSecret Sourceを選び、CredentialではなくActorRefだけをFrameworkへ渡します。
BootstrapのLoading BoundaryはApplication Bootstrap、実行CommandはBlackOps CLIを参照してください。
Outbox relay
Deferred Outbox配送はconfig/execution.phpのexecution.outbox_relayで設定します。Relay IDは必須で、その他は安全な既定値(batch_size=50、lease_seconds=60、heartbeat_seconds=10、grace_seconds=20、max_attempts=8、initial_backoff_seconds=1、max_backoff_seconds=300、poll_interval_milliseconds=1000)を使用します。HeartbeatはLeaseより短く、初期Backoffは最大値以下でなければなりません。