managarten/maerchenzauber/MANA_CORE_INTEGRATION_CHECKLIST.md
Till-JS e7f5f942f3 chore: initial commit - consolidate 4 projects into monorepo
Projects included:
- maerchenzauber (NestJS backend + Expo mobile + SvelteKit web + Astro landing)
- manacore (Expo mobile + SvelteKit web + Astro landing)
- manadeck (NestJS backend + Expo mobile + SvelteKit web)
- memoro (Expo mobile + SvelteKit web + Astro landing)

This commit preserves the current state before monorepo restructuring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 23:38:24 +01:00

9.8 KiB

Mana Core Integration Checklist

Use this checklist when integrating @mana-core/nestjs-integration into a new NestJS project.

Prerequisites ✓

  • NestJS v10+ application set up
  • @nestjs/config installed
  • Node.js v18+ and npm/yarn
  • Mana Core credentials obtained:
    • MANA_SERVICE_URL
    • APP_ID
    • MANA_SUPABASE_SECRET_KEY (service key)

Backend Integration Steps

1. Installation

  • Install the package:

    npm install git+https://github.com/Memo-2023/mana-core-nestjs-package.git
    
  • Verify in package.json:

    "@mana-core/nestjs-integration": "git+https://github.com/..."
    

2. Environment Configuration

  • Create/update .env file:

    MANA_SERVICE_URL=https://your-mana-instance.com
    APP_ID=your-app-id
    MANA_SUPABASE_SECRET_KEY=your-service-key
    NODE_ENV=development
    
  • Add to .env.example (for team reference)

  • Add .env to .gitignore

3. Module Configuration

  • Import ManaCoreModule in app.module.ts

  • Configure with forRootAsync():

    ManaCoreModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        manaServiceUrl: 'your-mana-url',
        appId: 'your-app-id',
        serviceKey: configService.get('MANA_SUPABASE_SECRET_KEY'),
        debug: configService.get('NODE_ENV') === 'development',
      }),
      inject: [ConfigService],
    })
    
  • Test backend starts without errors

4. Protect Routes with AuthGuard

  • Import AuthGuard in controller:

    import { AuthGuard } from '@mana-core/nestjs-integration';
    
  • Apply to controller or route:

    @Controller('protected')
    @UseGuards(AuthGuard)
    export class ProtectedController {}
    
  • Test: Verify 401 without token

5. Extract User Information

  • Import @CurrentUser() decorator:

    import { CurrentUser } from '@mana-core/nestjs-integration';
    
  • Use in route handlers:

    @Get('profile')
    async getProfile(@CurrentUser() user: JwtPayload) {
      return { userId: user.sub, email: user.email };
    }
    
  • Test: Verify user data is extracted correctly

6. Integrate Credit System

  • Inject CreditClientService:

    constructor(private creditClient: CreditClientService) {}
    
  • Add pre-flight credit validation:

    const validation = await this.creditClient.validateCredits(
      userId,
      'operation_type',
      creditCost,
    );
    
  • Add credit consumption after success:

    await this.creditClient.consumeCredits(
      userId,
      'operation_type',
      creditCost,
      'Description',
      metadata,
    );
    
  • Handle InsufficientCreditsException:

    import { InsufficientCreditsException } from '@mana-core/nestjs-integration';
    
  • Test: Verify credits are deducted

7. (Optional) Custom Token Decorator

  • Create @UserToken() decorator for RLS:

    // decorators/user.decorator.ts
    export const UserToken = createParamDecorator(
      (_data: unknown, ctx: ExecutionContext): string => {
        const request = ctx.switchToHttp().getRequest();
        const authHeader = request.headers.authorization;
        if (authHeader?.startsWith('Bearer ')) {
          return authHeader.substring(7);
        }
        return request.token;
      },
    );
    
  • Use for database RLS:

    @Get()
    async getData(
      @CurrentUser() user: JwtPayload,
      @UserToken() token: string,
    ) {
      return await this.db.query(userId, token);
    }
    

Frontend Integration Steps

1. Configure API Base URL

  • Create .env file:

    EXPO_PUBLIC_STORYTELLER_BACKEND_URL=http://localhost:3002
    
  • Create API utility (utils/api.ts):

    export const API_BASE_URL = process.env.EXPO_PUBLIC_BACKEND_URL;
    

2. Create Auth Service

  • Create services/authService.ts

  • Implement sign-in:

    signIn: async (email: string, password: string) => {
      const deviceInfo = await getDeviceInfo();
      const response = await fetch(`${BACKEND_URL}/auth/signin`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password, deviceInfo }),
      });
      const data = await response.json();
      await storeTokens(data.appToken, data.refreshToken);
    }
    
  • Implement sign-up

  • Implement sign-out

  • Test: Verify tokens are stored securely

3. Create Token Manager

  • Create services/tokenManager.ts

  • Implement getValidToken():

    getValidToken: async () => {
      let token = await storage.getItem('appToken');
      if (isExpiringSoon(token)) {
        await this.refreshToken();
        token = await storage.getItem('appToken');
      }
      return token;
    }
    
  • Implement refreshToken():

    refreshToken: async () => {
      const refreshToken = await storage.getItem('refreshToken');
      const deviceInfo = await getDeviceInfo();
      const response = await fetch(`${BACKEND_URL}/auth/refresh`, {
        method: 'POST',
        body: JSON.stringify({ refreshToken, deviceInfo }),
      });
      const data = await response.json();
      await storeTokens(data.appToken, data.refreshToken);
    }
    
  • Test: Verify automatic refresh works

4. Create Authenticated API Client

  • Create fetchWithAuth() function:

    export async function fetchWithAuth(endpoint: string, options = {}) {
      const token = await tokenManager.getValidToken();
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        ...options,
        headers: {
          ...options.headers,
          'Authorization': `Bearer ${token}`,
        },
      });
    
      if (response.status === 401) {
        await tokenManager.refreshToken();
        // Retry request
      }
    
      return response;
    }
    
  • Test: Verify authenticated requests work

5. Handle Credit Errors

  • Create error handling utility:

    export function isInsufficientCreditsError(error: any) {
      return error?.error === 'insufficient_credits';
    }
    
  • Handle in UI:

    if (data.error === 'insufficient_credits') {
      showPurchaseCreditsModal({
        required: data.requiredCredits,
        available: data.availableCredits,
      });
    }
    
  • Test: Verify error is displayed correctly

6. Device Management

  • Create utils/deviceManager.ts:

    export class DeviceManager {
      static async getDeviceInfo() {
        return {
          deviceId: await getOrCreateDeviceId(),
          deviceName: Platform.OS,
          deviceType: Platform.OS as 'ios' | 'android' | 'web',
          userAgent: getUserAgent(),
        };
      }
    }
    
  • Include in auth requests

  • Test: Verify device info is sent


Testing Steps

Backend Tests

  • Create unit tests with mocked services:

    {
      provide: CreditClientService,
      useValue: {
        validateCredits: jest.fn().mockResolvedValue({
          hasCredits: true,
        }),
        consumeCredits: jest.fn(),
      },
    }
    
  • Create integration tests with real Mana Core module

  • Test credit validation flow

  • Test insufficient credits error

  • Run tests: npm run test

Frontend Tests

  • Test authentication flow

  • Test token refresh

  • Test authenticated API calls

  • Test credit error handling

  • Run tests: npm run test


Production Deployment

Backend

  • Set production environment variables:

    MANA_SERVICE_URL=https://production-mana.com
    APP_ID=production-app-id
    MANA_SUPABASE_SECRET_KEY=production-key
    NODE_ENV=production
    
  • Disable debug logging (debug: false)

  • Test health endpoint

  • Deploy and monitor logs

Frontend

  • Update .env for production:

    EXPO_PUBLIC_BACKEND_URL=https://your-api.com
    
  • Build production bundle

  • Test authentication flow

  • Test API calls

  • Deploy to stores (iOS/Android) or web


Post-Integration Verification

  • Sign-up flow works end-to-end

  • Sign-in flow works end-to-end

  • Token refresh works automatically

  • Protected routes require authentication

  • Credit validation prevents operations

  • Credit consumption records transactions

  • Insufficient credits error handled gracefully

  • Sign-out clears tokens

  • Multi-device support works


Documentation

  • Update README with Mana Core setup instructions

  • Document custom operation types and credit costs

  • Add environment variable documentation

  • Create troubleshooting guide

  • Document API endpoints


Common Issues Checklist

If something doesn't work, check:

  • Environment variables are set correctly
  • Backend is running and accessible
  • Service key is configured (for credit operations)
  • Tokens are being stored and retrieved correctly
  • Token expiration is being checked
  • Device info is being sent with auth requests
  • CORS is configured (if using web frontend)
  • Network requests are not being blocked
  • Debug logging is enabled for troubleshooting

Support Resources


Integration Complete! 🎉

Once all items are checked, your application is fully integrated with Mana Core.

Estimated Time: 2-4 hours for basic integration, 1-2 days for complete implementation with testing.

Next Steps:

  1. Define your operation types and credit costs
  2. Implement purchase flow for credits
  3. Add analytics and monitoring
  4. Set up role-based access control (if needed)