angular-fire

📁 7spade/black-tortoise 📅 Jan 30, 2026
10
总安装量
10
周安装量
#29343
全站排名
安装命令
npx skills add https://github.com/7spade/black-tortoise --skill angular-fire

Agent 安装分布

codex 9
opencode 8
gemini-cli 8
claude-code 8
replit 8
github-copilot 8

Skill 文档

AngularFire & Firebase Patterns Skill

🎯 Purpose

This skill provides implementation patterns for using @angular/fire in a Zoneless, Signal-first, and DDD-compliant Angular 20 application.

🛠️ Core Patterns

1. Repository Implementation (Infrastructure)

How to implement a Domain Repository using Firestore and Signals.

// src/app/integration/persistence/task-firestore.repository.ts
import { inject, Injectable } from '@angular/core';
import { Firestore, collection, collectionData, query, where, doc, setDoc } from '@angular/fire/firestore';
import { toSignal } from '@angular/core/rxjs-interop';
import { TaskRepository } from '@domain/repositories';
import { TaskEntity } from '@domain/entities';

@Injectable({ providedIn: 'root' })
export class TaskFirestoreRepository implements TaskRepository {
  private firestore = inject(Firestore);
  private collection = collection(this.firestore, 'tasks');

  // Return Observable (Infrastructure Standard)
  findByWorkspace(workspaceId: string): Observable<TaskEntity[]> {
    const q = query(this.collection, where('workspaceId', '==', workspaceId));
    return collectionData(q, { idField: 'id' }) as Observable<TaskEntity[]>;
  }

  async save(task: TaskEntity): Promise<void> {
    const docRef = doc(this.firestore, `tasks/${task.id}`);
    await setDoc(docRef, task);
  }
}

2. Signal-Based Auth State (Account Module)

Standard pattern for building an Auth Store.

// src/app/account/application/stores/auth.store.ts
import { inject } from '@angular/core';
import { Auth, user } from '@angular/fire/auth';
import { toSignal } from '@angular/core/rxjs-interop';
import { signalStore, withState, withComputed } from '@ngrx/signals';

export const AuthStore = signalStore(
  { providedIn: 'root' },
  withComputed(() => {
    const auth = inject(Auth);
    // Transform Firebase User stream to Signal
    const currentUser = toSignal(user(auth));
    
    return {
      user: currentUser,
      isAuthenticated: computed(() => !!currentUser()),
      userId: computed(() => currentUser()?.uid ?? null)
    };
  })
);

3. Error Mapping

Firebase errors should not reach the Domain or UI directly.

try {
  await signInWithEmailAndPassword(this.auth, email, password);
} catch (error: any) {
  // Map Firebase Auth Error to Domain Error
  if (error.code === 'auth/wrong-password') {
    throw new InvalidCredentialsError();
  }
  throw new InfrastructureError(error.message);
}

🔐 Security Rules Checklist

  • request.auth != null for all workspace data.
  • Users can only read workspaces they are members of.
  • Use get(/databases/(default)/documents/workspaces/$(workspaceId)).data.members for permission checks.
  • No allow read, write: if true; even in development.

🚀 Optimization Patterns

  • Zoneless Safety: Ensure all Firestore interactions are wrapped in Angular Signals to avoid missing change detection.
  • Snapshot Transformation: Always map Timestamp objects to number (milliseconds) when converting to Domain Entities.
  • Batching: Use writeBatch() for multiple updates to maintain atomicity and save costs.