Skip to Content

Providers y Servicios

Creative Minds utiliza un sistema de providers y servicios para manejar integraciones externas y lógica de negocio de manera limpia y mantenible.

Providers

Los providers son abstracciones para servicios externos como bases de datos, APIs, sistemas de monitoreo, etc.

Estructura de Providers

src/providers/ ├── database/ # Conexión a base de datos └── supabase/ # Cliente de Supabase ├── monitoring/ # Telemetría y logging ├── payments/ # Integración de pagos └── queries/ # Estado global (TanStack Query)

Implementación de Providers

Database Provider

// providers/database/database.provider.ts import { createClient } from '@supabase/supabase-js' export class SupabaseProvider { private static instance: SupabaseClient private static isInitialized: boolean = false static async initialize() { if (this.isInitialized) return this.instance = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ) this.isInitialized = true } static async access() { if (!this.isInitialized) { await this.initialize() } return this.instance } } export const supabaseProvider = SupabaseProvider

Monitoring Provider

// providers/monitoring/monitoring.provider.ts export class MonitoringProvider { private logger: Logger constructor() { this.logger = new Logger('MonitoringProvider') } async trackEvent(name: string, properties?: Record<string, any>) { try { // Implementación específica de tracking await analytics.track(name, properties) } catch (error) { this.logger.error('Failed to track event', { error }) } } async captureError(error: Error) { try { // Implementación de captura de errores await errorReporting.capture(error) } catch (err) { this.logger.error('Failed to capture error', { error: err }) } } } export const monitoringProvider = new MonitoringProvider()

Servicios

Los servicios encapsulan la lógica de negocio y utilizan los providers para interactuar con servicios externos.

Estructura Base de Servicio

// shared/utils/service.ts export class Service { protected logger: Logger constructor() { this.logger = new Logger(this.constructor.name) } protected async withErrorHandling<T>( operation: () => Promise<T>, errorMessage: string ): Promise<T> { try { return await operation() } catch (error) { this.logger.error(errorMessage, { error }) throw error } } }

Implementación de Servicios

Auth Service

// modules/auth/services/auth.service.ts export class AuthService extends Service { constructor( private authAdapter: AuthAdapter, private monitoringProvider: MonitoringProvider ) { super() } async getCurrentUser() { return this.withErrorHandling( async () => { const session = await this.authAdapter.getSession() return session?.user }, 'Failed to get current user' ) } async login(credentials: LoginCredentials) { return this.withErrorHandling( async () => { const result = await this.authAdapter.signIn(credentials) await this.monitoringProvider.trackEvent('user_login') return result }, 'Failed to login user' ) } } export const authService = new AuthService( authAdapter, monitoringProvider )

Onboarding Service

// modules/onboarding/services/onboarding.service.ts export class OnboardingService extends Service { constructor( private authService: AuthService, private database: SupabaseProvider ) { super() } async setUserOnboarding( onboardingData: CreateOnboardingData ): Promise<{ data: OnboardingResponse | null; error: Error | null }> { return this.withErrorHandling( async () => { const user = await this.authService.getCurrentUser() const { data, error } = await (await this.database.access()) .from("onboardings") .insert({ ...onboardingData, user_id: user?.id, created_at: new Date(), updated_at: new Date(), }) return { data, error: error as Error | null } }, 'Failed to set user onboarding' ) } } export const onboardingService = new OnboardingService( authService, supabaseProvider )

Integración con Server Actions

Los servicios se utilizan en Server Actions para manejar la lógica de negocio:

// modules/auth/actions/auth.actions.ts export async function loginAction( prevState: any, formData: FormData ) { const credentials = { email: formData.get('email') as string, password: formData.get('password') as string, } try { await authService.login(credentials) redirect('/dashboard') } catch (error) { return { error: 'Invalid credentials' } } }

Diagrama de Arquitectura

Mejores Prácticas

  1. Singleton Providers: Providers deben ser singleton para mantener una única instancia

  2. Error Handling Centralizado: Usar el método withErrorHandling en servicios

  3. Logging Consistente: Utilizar el logger en providers y servicios

  4. Tipado Fuerte: Definir interfaces claras para inputs y outputs

  5. Inyección de Dependencias: Pasar dependencias en constructores

  6. Monitoreo: Integrar tracking y captura de errores

Esta arquitectura de providers y servicios proporciona:

  • Separación clara de responsabilidades
  • Fácil testeo y mocking
  • Código mantenible y escalable
  • Gestión eficiente de recursos externos
Last updated on