| name | integrate-feedbackkit-firebase |
| description | Integrate sugijotaro/FeedbackKit into an existing SwiftUI Firebase app by adding a FeedbackSheet entry point, a Swift FirebaseFunctions submitter, and a callable Cloud Function named submitFeedback that stores validated feedback in Firestore with a pending status ready for optional AI triage. Use when FeedbackKit submissions show NOT_FOUND, when adding the backend for FeedbackKit, or when wiring FeedbackKit to Firebase. |
| metadata | {"short-description":"Add FeedbackKit backend on Firebase"} |
Integrate FeedbackKit with Firebase
Implement the integration; do not only document it.
Use this workflow when an app already shows FeedbackSheet and needs a working Firebase backend, or when submission fails with not found / FunctionsErrorCode.notFound.
Inspect first
- Read FeedbackKit's current public API instead of guessing initializer or model names.
- Confirm the Firebase project from
GoogleService-Info.plist (PROJECT_ID) or the app's existing Firebase configuration.
- Inspect existing Functions location, language, module system, Node runtime, region, and deployment conventions.
- Inspect current Firestore rules before editing or deploying them.
- Identify the existing settings/help view and Firebase service layer.
- Choose a stable lowercase
appId derived from the host app's bundle identifier or an existing internal routing key. Do not place an app-specific identifier in this reusable skill.
Do not move unrelated Firebase files, replace an existing architecture, or overwrite unrelated security rules.
Function contract
Default when the app has no established convention:
function: submitFeedback
region: asia-northeast1
Swift and Functions must use the same name and region:
Functions.functions(region: "asia-northeast1")
.httpsCallable("submitFeedback")
onCall({ region: "asia-northeast1" }, async (request) => {
});
A mismatch returns not found.
Typical files
Adapt to the repository. For a new TypeScript backend:
firebase/firebase.json
firebase/functions/package.json
firebase/functions/package-lock.json
firebase/functions/tsconfig.json
firebase/functions/src/index.ts
firebase/functions/src/submitFeedback.ts
firebase/firestore.rules
<AppTarget>/Features/Feedback/FeedbackSubmissionService.swift
Keep FeedbackKit UI-only. Firebase code belongs to the host app.
Functions runtime
Use Node 22 or the repository's newer Firebase-supported runtime. Do not downgrade an existing backend.
A minimal package commonly includes:
{
"type": "module",
"engines": { "node": "22" },
"main": "lib/index.js",
"scripts": {
"build": "tsc",
"lint": "tsc --noEmit",
"deploy": "npm run build && firebase deploy --only functions"
},
"dependencies": {
"firebase-admin": "^14.1.0",
"firebase-functions": "^7.2.5"
},
"devDependencies": {
"@types/node": "^22.15.0",
"typescript": "^5.8.3"
}
}
Use current compatible versions and commit the lockfile. CI should use npm ci.
Generated files and .gitignore
Before installing dependencies or building Functions, inspect the repository's applicable .gitignore files and add any missing generated-file entries. For the common repository layout above, the root .gitignore should normally contain:
firebase/functions/node_modules/
firebase/functions/lib/
firebase-debug.log*
firestore-debug.log*
ui-debug.log*
If the Functions directory has its own .gitignore, use paths relative to that directory instead:
node_modules/
lib/
Adapt the paths to the host repository and package manager. Do not add duplicate rules when an equivalent pattern such as **/node_modules/ already exists.
Never ignore or delete source and configuration files that must be reviewed or committed, including:
package.json
package-lock.json
pnpm-lock.yaml
yarn.lock
tsconfig.json
src/
firebase.json
firestore.rules
Commit the package-manager lockfile. After dependency installation and every build, run:
git status --short --branch --untracked-files=all
The integration is not complete while node_modules/, lib/, other compiler output, emulator data, or Firebase debug logs appear as untracked files. Add precise ignore rules before reporting completion. Do not use git clean, delete unknown files, or silently remove already tracked generated files; inspect them first and report any migration that needs user approval.
Swift submitter
Create a small service in the host app, for example:
<AppTarget>/Features/Feedback/FeedbackSubmissionService.swift
It should expose an async throws method compatible with FeedbackKit's submission closure and send:
schemaVersion: 1
appId: stable app identifier
category: FeedbackKit category raw value
message: trimmed feedback message
platform: "ios"
appVersion: app marketing version when available
buildNumber: app build number when available
osVersion: OS version when available
locale: current locale identifier when available
Do not send IDFA, device name, email address, Firebase tokens, or persistent device identifiers. Do not log raw feedback in Analytics or application logs.
Present FeedbackKit from the app's existing settings/help UI. Preserve the app's tint and navigation conventions.
Callable Function
Implement submitFeedback with these requirements:
- use Cloud Functions 2nd gen, Firebase Admin SDK, and structured logging;
- do not require App Check by default;
- preserve existing App Check enforcement only when the app already supports it reliably;
- validate the payload as an exact object and reject unknown fields;
- require
schemaVersion: 1;
- validate
appId against a conservative safe-character pattern;
- allow only
bug, featureRequest, feedback, and other;
- trim and require a message of 3 through 2,000 characters;
- validate optional metadata with conservative limits;
- set timestamps on the server;
- return only
{ success: true, feedbackId };
- emit stable
HttpsError codes such as invalid-argument, resource-exhausted, and internal.
Add lightweight server-side rate limiting for anonymous apps. Prefer Firebase Auth UID when available. Otherwise hash the runtime-resolved request address; never store a raw IP address or copy it into the feedback document. Add an expiry timestamp and document Firestore TTL cleanup.
Write:
feedback/{feedbackId}
schemaVersion: 1
appId: string
category: "bug" | "featureRequest" | "feedback" | "other"
message: string
platform: "ios"
appVersion: string | null
buildNumber: string | null
osVersion: string | null
locale: string | null
status: "pending"
processingAttempts: 0
createdAt: server timestamp
updatedAt: server timestamp
status: "pending" is required for the optional automate-feedback-github-issues processor.
Firestore rules safety
Feedback is written by Firebase Admin SDK, so mobile clients do not need direct access. The feedback collections should be server-only:
match /feedback/{document=**} {
allow read, write: if false;
}
match /feedbackRateLimits/{document=**} {
allow read, write: if false;
}
However, Firebase CLI rule deployment replaces the currently deployed Firestore ruleset. Therefore:
- inspect the active rules in the Firebase console or the repository's authoritative rules source;
- merge the feedback blocks into those existing rules;
- preserve every unrelated application rule;
- test the merged rules with the Emulator or Rules Playground;
- deploy Rules separately from Functions.
Do not make firebase deploy --only functions,firestore:rules the default command for an existing project.
Deploy Functions first:
firebase deploy --only functions:submitFeedback
Deploy the reviewed merged Rules separately:
firebase deploy --only firestore:rules
If no authoritative local rules file exists, do not invent a replacement ruleset and deploy it. Leave a clearly marked rules snippet and report that console review is required.
Validation
Before finishing:
- install dependencies with
npm ci or the repository's package manager;
- run TypeScript type-check and build;
- build the iOS app, not only resolve packages;
- submit valid, blank, oversized, malformed, and rapid-repeat payloads through the Emulator when available;
- deploy only the callable Function first;
- submit one item from the app and confirm exactly one
feedback/{feedbackId} document with server timestamps and status: "pending";
- review and merge Firestore rules before any Rules deployment;
- confirm logs contain neither the message nor request address;
- confirm generated dependency and build directories remain ignored and
git status contains only intentional source, configuration, and lockfile changes.
Report exact files changed, Function name and region, Firestore schema, rate-limit behavior, deployment results, and any Firebase project or rules work that still requires console access.
Optional AI and GitHub automation
After storage works, use automate-feedback-github-issues to add:
- Gemini triage through Vertex AI without a Gemini API key;
- structured prioritization and sensitive-data checks;
- semantic and feedback-specific idempotency;
- GitHub App authentication;
- staged automatic GitHub Issue creation.
Keep this as a separate second stage so feedback storage remains reliable when Vertex AI or GitHub is unavailable.
Troubleshooting
not found: Swift name/region does not match the deployed callable, or it is not deployed.
permission-denied: existing auth or App Check enforcement is not satisfied.
resource-exhausted: the rate limit is working.
invalid-argument: payload validation failed.
- feedback remains
pending: the optional processor is absent or failed before claiming it.