Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions skills/firebase-basics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ Please complete these setup steps before proceeding, and remember your progress
```bash
npx -y firebase-tools@latest use --add <PROJECT_ID>
```
- If no: Follow the project creation instructions in [references/firebase-project-create.md](references/firebase-project-create.md).
- If no: Follow these steps to create a new Firebase project from the CLI:
```bash
npx -y firebase-tools@latest projects:create <project-id> --display-name "<display-name>"
```
*Note: The `<project-id>` must be 6-30 characters, lowercase, and can contain digits and hyphens. It must be globally unique.*

# Firebase Usage Principles

Expand All @@ -35,11 +39,11 @@ Please adhere to these principles when working with Firebase, as they ensure rel
3. **Follow Agent Skills for implementation guidance:** Skills provide opinionated workflows (CUJs), security rules, and best practices. Always consult them to understand *how* to implement Firebase features correctly instead of relying on general knowledge.
4. **Use Firebase MCP Server tools instead of direct API calls:** Whenever you need to interact with remote Firebase APIs (such as fetching Crashlytics logs or executing Data Connect queries), use the tools provided by the Firebase MCP Server instead of attempting manual API calls.
5. **Keep Plugin / Agent Skills updated:** Since Firebase best practices evolve quickly, remind the user to regularly check for and install updates to their Firebase plugin or Agent Skills, ensuring you both operate with the latest workflows. Similarly, if you encounter issues with outdated tools or commands, follow the steps below based on your agent environment:
- **Antigravity**: Follow [references/refresh-antigravity.md](references/refresh-antigravity.md)
- **Gemini CLI**: Follow [references/refresh-gemini-cli.md](references/refresh-gemini-cli.md)
- **Claude Code**: Follow [references/refresh-claude.md](references/refresh-claude.md)
- **Cursor**: Follow [references/refresh-cursor.md](references/refresh-cursor.md)
- **Others**: Follow [references/refresh-other.md](references/refresh-other-agents.md)
- **Antigravity**: Follow [references/refresh/antigravity.md](references/refresh/antigravity.md)
- **Gemini CLI**: Follow [references/refresh/gemini-cli.md](references/refresh/gemini-cli.md)
- **Claude Code**: Follow [references/refresh/claude.md](references/refresh/claude.md)
- **Cursor**: Follow [references/refresh/cursor.md](references/refresh/cursor.md)
- **Others**: Follow [references/refresh/other-agents.md](references/refresh/other-agents.md)

# References

Expand Down
11 changes: 0 additions & 11 deletions skills/firebase-basics/references/firebase-project-create.md

This file was deleted.

12 changes: 6 additions & 6 deletions skills/firebase-basics/references/local-env-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ You must be authenticated to manage Firebase projects.
To fully manage Firebase, the agent needs specific skills and the Firebase MCP server installed. Identify the agent environment you are currently running in and follow the corresponding setup document strictly.

**Read the setup document for your current agent:**
- **Gemini CLI**: Review [setup-gemini_cli.md](setup-gemini_cli.md)
- **Antigravity**: Review [setup-antigravity.md](setup-antigravity.md)
- **Claude Code**: Review [setup-claude_code.md](setup-claude_code.md)
- **Cursor**: Review [setup-cursor.md](setup-cursor.md)
- **GitHub Copilot**: Review [setup-github_copilot.md](setup-github_copilot.md)
- **Other Agents** (Windsurf, Cline, etc.): Review [setup-other_agents.md](setup-other_agents.md)
- **Gemini CLI**: Review [setup/gemini_cli.md](setup/gemini_cli.md)
- **Antigravity**: Review [setup/antigravity.md](setup/antigravity.md)
- **Claude Code**: Review [setup/claude_code.md](setup/claude_code.md)
- **Cursor**: Review [setup/cursor.md](setup/cursor.md)
- **GitHub Copilot**: Review [setup/github_copilot.md](setup/github_copilot.md)
- **Other Agents** (Windsurf, Cline, etc.): Review [setup/other_agents.md](setup/other_agents.md)

---
**CRITICAL AGENT RULE:** Do NOT proceed with any other Firebase tasks until EVERY step above has been successfully verified and completed.
22 changes: 21 additions & 1 deletion skills/firebase-data-connect-basics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ dataconnect/
└── mutations.gql # Mutations
```

## Operation Strategies: GraphQL vs. Native SQL

Always default to **Native GraphQL**. **Native SQL lacks type safety** and bypasses schema-enforced structures. Only use **Native SQL** when the user explicitly requests it or when the task requires advanced database features.

| Strategy | When to use | Implementation |
|----------|-------------|----------------|
| **Native GraphQL** (Default) | Almost all use cases. Standard CRUD, basic filtering/sorting, simple relational joins. Requires full type safety. | Auto-generated fields (`movie_insert`, `movies`). Strong typing and schema enforcement. |
| **Native SQL** (Advanced) | PostgreSQL extensions (e.g., PostGIS), window functions (`RANK()`), complex aggregations, or highly tuned sub-queries. | Raw SQL string literals via `_select`, `_execute`, etc. Requires strict positional parameters (`$1`). No type safety. |

## Development Workflow

Follow this strict workflow to build your application. You **must** read the linked reference files for each step to understand the syntax and available features.
Expand All @@ -38,6 +47,11 @@ Write the queries and mutations your client will use. Data Connect generates the
> * **Mutations**: Create (`_insert`), Update (`_update`), Delete (`_delete`).
> * **Upserts**: Use `_upsert` to "insert or update" records (CRITICAL for user profiles).
> * **Transactions**: use `@transaction` for multi-step atomic operations.
>
> **Read [reference/native_sql.md](reference/native_sql.md)** for Native SQL operations:
> * Embedding raw SQL with `_select`, `_selectFirst`, `_execute`
> * Strict rules for positional parameters (`$1`, `$2`), quoting, and CTEs
> * Advanced PostgreSQL features (PostGIS, Window Functions)

### 3. Secure Your App (`connector/` files)
Add authorization logic closely with your operations.
Expand Down Expand Up @@ -75,7 +89,6 @@ If you need to implement a specific feature, consult the mapped reference file:
> **Read [reference/config.md](reference/config.md)** for deep dive on configuration.

Common commands (run from project root):

```bash
# Initialize Data Connect
npx -y firebase-tools@latest init dataconnect
Expand All @@ -90,6 +103,13 @@ npx -y firebase-tools@latest dataconnect:sdk:generate
npx -y firebase-tools@latest deploy --only dataconnect
```

## MCP Tools Available

- `firebase_init` - Initialize Data Connect with `dataconnect` feature
- `firebase_get_sdk_config` - Get Firebase configuration for client apps
- `firebase_get_project` - Get current project information
- `firebase_update_environment` - Set project directory and active project

## Examples

For complete, working code examples of schemas and operations, see **[examples.md](examples.md)**.
163 changes: 163 additions & 0 deletions skills/firebase-data-connect-basics/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,166 @@ mutation GrantRole($userUid: String!, $role: UserRole!)
})
}
```

---

## Native SQL Examples

For scenarios where standard GraphQL cannot express the required database logic, use Native SQL.

### Basic SELECT with field aliasing

```graphql
query GetMoviesByGenre($genre: String!, $limit: Int!) @auth(level: PUBLIC) {
movies: _select(
sql: """
SELECT id, title, release_year, rating
FROM movie
WHERE genre = $1
ORDER BY release_year DESC
LIMIT $2
""",
params: [$genre, $limit]
)
}
```

### Basic UPDATE

```graphql
mutation UpdateMovieRating($movieId: UUID!, $newRating: Float!) @auth(level: USER) {
_execute(
sql: """
UPDATE movie
SET rating = $2
WHERE id = $1
""",
params: [$movieId, $newRating]
)
}
```

### Advanced aggregation with RANK

```graphql
query GetMoviesRankedByRating @auth(level: PUBLIC) {
_select(
sql: """
SELECT
id,
title,
rating,
RANK() OVER (ORDER BY rating DESC) as rank
FROM movie
WHERE rating IS NOT NULL
LIMIT 20
""",
params: []
)
}
```

### UPDATE with RETURNING and Auth Context

```graphql
mutation UpdateMyReviewText($movieId: UUID!, $newText: String!) @auth(level: USER) {
updatedReview: _executeReturningFirst(
sql: """
UPDATE "Reviews"
SET review_text = $2
WHERE movie_id = $1 AND user_id = $3
RETURNING movie_id, user_id, rating, review_text
""",
params: [$movieId, $newText, {_expr: "auth.uid"}]
)
}
```

### Advanced CTE with upserts (atomic get-or-create)

*Note: Data-modifying CTEs are only supported by `_execute`, not `_executeReturning`.*

```graphql
mutation CreateMovieCTE($movieId: UUID!, $userId: UUID!, $reviewId: UUID!) @auth(level: USER) {
_execute(
sql: """
WITH
new_user AS (
INSERT INTO "user" (id, username)
VALUES ($2, 'Auto-Generated User')
ON CONFLICT (id) DO NOTHING
RETURNING id
),
movie AS (
INSERT INTO movie (id, title, image_url, release_year, genre)
VALUES ($1, 'Auto-Generated Movie', 'https://placeholder.com', 2025, 'Sci-Fi')
ON CONFLICT (id) DO NOTHING
RETURNING id
)
INSERT INTO "Reviews" (id, movie_id, user_id, rating, review_text, review_date)
VALUES (
$3,
$1,
$2,
5,
'Good!',
NOW()
)
""",
params: [$movieId, $userId, $reviewId]
)
}
```

### Multi-statement Transactions

Because `mutation` operations are single requests, you can chain multiple `_execute` commands within a `@transaction` to ensure they all succeed or fail together.

```graphql
mutation SafeTransfer($from: UUID!, $to: UUID!, $amount: Float!) @auth(level: USER) @transaction {
deduct: _execute(
sql: "UPDATE accounts SET balance = balance - $3 WHERE id = $1",
params: [$from, $to, $amount]
)
add: _execute(
sql: "UPDATE accounts SET balance = balance + $3 WHERE id = $2",
params: [$from, $to, $amount]
)
}
```

### Use of extensions (e.g. PostGIS for geospatial data)

*Prerequisite:* You must enable the extension on your underlying Cloud SQL instance by connecting to your database as the postgres user and running:
```sql
CREATE EXTENSION IF NOT EXISTS postgis;
```

```graphql
query GetNearbyActiveRestaurants($userLong: Float!, $userLat: Float!, $maxDistanceMeters: Float!) @auth(level: USER) {
nearby: _select(
sql: """
SELECT
id,
name,
tags,
ST_Distance(
ST_MakePoint((metadata->>'longitude')::float, (metadata->>'latitude')::float)::geography,
ST_MakePoint($1, $2)::geography
) as distance_meters
FROM restaurant
WHERE active = true
AND metadata ? 'longitude' AND metadata ? 'latitude'
AND ST_DWithin(
ST_MakePoint((metadata->>'longitude')::float, (metadata->>'latitude')::float)::geography,
ST_MakePoint($1, $2)::geography,
$3
)
ORDER BY distance_meters ASC
LIMIT 10
""",
params: [$userLong, $userLat, $maxDistanceMeters]
)
}
```
*After running the query using a client SDK, the result will be in `data.nearby`.*
Loading