firebase-data-connect
Firebase Data ConnectとPostgreSQLを連携させ、GraphQLベースのデータアクセスを安全かつリアルタイムに実現するSkill。
📜 元の英語説明(参考)
Firebase Data Connect integration for GraphQL-based data access with PostgreSQL. Use when building GraphQL schemas, queries, mutations, or integrating Firebase Data Connect with Angular applications. Supports type-safe generated SDKs, real-time subscriptions, and server-side data validation.
🇯🇵 日本人クリエイター向け解説
Firebase Data ConnectとPostgreSQLを連携させ、GraphQLベースのデータアクセスを安全かつリアルタイムに実現するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o firebase-data-connect.zip https://jpskill.com/download/6854.zip && unzip -o firebase-data-connect.zip && rm firebase-data-connect.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/6854.zip -OutFile "$d\firebase-data-connect.zip"; Expand-Archive "$d\firebase-data-connect.zip" -DestinationPath $d -Force; ri "$d\firebase-data-connect.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
firebase-data-connect.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
firebase-data-connectフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-17
- 取得日時
- 2026-05-17
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Firebase Data Connect
Firebase Data Connect を Angular アプリケーションと統合するための専門的なガイダンスです。PostgreSQL に裏打ちされた型安全な GraphQL 操作を提供します。
このスキルを使用するタイミング
以下の必要がある場合に、このスキルを有効にしてください。
- Firebase Data Connect 用の GraphQL スキーマを定義する
- データ操作のためのクエリとミューテーションを作成する
- Data Connect を Angular サービスと統合する
- 型安全な TypeScript SDK を生成する
- リアルタイムデータサブスクリプションを実装する
- Data Connect コネクタとサービスを設定する
- Firestore から Data Connect へ移行する
- GraphQL クエリのパフォーマンスを最適化する
Firebase Data Connect とは
Firebase Data Connect は、以下の機能を提供するリレーショナルデータベースサービスです。
- 型安全なデータアクセスを実現する GraphQL API
- リレーショナルデータ用の PostgreSQL バックエンド
- TypeScript/JavaScript 用の 生成された SDK
- ライブデータ用の リアルタイムサブスクリプション
- サーバーサイドの検証 とセキュリティルール
- 開発とテスト用の ローカルエミュレーター
前提条件
必要なツール
- Firebase CLI (
npm install -g firebase-tools) - Node.js 18+ と npm/pnpm
- Angular 20+ プロジェクト
- Data Connect が有効化された Firebase プロジェクト
インストール
# Firebase CLI をインストール
npm install -g firebase-tools
# Firebase にログイン
firebase login
# プロジェクトで Data Connect を初期化
firebase init dataconnect
# Angular Fire をインストール (まだインストールされていない場合)
npm install @angular/fire
プロジェクト構造
dataconnect/
├── dataconnect.yaml # コネクタ設定
├── schema/
│ ├── schema.gql # GraphQL スキーマ定義
│ └── types.gql # カスタム型と列挙型
├── queries/
│ ├── users.gql # ユーザー関連クエリ
│ └── workspace.gql # ワークスペース関連クエリ
├── mutations/
│ ├── createUser.gql # ユーザー関連ミューテーション
│ └── updateWorkspace.gql # ワークスペース関連ミューテーション
└── seed_data.gql # 開発用シードデータ
src/dataconnect-generated/ # 生成された TypeScript SDK
└── index.ts # 自動生成された型安全な操作
スキーマ定義
基本的なスキーマの例
# dataconnect/schema/schema.gql
type User @table {
id: UUID! @default(expr: "uuidV4()")
email: String! @unique
displayName: String!
photoURL: String
createdAt: Timestamp! @default(expr: "request.time")
updatedAt: Timestamp! @default(expr: "request.time")
# Relationships
workspaces: [WorkspaceMember!]! @relationFrom(field: "user")
}
type Workspace @table {
id: UUID! @default(expr: "uuidV4()")
name: String!
description: String
ownerId: UUID!
createdAt: Timestamp! @default(expr: "request.time")
# Relationships
owner: User! @relation(fields: "ownerId")
members: [WorkspaceMember!]! @relationFrom(field: "workspace")
}
type WorkspaceMember @table {
id: UUID! @default(expr: "uuidV4()")
userId: UUID!
workspaceId: UUID!
role: MemberRole!
joinedAt: Timestamp! @default(expr: "request.time")
# Relationships
user: User! @relation(fields: "userId")
workspace: Workspace! @relation(fields: "workspaceId")
# Composite unique constraint
@unique(fields: ["userId", "workspaceId"])
}
enum MemberRole {
OWNER
ADMIN
MEMBER
VIEWER
}
クエリ
クエリ定義
# dataconnect/queries/users.gql
query GetUser($userId: UUID!) @auth(level: USER) {
user(id: $userId) {
id
email
displayName
photoURL
createdAt
}
}
query ListUserWorkspaces($userId: UUID!) @auth(level: USER) {
workspaceMembers(where: { userId: { eq: $userId } }) {
workspace {
id
name
description
owner {
id
displayName
}
}
role
joinedAt
}
}
query SearchWorkspaces($searchTerm: String!) @auth(level: USER) {
workspaces(
where: {
name: { contains: $searchTerm }
}
orderBy: { createdAt: DESC }
limit: 20
) {
id
name
description
owner {
displayName
}
createdAt
}
}
ミューテーション
ミューテーション定義
# dataconnect/mutations/workspace.gql
mutation CreateWorkspace(
$name: String!
$description: String
$ownerId: UUID!
) @auth(level: USER) {
workspace_insert(data: {
name: $name
description: $description
ownerId: $ownerId
}) {
id
name
description
createdAt
}
}
mutation AddWorkspaceMember(
$workspaceId: UUID!
$userId: UUID!
$role: MemberRole!
) @auth(level: USER) {
workspaceMember_insert(data: {
workspaceId: $workspaceId
userId: $userId
role: $role
}) {
id
user {
displayName
email
}
role
joinedAt
}
}
mutation UpdateWorkspace(
$id: UUID!
$name: String
$description: String
) @auth(level: USER) {
workspace_update(
id: $id
data: {
name: $name
description: $description
}
) {
id
name
description
updatedAt
}
}
Angular 統合
生成された SDK の使用法
// src/app/infrastructure/firebase/data-connect.service.ts
import { Injectable, inject } from '@angular/core';
import { ConnectorConfig, getDataConnect } from '@angular/fire/data-connect';
import {
getUser,
listUserWorkspaces,
createWorkspace,
addWorkspaceMember
} from '@/dataconnect-generated';
@Injectable({ providedIn: 'root' })
export class DataConnectService {
private dataConnect = getDataConnect();
// クエリを実行
async getUserById(userId: string) {
const result = await getUser(this.dataConnect, { userId });
return result.data.user;
}
// 変数付きでクエリを実行
async getUserWorkspaces(userId: string) {
const result = await listUserWorkspaces(this.dataConnect, { userId });
return result.data.workspaceMembers;
}
// ミューテーションを実行
async createNewWorkspace(name: string, description: string, ownerId: string) {
const result = await createWorkspace(this.dataConnect, {
name,
description,
ownerId
});
return result.data.workspace_insert;
}
} 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Firebase Data Connect
Expert guidance for integrating Firebase Data Connect with Angular applications, providing type-safe GraphQL operations backed by PostgreSQL.
When to Use This Skill
Activate this skill when you need to:
- Define GraphQL schemas for Firebase Data Connect
- Create queries and mutations for data operations
- Integrate Data Connect with Angular services
- Generate type-safe TypeScript SDKs
- Implement real-time data subscriptions
- Configure Data Connect connectors and services
- Migrate from Firestore to Data Connect
- Optimize GraphQL query performance
What is Firebase Data Connect?
Firebase Data Connect is a relational database service that provides:
- GraphQL API for type-safe data access
- PostgreSQL backend for relational data
- Generated SDKs for TypeScript/JavaScript
- Real-time subscriptions for live data
- Server-side validation and security rules
- Local emulator for development and testing
Prerequisites
Required Tools
- Firebase CLI (
npm install -g firebase-tools) - Node.js 18+ and npm/pnpm
- Angular 20+ project
- Firebase project with Data Connect enabled
Installation
# Install Firebase CLI
npm install -g firebase-tools
# Login to Firebase
firebase login
# Initialize Data Connect in your project
firebase init dataconnect
# Install Angular Fire (if not already installed)
npm install @angular/fire
Project Structure
dataconnect/
├── dataconnect.yaml # Connector configuration
├── schema/
│ ├── schema.gql # GraphQL schema definitions
│ └── types.gql # Custom types and enums
├── queries/
│ ├── users.gql # User queries
│ └── workspace.gql # Workspace queries
├── mutations/
│ ├── createUser.gql # User mutations
│ └── updateWorkspace.gql # Workspace mutations
└── seed_data.gql # Development seed data
src/dataconnect-generated/ # Generated TypeScript SDK
└── index.ts # Auto-generated type-safe operations
Schema Definition
Basic Schema Example
# dataconnect/schema/schema.gql
type User @table {
id: UUID! @default(expr: "uuidV4()")
email: String! @unique
displayName: String!
photoURL: String
createdAt: Timestamp! @default(expr: "request.time")
updatedAt: Timestamp! @default(expr: "request.time")
# Relationships
workspaces: [WorkspaceMember!]! @relationFrom(field: "user")
}
type Workspace @table {
id: UUID! @default(expr: "uuidV4()")
name: String!
description: String
ownerId: UUID!
createdAt: Timestamp! @default(expr: "request.time")
# Relationships
owner: User! @relation(fields: "ownerId")
members: [WorkspaceMember!]! @relationFrom(field: "workspace")
}
type WorkspaceMember @table {
id: UUID! @default(expr: "uuidV4()")
userId: UUID!
workspaceId: UUID!
role: MemberRole!
joinedAt: Timestamp! @default(expr: "request.time")
# Relationships
user: User! @relation(fields: "userId")
workspace: Workspace! @relation(fields: "workspaceId")
# Composite unique constraint
@unique(fields: ["userId", "workspaceId"])
}
enum MemberRole {
OWNER
ADMIN
MEMBER
VIEWER
}
Queries
Query Definition
# dataconnect/queries/users.gql
query GetUser($userId: UUID!) @auth(level: USER) {
user(id: $userId) {
id
email
displayName
photoURL
createdAt
}
}
query ListUserWorkspaces($userId: UUID!) @auth(level: USER) {
workspaceMembers(where: { userId: { eq: $userId } }) {
workspace {
id
name
description
owner {
id
displayName
}
}
role
joinedAt
}
}
query SearchWorkspaces($searchTerm: String!) @auth(level: USER) {
workspaces(
where: {
name: { contains: $searchTerm }
}
orderBy: { createdAt: DESC }
limit: 20
) {
id
name
description
owner {
displayName
}
createdAt
}
}
Mutations
Mutation Definition
# dataconnect/mutations/workspace.gql
mutation CreateWorkspace(
$name: String!
$description: String
$ownerId: UUID!
) @auth(level: USER) {
workspace_insert(data: {
name: $name
description: $description
ownerId: $ownerId
}) {
id
name
description
createdAt
}
}
mutation AddWorkspaceMember(
$workspaceId: UUID!
$userId: UUID!
$role: MemberRole!
) @auth(level: USER) {
workspaceMember_insert(data: {
workspaceId: $workspaceId
userId: $userId
role: $role
}) {
id
user {
displayName
email
}
role
joinedAt
}
}
mutation UpdateWorkspace(
$id: UUID!
$name: String
$description: String
) @auth(level: USER) {
workspace_update(
id: $id
data: {
name: $name
description: $description
}
) {
id
name
description
updatedAt
}
}
Angular Integration
Generated SDK Usage
// src/app/infrastructure/firebase/data-connect.service.ts
import { Injectable, inject } from '@angular/core';
import { ConnectorConfig, getDataConnect } from '@angular/fire/data-connect';
import {
getUser,
listUserWorkspaces,
createWorkspace,
addWorkspaceMember
} from '@/dataconnect-generated';
@Injectable({ providedIn: 'root' })
export class DataConnectService {
private dataConnect = getDataConnect();
// Execute query
async getUserById(userId: string) {
const result = await getUser(this.dataConnect, { userId });
return result.data.user;
}
// Execute query with variables
async getUserWorkspaces(userId: string) {
const result = await listUserWorkspaces(this.dataConnect, { userId });
return result.data.workspaceMembers;
}
// Execute mutation
async createNewWorkspace(name: string, description: string, ownerId: string) {
const result = await createWorkspace(this.dataConnect, {
name,
description,
ownerId
});
return result.data.workspace_insert;
}
}
Repository Pattern
// src/app/infrastructure/persistence/workspace-dataconnect.repository.ts
import { Injectable } from '@angular/core';
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { DataConnectService } from '../firebase/data-connect.service';
import { IWorkspaceRepository } from '@domain/repositories/workspace.repository';
import { Workspace } from '@domain/workspace/workspace.entity';
@Injectable({ providedIn: 'root' })
export class WorkspaceDataConnectRepository implements IWorkspaceRepository {
constructor(private dataConnect: DataConnectService) {}
findById(id: string): Observable<Workspace | null> {
return from(this.dataConnect.getWorkspaceById(id)).pipe(
map(data => data ? this.toDomain(data) : null)
);
}
findByOwnerId(ownerId: string): Observable<Workspace[]> {
return from(this.dataConnect.getUserWorkspaces(ownerId)).pipe(
map(members => members.map(m => this.toDomain(m.workspace)))
);
}
save(workspace: Workspace): Observable<Workspace> {
return from(this.dataConnect.createNewWorkspace(
workspace.name,
workspace.description,
workspace.ownerId
)).pipe(
map(data => this.toDomain(data))
);
}
private toDomain(data: any): Workspace {
// Map Data Connect response to domain entity
return new Workspace({
id: data.id,
name: data.name,
description: data.description,
ownerId: data.ownerId,
createdAt: new Date(data.createdAt)
});
}
}
NgRx Signals Integration
// src/app/application/store/workspace.store.ts
import { signalStore, withState, withMethods } from '@ngrx/signals';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { pipe, switchMap, tap } from 'rxjs';
import { tapResponse } from '@ngrx/operators';
import { inject } from '@angular/core';
import { patchState } from '@ngrx/signals';
import { DataConnectService } from '@infrastructure/firebase/data-connect.service';
export const WorkspaceStore = signalStore(
{ providedIn: 'root' },
withState({
workspaces: [] as Workspace[],
selectedWorkspace: null as Workspace | null,
loading: false,
error: null as string | null
}),
withMethods((store, dataConnect = inject(DataConnectService)) => ({
loadUserWorkspaces: rxMethod<string>(
pipe(
tap(() => patchState(store, { loading: true, error: null })),
switchMap((userId) => dataConnect.getUserWorkspaces(userId)),
tapResponse({
next: (workspaces) => patchState(store, {
workspaces,
loading: false
}),
error: (error: Error) => patchState(store, {
error: error.message,
loading: false
})
})
)
),
createWorkspace: rxMethod<{ name: string; description: string; ownerId: string }>(
pipe(
tap(() => patchState(store, { loading: true })),
switchMap(({ name, description, ownerId }) =>
dataConnect.createNewWorkspace(name, description, ownerId)
),
tapResponse({
next: (workspace) => patchState(store, (state) => ({
workspaces: [...state.workspaces, workspace],
loading: false
})),
error: (error: Error) => patchState(store, {
error: error.message,
loading: false
})
})
)
)
}))
);
Configuration
dataconnect.yaml
# dataconnect/dataconnect.yaml
connectorId: my-connector
cloudSql:
instanceId: my-instance
database: my-database
schema:
source: ./schema
datasource:
postgresql: {}
queries:
source: ./queries
mutations:
source: ./mutations
Angular Fire Configuration
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
import { provideDataConnect, getDataConnect } from '@angular/fire/data-connect';
import { environment } from './environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideDataConnect(() => getDataConnect({
connector: 'my-connector',
location: 'us-central1'
})),
]
};
Local Development
Start Emulator
# Start Data Connect emulator
firebase emulators:start --only dataconnect
# Run with seed data
firebase emulators:start --only dataconnect --import=./seed-data
# Generate TypeScript SDK
firebase dataconnect:sdk:generate --output=src/dataconnect-generated
Seed Data
# dataconnect/seed_data.gql
mutation SeedUsers {
user1: user_insert(data: {
email: "admin@example.com"
displayName: "Admin User"
}) { id }
user2: user_insert(data: {
email: "member@example.com"
displayName: "Member User"
}) { id }
}
mutation SeedWorkspaces {
workspace1: workspace_insert(data: {
name: "Default Workspace"
description: "Main workspace"
ownerId: "USER_ID_HERE"
}) { id }
}
Best Practices
Schema Design
// ✅ Good - Use proper relationships
type Post @table {
authorId: UUID!
author: User! @relation(fields: "authorId")
}
// ❌ Bad - Duplicating data
type Post @table {
authorEmail: String
authorName: String
}
Query Optimization
# ✅ Good - Request only needed fields
query GetWorkspace($id: UUID!) {
workspace(id: $id) {
id
name
owner { displayName }
}
}
# ❌ Bad - Over-fetching
query GetWorkspace($id: UUID!) {
workspace(id: $id) {
id
name
description
owner {
id
email
displayName
photoURL
createdAt
updatedAt
}
members {
user {
id
email
displayName
}
}
}
}
Error Handling
// ✅ Good - Handle errors properly
async loadWorkspace(id: string) {
try {
const result = await getWorkspace(this.dataConnect, { id });
if (result.errors) {
throw new Error(result.errors[0].message);
}
return result.data.workspace;
} catch (error) {
console.error('Failed to load workspace:', error);
throw error;
}
}
// ❌ Bad - Ignore errors
async loadWorkspace(id: string) {
const result = await getWorkspace(this.dataConnect, { id });
return result.data.workspace;
}
Security
Authentication Rules
# Require authentication
query GetUser($id: UUID!) @auth(level: USER) {
user(id: $id) { ... }
}
# Require specific role
mutation DeleteWorkspace($id: UUID!) @auth(level: USER, expr: "auth.uid == resource.ownerId") {
workspace_delete(id: $id) { id }
}
Input Validation
# Use constraints
type User @table {
email: String! @unique
displayName: String! @check(expr: "length(this) >= 3")
age: Int @check(expr: "this >= 18")
}
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| SDK generation fails | Schema syntax errors | Run firebase dataconnect:validate |
| Query returns null | Missing @auth directive | Add proper authentication |
| Relationship error | Incorrect field references | Check @relation fields match column names |
| Emulator won't start | Port already in use | Change port in firebase.json or kill process |
| Type mismatch | Stale generated code | Re-run firebase dataconnect:sdk:generate |
Migration from Firestore
// Before (Firestore)
const docRef = doc(firestore, 'workspaces', id);
const docSnap = await getDoc(docRef);
const data = docSnap.data();
// After (Data Connect)
const result = await getWorkspace(dataConnect, { id });
const data = result.data.workspace;