Allmine API
Live Stream

Live Stream ban — RTK Query

Yayın ban mobil API entegrasyonu

Live Stream Ban - React Native (RTK Query)

Migration rehberi

Yapılandırma sırası için Migration şablonu. Yeni düzenlemelerde Amaç → Önkoşullar → Endpoint → Request/Response → Hata kodları → Client adımları → İlgili sayfalar bölümlerini tercih edin.

Bu doküman, live-stream-ban modülü endpointlerini React Native tarafında RTK Query ile kullanmak için hazırlandı.

Kapsam

  • Base path: /api/v1/live-stream-ban
  • Auth: Authorization: Bearer <JWT> (tüm endpointlerde zorunlu)
  • Response formati: BaseResponseDto<T> (asil payload data alanindadir)
  • Ban modeli: sadece stream bazli
  • Unban: fiziksel silme değil, soft delete (DELETE /:id)

Is Kurallari (Mobil Tarafindan Bilinmeli)

  • Ban oluşturma ve ban kaldirma sadece ilgili stream creator tarafından yapilabilir.
  • Ayni targetUserId + liveStreamId için aktif duplicate ban olusturulamaz.
  • check endpointinde liveStreamId query parametresi zorunludur.
  • actionType alanini göndermezseniz backend default olarak BLOCK kullanir.

Endpoint Ozeti

  • POST /api/v1/live-stream-ban
  • GET /api/v1/live-stream-ban
  • GET /api/v1/live-stream-ban/:id
  • GET /api/v1/live-stream-ban/check/:targetUserId?liveStreamId=...
  • DELETE /api/v1/live-stream-ban/:id

Socket Baglantisi (Ban Eventleri)

REST cagrilarina ek olarak ban/unban olaylari socket ile de yayinlanir.

  • Namespace: /live-stream
  • Oda: stream:<liveStreamId>
  • Odaya giris: joinStream eventi ile { streamId } gönderilmelidir.

Ban endpointleri tetiklenince gateway su eventleri yayinlar:

  • userBanned
  • userBanRevoked

userBanned payload:

{
  "targetUserId": "673ac9e2c93fe18d3fdd23f1",
  "targetUser": {
    "_id": "673ac9e2c93fe18d3fdd23f1",
    "username": "target-user"
  },
  "actionType": "BLOCK",
  "reason": "Spam",
  "timestamp": "2026-03-09T12:10:00.000Z"
}

userBanRevoked payload:

{
  "targetUserId": "673ac9e2c93fe18d3fdd23f1",
  "timestamp": "2026-03-09T12:20:00.000Z"
}

React Native socket ornegi (socket.io-client):

import { io, Socket } from 'socket.io-client';

type UserBannedEvent = {
  targetUserId: string;
  targetUser?: {
    _id: string;
    username?: string;
    name?: string;
    surname?: string;
    profilePhoto?: string | null;
  };
  actionType: 'BLOCK' | 'CHAT_ONLY';
  reason?: string;
  timestamp: string;
};

type UserBanRevokedEvent = {
  targetUserId: string;
  timestamp: string;
};

export const connectLiveStreamSocket = ({
  baseUrl,
  accessToken,
  streamId,
  onUserBanned,
  onUserBanRevoked,
}: {
  baseUrl: string;
  accessToken: string;
  streamId: string;
  onUserBanned: (payload: UserBannedEvent) => void;
  onUserBanRevoked: (payload: UserBanRevokedEvent) => void;
}) => {
  const socket: Socket = io(`${baseUrl.replace(/\/$/, '')}/live-stream`, {
    transports: ['websocket'],
    auth: { token: accessToken },
  });

  socket.on('connect', () => {
    socket.emit('joinStream', { streamId });
  });

  socket.on('userBanned', onUserBanned);
  socket.on('userBanRevoked', onUserBanRevoked);

  socket.on('disconnect', () => {
    // reconnect stratejisi app seviyesinde ele alınabilir
  });

  return () => {
    socket.emit('leaveStream', { streamId });
    socket.off('userBanned', onUserBanned);
    socket.off('userBanRevoked', onUserBanRevoked);
    socket.disconnect();
  };
};

Not:

  • Socket token'i auth.token ile göndermek en guvenli yoldur.
  • Ban eventleri sadece ilgili stream odasina (stream:<id>) yayinlandigi için joinStream çağrısı zorunludur.
  • UI tarafında userBanned geldiginde mesaj girisi/superlike butonu kapatilabilir.

Request / Response Sozlesmesi

1) Ban oluşturma

POST /api/v1/live-stream-ban

Body:

{
  "targetUserId": "673ac9e2c93fe18d3fdd23f1",
  "liveStreamId": "673acae0c93fe18d3fdd2407",
  "actionType": "BLOCK",
  "reason": "Toksik davranis"
}

actionType: BLOCK | CHAT_ONLY (opsiyonel)

Response data (StreamBanResponseDto):

{
  "_id": "67ca1234c93fe18d3fdd1234",
  "targetUserId": "673ac9e2c93fe18d3fdd23f1",
  "targetUser": {
    "_id": "673ac9e2c93fe18d3fdd23f1",
    "name": "Ayse",
    "surname": "Yilmaz",
    "profilePhoto": {
      "_id": "67ca5555c93fe18d3fdd9999",
      "url": "https://cdn.example.com/profile/ayse.webp"
    }
  },
  "liveStreamId": "673acae0c93fe18d3fdd2407",
  "actionType": "BLOCK",
  "reason": "Toksik davranis",
  "createdBy": "673ac9e2c93fe18d3fdd23f1",
  "deletedAt": null,
  "deletedBy": null,
  "createdAt": "2026-03-09T12:00:00.000Z",
  "updatedAt": "2026-03-09T12:00:00.000Z"
}

2) Ban listesi

GET /api/v1/live-stream-ban

Query (hepsi opsiyonel):

  • page (default: 1)
  • limit (default: 10, max: 100)
  • targetUserId
  • liveStreamId
  • actionType (BLOCK | CHAT_ONLY)

Response data:

{
  "list": [
    {
      "_id": "67ca1234c93fe18d3fdd1234",
      "targetUserId": "673ac9e2c93fe18d3fdd23f1",
      "targetUser": {
        "_id": "673ac9e2c93fe18d3fdd23f1",
        "name": "Ayse",
        "surname": "Yilmaz",
        "profilePhoto": {
          "_id": "67ca5555c93fe18d3fdd9999",
          "url": "https://cdn.example.com/profile/ayse.webp"
        }
      },
      "liveStreamId": "673acae0c93fe18d3fdd2407",
      "actionType": "BLOCK",
      "reason": "Toksik davranis",
      "createdBy": "673ac9e2c93fe18d3fdd23f1",
      "deletedAt": null,
      "deletedBy": null,
      "createdAt": "2026-03-09T12:00:00.000Z",
      "updatedAt": "2026-03-09T12:00:00.000Z"
    }
  ],
  "pagination": {
    "currentPage": 1,
    "totalPages": 1,
    "totalItems": 1,
    "itemsPerPage": 10,
    "hasNextPage": false,
    "hasPrevPage": false
  }
}

3) Tek ban detayi

GET /api/v1/live-stream-ban/:id

Response data: StreamBanResponseDto

4) Ban durum kontrolu

GET /api/v1/live-stream-ban/check/:targetUserId?liveStreamId=<streamId>

Response data:

{
  "isBanned": true,
  "ban": {
    "_id": "67ca1234c93fe18d3fdd1234",
    "targetUserId": "673ac9e2c93fe18d3fdd23f1",
    "targetUser": {
      "_id": "673ac9e2c93fe18d3fdd23f1",
      "name": "Ayse",
      "surname": "Yilmaz",
      "profilePhoto": {
        "_id": "67ca5555c93fe18d3fdd9999",
        "url": "https://cdn.example.com/profile/ayse.webp"
      }
    },
    "liveStreamId": "673acae0c93fe18d3fdd2407",
    "actionType": "CHAT_ONLY",
    "reason": "Spam",
    "createdBy": "673ac9e2c93fe18d3fdd23f1",
    "deletedAt": null,
    "deletedBy": null,
    "createdAt": "2026-03-09T12:00:00.000Z",
    "updatedAt": "2026-03-09T12:00:00.000Z"
  }
}

Ban yoksa:

{
  "isBanned": false,
  "ban": null
}

5) Ban kaldirma (soft delete)

DELETE /api/v1/live-stream-ban/:id

Response data: StreamBanResponseDto (deletedAt ve deletedBy dolu gelir)

RTK Query - Ornek API Slice

import { baseApi } from './baseApi';

type BaseResponseDto<T> = {
  isSuccess: boolean;
  statusCode: number;
  data: T;
  errors?: string[];
  timestamp: string;
};

type BanActionType = 'BLOCK' | 'CHAT_ONLY';

type UserSummary = {
  _id: string;
  username?: string;
  name?: string | null;
  surname?: string | null;
  profilePhoto?: {
    _id: string;
    url?: string;
  } | null;
};

type Pagination = {
  currentPage: number;
  totalPages: number;
  totalItems: number;
  itemsPerPage: number;
  hasNextPage?: boolean;
  hasPrevPage?: boolean;
};

export type StreamBanResponse = {
  _id: string;
  targetUserId: string;
  targetUser?: UserSummary | null;
  liveStreamId: string;
  actionType: BanActionType;
  reason?: string | null;
  createdBy: string;
  deletedAt?: string | null;
  deletedBy?: string | null;
  createdAt?: string;
  updatedAt?: string;
};

// Not: Backend kullanıcı ozetini cozemiyorsa `targetUser` null donebilir.

export type StreamBanListResponse = {
  list: StreamBanResponse[];
  pagination: Pagination;
};

export type CheckBanStatusResponse = {
  isBanned: boolean;
  ban: StreamBanResponse | null;
};

export type CreateLiveStreamBanBody = {
  targetUserId: string;
  liveStreamId: string;
  actionType?: BanActionType;
  reason?: string;
};

export type GetLiveStreamBansQuery = {
  page?: number;
  limit?: number;
  targetUserId?: string;
  liveStreamId?: string;
  actionType?: BanActionType;
};

const unwrap = <T>(r: BaseResponseDto<T> | T): T => {
  if (r && typeof r === 'object' && 'data' in (r as any)) {
    return (r as BaseResponseDto<T>).data;
  }
  return r as T;
};

export const liveStreamBanApi = baseApi
  .enhanceEndpoints({ addTagTypes: ['LiveStreamBan', 'LiveStreamBanCheck'] })
  .injectEndpoints({
    endpoints: (builder) => ({
      createLiveStreamBan: builder.mutation<
        StreamBanResponse,
        CreateLiveStreamBanBody
      >({
        query: (body) => ({
          url: '/v1/live-stream-ban',
          method: 'POST',
          body,
        }),
        transformResponse: (r: BaseResponseDto<StreamBanResponse> | StreamBanResponse) =>
          unwrap(r),
        invalidatesTags: (_res, _err, arg) => [
          { type: 'LiveStreamBan', id: 'LIST' },
          { type: 'LiveStreamBanCheck', id: `${arg.targetUserId}-${arg.liveStreamId}` },
        ],
      }),

      getLiveStreamBans: builder.query<
        StreamBanListResponse,
        GetLiveStreamBansQuery | void
      >({
        query: (params) => ({
          url: '/v1/live-stream-ban',
          params,
        }),
        transformResponse: (r: BaseResponseDto<StreamBanListResponse> | StreamBanListResponse) =>
          unwrap(r),
        providesTags: (res) => {
          const base = [{ type: 'LiveStreamBan' as const, id: 'LIST' }];
          if (!res?.list?.length) {
            return base;
          }
          return [
            ...base,
            ...res.list.map((item) => ({ type: 'LiveStreamBan' as const, id: item._id })),
          ];
        },
      }),

      getLiveStreamBanById: builder.query<StreamBanResponse, { id: string }>({
        query: ({ id }) => ({ url: `/v1/live-stream-ban/${id}` }),
        transformResponse: (r: BaseResponseDto<StreamBanResponse> | StreamBanResponse) =>
          unwrap(r),
        providesTags: (_res, _err, arg) => [{ type: 'LiveStreamBan', id: arg.id }],
      }),

      checkLiveStreamBanStatus: builder.query<
        CheckBanStatusResponse,
        { targetUserId: string; liveStreamId: string }
      >({
        query: ({ targetUserId, liveStreamId }) => ({
          url: `/v1/live-stream-ban/check/${targetUserId}`,
          params: { liveStreamId },
        }),
        transformResponse: (
          r: BaseResponseDto<CheckBanStatusResponse> | CheckBanStatusResponse,
        ) => unwrap(r),
        providesTags: (_res, _err, arg) => [
          { type: 'LiveStreamBanCheck', id: `${arg.targetUserId}-${arg.liveStreamId}` },
        ],
      }),

      deleteLiveStreamBan: builder.mutation<StreamBanResponse, { id: string }>({
        query: ({ id }) => ({
          url: `/v1/live-stream-ban/${id}`,
          method: 'DELETE',
        }),
        transformResponse: (r: BaseResponseDto<StreamBanResponse> | StreamBanResponse) =>
          unwrap(r),
        invalidatesTags: (_res, _err, arg) => [
          { type: 'LiveStreamBan', id: 'LIST' },
          { type: 'LiveStreamBan', id: arg.id },
        ],
      }),
    }),
  });

export const {
  useCreateLiveStreamBanMutation,
  useGetLiveStreamBansQuery,
  useGetLiveStreamBanByIdQuery,
  useCheckLiveStreamBanStatusQuery,
  useDeleteLiveStreamBanMutation,
} = liveStreamBanApi;

React Native Kullanim Ornekleri

1) Bir kullanıcıyi banla

const [createBan, { isLoading: isBanning }] = useCreateLiveStreamBanMutation();

await createBan({
  targetUserId,
  liveStreamId,
  actionType: 'BLOCK',
  reason: 'Spam mesaj',
}).unwrap();

2) Stream için ban listesi çek

const { data, isFetching, refetch } = useGetLiveStreamBansQuery({
  liveStreamId,
  page: 1,
  limit: 20,
});

const bans = data?.list ?? [];

3) Kullanıcı banli mi kontrol et

const { data: banStatus } = useCheckLiveStreamBanStatusQuery(
  { targetUserId, liveStreamId },
  { skip: !targetUserId || !liveStreamId },
);

if (banStatus?.isBanned) {
  // chat input disable vb.
}

4) Ban kaldir

const [deleteBan, { isLoading: isRemoving }] = useDeleteLiveStreamBanMutation();

await deleteBan({ id: banId }).unwrap();

Error Handling Notlari

  • 403: stream creator olmayan kullanıcı ban ekleyemez/kaldiramaz.
  • 404: ban veya stream bulunamadi.
  • 409: aktif duplicate ban oluşturma denemesi veya zaten kaldirilmis ban.
  • Validation hatalari (400) için backend errors/message alanlarini UI'da toast/snackbar ile gösterebilirsiniz.

Onerilen UI Akisi

  1. Stream admin ekraninda once getLiveStreamBans(liveStreamId) ile listeyi çekin.
  2. Kullanıcı satirinda Ban aksiyonu -> createLiveStreamBan.
  3. Ban kartinda Kaldir aksiyonu -> deleteLiveStreamBan.
  4. Mesaj gönderme gibi kritik aksiyonlardan once checkLiveStreamBanStatus ile gate kontrolu yapin.

On this page