コンテンツにスキップ
BlackOps1.xは試験的なバージョンです。Production Readyは2.xを予定しています。Releases
BlackOps
Esc
navigateopen⌘Jpreview
このページの内容

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.phpwithEnvironmentFile()を明示し、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な$_ENVgetenv()を直接読みません。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は大文字小文字を区別しないtruefalse10だけを受理します。定義済みの不正値を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.servicesapp.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:generatefrontend: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.tscreateBlackOpsClient()と全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'),
    ],
];

defaultframework.connectionconnections内の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.idsystemへ置き換わります。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はdriverstreamchannelminimum_levelです。Phase 14のDriverはjsonlだけで、Fileがない場合はphp://stderrblackopsinfoを使います。streamphp://stderrphp://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=false127.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のSampleTokenAuthenticatorSAMPLE_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.phpexecution.outbox_relayで設定します。Relay IDは必須で、その他は安全な既定値(batch_size=50lease_seconds=60heartbeat_seconds=10grace_seconds=20max_attempts=8initial_backoff_seconds=1max_backoff_seconds=300poll_interval_milliseconds=1000)を使用します。HeartbeatはLeaseより短く、初期Backoffは最大値以下でなければなりません。