Files
firebase/CLAUDE.md
Rene Nochebuena 3ef30c2354 feat(firebase): initial stable release v0.9.0
Firebase App component with launcher lifecycle and health check integration.

What's included:
- Config with ProjectID (FIREBASE_PROJECT_ID env var); credentials via ADC
- Provider interface exposing native *firebase.App directly
- Component interface: launcher.Component + health.Checkable + Provider
- New(logger, cfg) constructor for lifecycle registration via lc.Append
- Health check via GetUser("health-probe-non-existent") + auth.IsUserNotFound at LevelCritical
- No-op OnStop (Firebase Admin SDK has no Close method)

Tested-via: todo-api POC integration
Reviewed-against: docs/adr/
2026-03-19 13:35:40 +00:00

3.6 KiB

firebase

Firebase App component with launcher lifecycle and health check integration.

Purpose

Manages the lifecycle of a firebase.google.com/go/v4 App: validates config at init time, exposes the native *fb.App to consumers, and performs health checks by probing the Auth service. Does not wrap or abstract any Firebase service beyond App construction.

Tier & Dependencies

Tier 3 (infrastructure) — depends on:

  • code.nochebuena.dev/go/health (Tier 2)
  • code.nochebuena.dev/go/launcher (Tier 2)
  • code.nochebuena.dev/go/logz (Tier 1)
  • firebase.google.com/go/v4 (Firebase Admin SDK, wraps gRPC/HTTP internally)

Key Design Decisions

  • Health check via known-nonexistent UID: HealthCheck calls GetUser with the UID "health-probe-non-existent" and uses auth.IsUserNotFound(err) to distinguish a healthy "not found" response from a real connectivity failure. Avoids string matching on error messages. See ADR-001.
  • SDK lifecycle management: OnInit calls fb.NewApp. OnStop is a no-op log because the SDK has no Close method. See ADR-002.
  • App exposed directly: App() *fb.App gives consumers the full SDK entry point. They call app.Auth(ctx) or app.Firestore(ctx) themselves. The module does not cache or pre-construct service-specific clients.
  • Health priority is Critical: Priority() returns health.LevelCritical. A Firebase Auth outage is treated as a critical failure.
  • Duck-typed Logger: The internal logger field is typed as logz.Logger, the shared interface from the logz module (ADR-001 global pattern).

Patterns

Lifecycle registration:

fb := firebase.New(logger, cfg)
lc.Append(fb) // registers OnInit / OnStart / OnStop

Obtaining service clients from consumers:

type authService struct {
    provider firebase.Provider
}

func (s *authService) VerifyToken(ctx context.Context, token string) (*auth.Token, error) {
    authClient, err := s.provider.App().Auth(ctx)
    if err != nil {
        return nil, err
    }
    return authClient.VerifyIDToken(ctx, token)
}

Health check registration:

health.Register(fbComponent) // satisfies health.Checkable via Name()/Priority()/HealthCheck()

What to Avoid

  • Do not call App() before OnInit has run — it returns nil. Guard against this in tests or when constructing components manually outside a lifecycle manager.
  • Do not add service-specific methods (e.g. AuthClient(), FirestoreClient()) to this module. Callers obtain them from App() directly, which keeps the module free of service proliferation.
  • Do not increase the health check polling frequency significantly. Each HealthCheck call makes a live API call to Firebase Auth. Poll at most every 30 seconds.
  • Do not rely on OnStop for graceful in-flight request drain. The SDK has no explicit close; in-flight Firebase calls at shutdown must be handled by request context deadlines in the caller.

Testing Notes

  • Unit tests do not require a real Firebase project. They test structural invariants: Name(), Priority(), nil-safety of OnStop, and error on empty ProjectID.
  • TestComponent_OnInit_MissingProjectID verifies that OnInit returns an error before attempting SDK initialisation when ProjectID is empty.
  • TestComponent_App_ReturnsNilBeforeInit confirms App() is nil before OnInit is called.
  • Integration tests (real token verification, real health check) require Firebase credentials and belong outside this module.
  • compliance_test.go (package firebase_test) asserts New(...) satisfies Component at compile time.