Current Status
Push has a first-class CLI command group for local payload validation, Firestore-backed token resolution, and guarded send attempts.
Use the CLI for repeatable QA checks that do not deliver notifications, plus explicitly labeled simulated sends. Non-dry-run sends require credentials and produce per-target HTTP results. Real FCM delivery is still not claimed until an approved live project/device fixture proves it.
Commands
push validate --payload payload.json
push validate --payload payload.json --project demo-firestruct
push resolve-tokens --source token-source.json
push resolve-tokens --collection users --field "push.tokens.*" --path-pattern "users/*"
push send --payload payload.json --confirm --dry-run
push send --payload payload.json --confirm --access-token "$GOOGLE_ACCESS_TOKEN"
The push module also supports selected-module routing:
module select push
run validate --payload payload.json
run resolve-tokens --source token-source.json
Payload File
push validate --payload reads a JSON object. Common fields:
{
"targetMode": "token",
"tokens": ["abcDEF1234567890"],
"title": "Hello",
"body": "World",
"data": {
"kind": "smoke"
},
"dryRun": true
}
Validation returns JSON with:
valid- validation
errorsandwarnings messagePreviewdeliveryMode: "validation-only"sendImplemented: false
Validation covers local request shape and payload safety only. It reports APNS badge, priority, push type, expiration, and background-update issues; Android priority, TTL, notification priority, visibility, and color issues; Webpush TTL, urgency, and link issues; invalid notification image/icon/badge URLs; reserved FCM data keys; oversized data fields; and the FCM HTTP v1 4096-byte message limit.
No FCM send is attempted by push validate.
Send Boundary
push send requires a selected project and --confirm. Non-dry-run delivery is
rejected for read-only projects, and production non-dry-run delivery requires
--production-confirm SEND.
Without --authorization or --access-token, push send does not contact FCM.
It returns deliveryMode: "simulated-send", per-token status: "simulated",
fcmAPIAttempted: false, liveDeliveryAttempted: false, and task output.
With credentials, push send uses the FCM HTTP v1 API. --dry-run sends
validate_only: true and reports deliveryMode: "fcm-http-v1-dry-run".
Non-dry-run credentialed sends report deliveryMode: "fcm-http-v1-send" and
must not be claimed as release evidence until an approved live FCM project and
device/token fixture are recorded.
Token Source File
push resolve-tokens --source reads a JSON object:
{
"collection": "users",
"pathPattern": "users/*",
"tokenFieldPath": "push.tokens.*",
"limit": 500
}
Resolution queries the selected Firebase project with Firestruct's Firestore
query service, then passes the real returned documents into
PushTokenSourceResolverService. Output includes resolved tokens, matched
document paths, invalid token candidates, and logs.
Still Live-Only
Actual FCM delivery proof remains live-only. Release runbooks may not claim real delivery support until an approved FCM project/device fixture captures the API response and cleanup or token invalidation notes.
Verification
Covered by:
swift test --filter FirestructCLIIntegrationTests/testPushValidateUsesPayloadJSONAndSelectedModuleRouting
swift test --filter FirestructCLIIntegrationTests/testCLICommandsRoundTripAgainstFirebaseEmulators
The focused validation test reads real valid and invalid payload files, validates
locally, checks warnings, platform/data/URL errors, message preview JSON, and
verifies selected-module run validate. It also verifies push send rejects
missing --confirm, returns labeled simulated per-token results with task
counters for a confirmed no-credential dry-run, rejects read-only non-dry-run
delivery, and requires --production-confirm SEND for production non-dry-run
sends.
The emulator round-trip writes token documents into a real Firestore emulator,
resolves tokens via a JSON token-source file, reports invalid candidates, and
verifies selected-module run resolve-tokens.
Source Anchors
Sources/FirestructCLIKit/PushCommand.swiftSources/FirestructCore/PushTestingService.swiftSources/FirestructCore/PushTokenSourceResolverService.swift