Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/AndrewwCO/Panahashi-Backend/llms.txt

Use this file to discover all available pages before exploring further.

The Panahashi backend sends push notifications through Firebase Cloud Messaging (FCM) to keep bakers and customers informed as orders move through the system. All notifications are sent server-side using the Firebase Admin SDK — the client only needs to register a valid FCM token.

How notifications work

When a significant event occurs (a new order, a status change, a loyalty stamp, etc.), the backend fetches the target user’s FCM token from their Firestore document at users/{uid}.fcmToken, constructs a message, and calls FirebaseMessaging.getInstance().send(message). If the user does not have a token stored, no notification is sent.

Registering a device token

When the app launches (or when the FCM token refreshes), the client must send the new token to the backend so the server always has a valid address to deliver notifications to. Send a PATCH request to /api/v1/users/me with the fcmToken field in the request body:
curl -X PATCH https://your-api-host/api/v1/users/me \
  -H "Authorization: Bearer <firebase-id-token>" \
  -H "Content-Type: application/json" \
  -d '{"fcmToken": "your-fcm-device-token"}'
Call this function on every app launch, not just on the first install. FCM tokens can be refreshed by the device at any time. Use messaging().onTokenRefresh(token => registerFcmToken(authToken)) to handle mid-session refreshes.

Notification events

The table below lists every notification the backend can send, including the Spanish-language strings used in the app (Panahashi serves the Colombian market).
EventTriggerRecipientTitleBody
New order (cash)Customer places a cash-on-pickup orderBaker¡Nuevo Pedido!Tienes un nuevo pedido de {customerName}
New order (payment approved)Payment gateway approves paymentBaker¡Nuevo Pedido!Tienes un nuevo pedido de {customerName}
Order confirmedBaker confirms the orderCustomerPedido ConfirmadoTu pedido ha sido confirmado y está siendo preparado
Order bakingBaker marks order as in progressCustomerPedido en PreparaciónTu pedido está siendo preparado
Order readyBaker marks order as ready for pickupCustomer¡Pedido Listo!Tu pedido está listo para recoger
Order completedBaker marks order as completedCustomerPedido CompletadoTu pedido ha sido completado. ¡Gracias por tu compra!
Order cancelledBaker or system cancels the orderCustomerPedido CanceladoTu pedido ha sido cancelado
Bakery activatedAdmin activates a baker’s bakeryBaker¡Panadería Activada!Tu panadería {bakeryName} ha sido activada
Estimated ready timeBaker sets an estimated ready timeCustomerTiempo Estimado ActualizadoTu pedido estará listo aproximadamente a las {estimatedReadyAt}
Loyalty stamp awardedOrder completed; stamp recordedCustomer¡Sello de Fidelidad!Has ganado un sello en {bakeryName}. Tienes {stamps}/{stampsForReward} sellos
Payment rejectedPayment gateway rejects paymentCustomerPago RechazadoEl pago de tu pedido {orderId} fue rechazado

Order status notification flow

As an order moves through its lifecycle, specific notifications fire at each transition. The diagram below shows the full flow from order placement to completion or cancellation.

Client implementation (React Native)

The following example shows how to set up FCM in a React Native app, request permissions, register the token, and handle incoming notifications.
import messaging from '@react-native-firebase/messaging';
import { useEffect } from 'react';

export function usePushNotifications(authToken: string | null) {
  useEffect(() => {
    if (!authToken) return;

    // Request permission (iOS requires explicit request)
    messaging()
      .requestPermission()
      .then(async (status) => {
        if (
          status === messaging.AuthorizationStatus.AUTHORIZED ||
          status === messaging.AuthorizationStatus.PROVISIONAL
        ) {
          const token = await messaging().getToken();
          await registerFcmToken(authToken, token);
        }
      });

    // Handle token refresh
    const unsubscribeRefresh = messaging().onTokenRefresh((token) => {
      registerFcmToken(authToken, token);
    });

    // Handle notifications received while the app is in the foreground
    const unsubscribeForeground = messaging().onMessage(async (remoteMessage) => {
      console.log('Foreground notification:', remoteMessage.notification);
      // Show an in-app alert or update your UI here
    });

    return () => {
      unsubscribeRefresh();
      unsubscribeForeground();
    };
  }, [authToken]);
}

async function registerFcmToken(authToken: string, fcmToken: string) {
  await fetch('https://your-api-host/api/v1/users/me', {
    method: 'PATCH',
    headers: {
      Authorization: `Bearer ${authToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ fcmToken }),
  });
}

Foreground and background handling

When the app is in the background or closed, FCM delivers the notification to the device’s notification tray. Tapping the notification launches the app. Use messaging().getInitialNotification() in your root component to read the notification that opened the app and navigate accordingly.
const remoteMessage = await messaging().getInitialNotification();
if (remoteMessage) {
  // Navigate to the relevant order or screen
}
Notifications are only delivered if the target user has a valid fcmToken stored in their Firestore profile. If a user never calls PATCH /api/v1/users/me with their token — or if the token is stale — the notification is silently dropped. Always register the token on login and refresh it when FCM reports a new one.

Build docs developers (and LLMs) love