nivq
Bu kurulum bölümü, nivq'yu kendi altyapısında çalıştıran Enterprise / on-prem müşteriler içindir.

Sohbet widget'ı (gömme)

nivq sohbetini tek bir tag ile herhangi bir siteye gömün — framework-bağımsız <nivq-chat> Web Component'i, secret'ınız tarayıcıya hiç gitmesin diye küçük bir token broker, tema ve yapılandırma.

nivq sohbetini herhangi bir siteye ya da uygulamaya tek bir tag ile ekleyebilirsiniz. Widget, framework-bağımsız bir Web Component'tir (<nivq-chat>) — düz HTML, React, Angular ya da Vue'da aynı şekilde çalışır — ve bir Shadow DOM içinde render olur; yani stilleri sayfanıza sızmaz, sayfanızın CSS'i de onu bozmaz.

HTML
<script type="module" src="https://cdn.jsdelivr.net/npm/nivorbit-chat-widget@1/dist/nivq-chat.js"></script>
<nivq-chat
  agent-id="AJAN_ID"
  api-base-url="https://api.example.com"
  token-endpoint="/nivq-token">
</nivq-chat>

token-endpoint, kendi sunucunuzda barındırdığınız tek parçadır. Nedenini görelim.

Kimlik doğrulama nasıl işliyor — önce bunu okuyun

Bir nivq API client'ı, client_credentials akışında kullanılan bir OAuth2 kimlik çiftidir (clientId + clientSecret):

clientId + clientSecret    POST /oauth2/token    kısa ömürlü erişim token'ı (~1s)
erişim token'ı (Bearer)    POST /v1/agents/{agentId}/conversations   (sohbet)

clientSecret uzun ömürlü bir kök kimlik bilgisidir — onu okuyan herkes token üretip kullanımınızı şişirebilir. Bu yüzden asla tarayıcıya gitmemelidir. Widget yalnızca kısa ömürlü bir erişim token'ı tutar ve bunu sizin backend'inizdeki küçük bir uç noktadan ("token broker") alır. Secret sunucunuzda kalır.

Tarayıcı (widget) ──POST──►  sizin /nivq-token  ──client_credentials──►  NivQ /oauth2/token
                                 
       └──── { access_token } ◄────┘     (secret tarayıcıya asla dönmez)

Secret'ı tarayıcıya asla göndermeyin

clientSecret'ı widget'a, istemci tarafı JS'e ya da herkese açık bir config'e koymayın. Sunucunuzda tutun; widget'a yalnızca kısa ömürlü token'ı verin.

1. Bir API client oluşturun

nivq'da bir API client oluşturun (clientId + clientSecret veren ekran). Bu anahtarda, widget'ın gömüleceği her web origin'ini İzinli origin'ler (Allowed origins) altında listeleyin — örn. https://app.acme.com — çünkü widget sohbeti doğrudan tarayıcıdan API'nize akıtır (bkz. aşağıdaki Gömme origin'inizi izinleyin).

2. Bir token broker çalıştırın

Broker, backend'inizdeki tek bir uç noktadır. Sizin son kullanıcınızı kendi oturumunuzla doğrular, secret'ı bir token'la takas eder ve yalnızca { access_token, expires_in } döner. Widget token'ı cache'leyip süresi dolmadan yeniler.

JS
// Node / Express
import express from "express";
const app = express();

app.post("/nivq-token", async (req, res) => {
  // 1. KENDİ kullanıcınızı doğrulayın (session/cookie/JWT). Girişli değilse reddedin.
  // if (!req.user) return res.sendStatus(401);

  // 2. Secret'ı kısa ömürlü bir token'la takas edin.
  const r = await fetch(`${process.env.NIVQ_API_BASE}/oauth2/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id: process.env.NIVQ_CLIENT_ID,
      client_secret: process.env.NIVQ_CLIENT_SECRET, // sunucuda kalır
    }),
  });
  if (!r.ok) return res.sendStatus(502);
  const { access_token, expires_in } = await r.json();

  // 3. YALNIZCA token'ı dönün — secret'ı asla.
  res.json({ access_token, expires_in });
});
JAVA
// Spring Boot
@RestController
class NivqTokenBroker {

  private final RestClient client = RestClient.create();

  @Value("${nivq.api-base}")      String apiBase;
  @Value("${nivq.client-id}")     String clientId;
  @Value("${nivq.client-secret}") String clientSecret; // sunucuda kalır

  @PostMapping("/nivq-token")
  Map<String, Object> token(/* kimliği doğrulanmış principal'ı buraya enjekte edin */) {
    var form = new LinkedMultiValueMap<String, String>();
    form.add("grant_type", "client_credentials");
    form.add("client_id", clientId);
    form.add("client_secret", clientSecret);

    var resp = client.post()
        .uri(apiBase + "/oauth2/token")
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .body(form)
        .retrieve()
        .body(Map.class);

    // Yalnızca token + süre dönün — secret'ı asla.
    return Map.of("access_token", resp.get("access_token"),
                  "expires_in",   resp.get("expires_in"));
  }
}

3. Widget'ı gömün

Düz HTML / herhangi bir site

HTML
<script type="module" src="https://cdn.jsdelivr.net/npm/nivorbit-chat-widget@1/dist/nivq-chat.js"></script>
<nivq-chat agent-id="" api-base-url="https://api.example.com" token-endpoint="/nivq-token"></nivq-chat>

React

Paketlenmiş uygulamalar için npm'den kurun:

Shell
npm i nivorbit-chat-widget
TSX
import "nivorbit-chat-widget"; // <nivq-chat>'i kaydeder; kendi tiplerini getirir

export function Support() {
  return (
    <nivq-chat
      agent-id=""
      api-base-url="https://api.example.com"
      token-endpoint="/nivq-token"
    />
  );
}

Paket tip tanımlarını içerir, yani tag hazırdan tipli gelir. React 19'un katı JSX'inde editörünüz tag'i işaretlerse tek satırlık bir modül augmentation ekleyin:

TS
declare module "react" {
  namespace JSX {
    interface IntrinsicElements {
      "nivq-chat": any;
    }
  }
}

Angular

TS
// app.module.ts — custom element'lere izin ver
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
export class AppModule {}
HTML
<nivq-chat agent-id="" api-base-url="https://api.example.com" token-endpoint="/nivq-token"></nivq-chat>

Yapılandırma

Özellik (attribute)ZorunluVarsayılanAçıklama
agent-idSohbet edilecek nivq ajanı
token-endpointToken broker URL'iniz
api-base-urlnivq sohbet API tabanı (kendi kurulumunuz)
modefabfab (yüzen başlatıcı) veya inline
targetYalnızca inline: gömüleceği kabın CSS seçicisi
positionbottom-rightbottom-right veya bottom-left (FAB)
themeautolight, dark veya auto (OS'i izler)
localeautotr, en veya auto (tarayıcı dili)
primary-colorNivQ markasıHex (#6d28d9) ya da HSL üçlüsü (265 70% 50%)
accent-colorNivQ markasıHex ya da HSL üçlüsü
radius0.625remKöşe yarıçapı (herhangi bir CSS uzunluğu)
logo-urlNivQ logosuMarka logosunu değiştirir
brand-nameNivQBaşlık / logo alt metni
launcher-labelFAB ikonunun yanındaki metin
greetingÖzel boş-durum başlığı
placeholderyerelleştirilmişGirdi placeholder metni
external-user-idSon kullanıcınızı ayırt eder (analitik / izolasyon)
persistfalseSohbeti localStorage'da saklar
start-openfalseYalnızca FAB: açılışta paneli açar

JavaScript'ten de yönetebilirsiniz:

JS
const el = document.querySelector("nivq-chat");
el.configure({ primaryColor: "#6d28d9", brandName: "Acme Assistant", mode: "inline" });

Tema

Varsayılanlar nivq markasıdır. Ana token'ları geçersiz kılın; gerisi onlardan türetilir:

HTML
<nivq-chat  primary-color="#6d28d9" accent-color="#f59e0b" radius="14px"
  logo-url="https://acme.com/logo.svg" brand-name="Acme Assistant"></nivq-chat>

Gömme origin'inizi izinleyin

Widget sohbeti doğrudan tarayıcıdan api-base-url'inize akıtır (broker yalnızca token üretir), bu yüzden API'nizin sitenizin origin'ine izin vermesi gerekir. Bunu API client'ta ayarlayın: İzinli origin'ler altında widget'ın gömülü olduğu her origin'i listeleyin — şema://host[:port], yol ya da joker olmadan, örn. https://app.acme.com. Liste boşsa o anahtar için tarayıcı gömme kapanır (yalnızca sunucu-sunucu kullanım). Değişiklikler bir dakika içinde etkin olur.

On-prem

api-base-url'i kendi nivq kurulumunuza yönlendirin; aynı anahtar-bazlı İzinli origin'ler geçerlidir. Gömme alan adlarını merkezî yönetmeyi tercih ederseniz deployment-geneli CORS_ALLOWED_ORIGIN_PATTERNS ayarı da aynı işi yapar — bkz. Yapılandırma.

Gizlilik

Bir API client, entegrasyonunuzun tüm son kullanıcıları arasında paylaşılır ve sohbet geçmişi kişiye değil, client'a göre kapsanır. Bu yüzden widget her oturumu yerelde tutar (bellekte ya da persist açıkken localStorage'da) ve paylaşılan geçmişi yüklemez. Son kullanıcılarınızı nivq tarafında ayırt etmek için external-user-id kullanın.