nessie

Nessie’yi kurma

Nessie’yi seçtiğiniz altyapıda çalıştırın: tek bir makineden yönetilen bulut ortamına kadar.

Başlamadan önce ihtiyacınız olanlar

Nessie, Node servislerinden oluşan bir pnpm monorepo’su ve iki statik paketten oluşur. Hangi yöntemle çalıştırırsanız çalıştırın, önce aynı dört şeyin hazır olması gerekir.

  • pgvector eklentili PostgreSQL. İsteğe bağlı değildir ve başka bir veritabanıyla değiştirilemez. Geçişler CREATE EXTENSION vector komutunu çalıştırır ve vector(1024) sütunlarını oluşturur. Üretim ortamı pgvector/pgvector:pg17 kullanır.
  • Node 22 ve pnpm. infrastructure/docker/ içindeki her Dockerfile node:22-slim üzerine kurulur ve depo, paket yöneticisini kök package.json dosyasında sabitler (pnpm@10.22.0).
  • OpenAI uyumlu bir model uç noktası ve onun anahtarı. Ajanlar ve embedding’ler ikisi de bu uç noktadan geçer. Aşağıdaki “Çıkarımın yapılandırılması” bölümüne bakın.
  • S3 uyumlu nesne depolama, yerel geliştirici kurulumu dışındaki her dağıtım için gereklidir. local modu dışında yerel disk üzerindeki yüklemeler reddedilir ve bu ret, bozuk ama çalışan bir başlatma değil, doğrudan bir başlatma hatasıdır. Bkz. “Tek makine mi, yönetilen bulut mu”.

Aşağıda anlatılan konteyner yolu için Docker ve bir ters proxy gerekir; internetten erişilebilecek her şey için ise bir alan adı ve TLS gerekir.

Belirli sayıda kişi için minimum CPU, bellek ve disk gibi donanım boyutlandırması depoda hiçbir yerde belirtilmediği için bu sayfa da bunu belirtmez.

Bileşenler ve birbirine nasıl bağlandıkları

BileşenNedirDışarıdan erişim
api/Fastify HTTP/WebSocket API’si. Her istemci yalnızca bununla konuşur.Evet
worker/Ajan orkestrasyonu ve arka plan çalışmaları. İş kuyruğunu yoklar; bir bağlantı noktası dinlemez.Hayır
admin/Ürün arayüzü — Vite ile derlenen ve nginx ile sunulan statik bir paket.Evet
web/Herkese açık site. Statiktir ve isteğe bağlıdır; ürünün çalışmasıyla ilgisi yoktur.Evet
PostgreSQLVeritabanı, iş kuyruğu ve gerçek zamanlı veri yolu — üçü birden.Hayır
Nesne depolamaEkler, avatarlar ve bilgi tabanı dosyaları. S3 uyumludur; üretimde MinIO kullanılır.Hayır
gateway/APNs ve FCM için isteğe bağlı bir push aktarıcısı. Siz bilerek etkinleştirmedikçe kapalıdır.Evet

API ve worker tek bir imajdır. İki paket birbirine çok sıkı bağlı olduğundan Dockerfile.app tüm ekibi bir kez derler ve worker konteyneri komutu node worker/dist/index.js olarak geçersiz kılar. local modunda hiç worker konteyneri yoktur: API, worker’ı kendi sürecinin içinde çalıştırır.

Redis yoktur. İş kuyruğu ve gerçek zamanlı aktarım ikisi de Postgres üzerinde çalışır; bu bir ihmal değil, bilinçli bir karardır. Google Cloud ağacı da Pub/Sub ve Redis modüllerini aynı nedenle siler.

Bağlantı noktaları

Yerel geliştirmede API varsayılan olarak 5454, yönetim arayüzü 5455 üzerindedir. Bir checkout, ortamda ya da deponun .env dosyasında NESSIE_API_PORT ve NESSIE_ADMIN_PORT değerlerini ayarlayarak kendi çiftini alabilir; depodaki her araç, tarayıcı test paketleri dahil, aynı iki değeri okur. Çifti başlamadan önce seçin ve sabit tutun: çalışan bir servisi başka bir porta taşımak, yönetim arayüzünün yanlış API ile konuşmasına yol açar.

Üretim farklıdır ve bu kural onu değiştirmez. API konteyneri iç olarak 5554 üzerinde dinler (NESSIE_API_PORT ile sabitlenmiştir), push aktarıcısı ise 5556 üzerinde; ikisi de ters proxy’nin arkasındadır.

Tek makinede, geliştirme için çalıştırmak

Depo, yalnızca bir veritabanı içeren bir Compose dosyasıyla gelir; yerel geliştirme döngüsünün ihtiyacı olan tek şey budur.

pnpm install
docker compose -f infrastructure/compose/docker-compose.yml up -d postgres

Bu konteyner, kullanıcı adı, parola ve veritabanı adı nessie olan bir Postgres’i 55432 portunda yayımlar. Bağlantı dizesini depo kökündeki bir .env dosyasına koyun — API’nin geliştirme betiği bunu okur — sonra geçişleri uygulayın ve worker’ı bir kez derleyin, çünkü yerel modda API worker’ı derlenmiş dist klasöründen yükler:

DATABASE_URL=postgresql://nessie:nessie@localhost:55432/nessie

pnpm --filter @nessie/api prisma:migrate:deploy
pnpm --filter @nessie/worker build
pnpm dev

pnpm dev, API’yi ve yönetim arayüzünü 5454 ve 5455 portlarında, sıcak yeniden yükleme ile paralel çalıştırır. API’nin GET /api/health ile yanıt verdiğini kontrol edin.

Postgres ve pgvector gereksinimi

Üç eklenti geçişlerin kendisi tarafından oluşturulur — vector, pg_trgm ve pgcrypto — bu yüzden bunları çalıştıran rolün eklenti oluşturmasına izin verilmiş olmalıdır. Yönetilen bir Postgres’te önce bunu kontrol etmeniz gerekir.

Vektör genişliği bir ayar değil, şemanın bir parçasıdır. thoughts.embedding, thought_recalls.query_embedding ve knowledge_page_chunks.embedding birer vector(N) sütunudur ve N, packages/schemas/src/embedding.ts içinde EMBEDDING_DIMENSIONS olarak bir kez tanımlanır — şu anda 1024, üretimin kullandığı embedding modelinin doğal genişliği. Her embedding isteği bu genişliği gönderir; başka bir genişlikte yanıt veren bir sağlayıcı, veritabanının reddedeceği vektörleri yazmak yerine yüksek sesle başarısız olur. Farklı genişlikte bir embedding modeline geçmek, bu sabiti değiştirmeyi, üç sütunu yeniden tanımlayan bir geçiş yazmayı ve yeniden embedding yapmayı gerektirir. Farklı genişlikteki vektörler dönüştürülemez; bu yüzden geçiş bunları kırpmak yerine boşa (NULL) çeker.

Nessie’yi paylaşılan bir Docker ağında başka uygulamalarla birlikte çalıştırıyorsanız, veritabanı konteynerine ayrı bir ad verin. Projenin kendi Compose servisinin adı nessie-postgres’tir, asla postgres değildir; çünkü servis adı paylaşılan ağda bir DNS takma adı olur ve çakışma, postgres:5432 adresinin iki veritabanı arasında dönüşümlü olarak yönlendirilmesine yol açar.

Yapılandırma

Çalışma zamanı yapılandırması katmanlıdır: API ve worker’a salt okunur olarak bağlanan bir nessie.config.json dosyası vardır ve üstüne ortam değişkenleri uygulanır. İkisi arasındaki eşleme packages/config içindeki ConfigEnvMap’tir ve yetkili listedir.

NESSIE_MODE dağıtım biçimini seçer: local (varsayılan ve geliştirici yolu), hosted veya selfHosted — kendi sunucusuna kurulumun ayarladığı değer budur. Geliştirici girişini devre dışı bırakır ve bir CORS izin listesi gerektirir.

selfHosted dağıtımının bunlar olmadan başlamayacağı ya da çalışmayacağı ayarlar şunlardır:

DeğişkenNeden
DATABASE_URL / NESSIE_DB_URLPostgres bağlantı dizesi.
NESSIE_AUTH_SECRETHex biçiminde 32 bayt (openssl rand -hex 32). Oturumları ve önyükleme belirteçlerini imzalar. local modu dışında bu olmadan başlatma hata verir; her replikada ve dağıtımlar boyunca aynı değer olmalıdır, yoksa her sürümde tüm oturumlar sona erer.
NESSIE_ENCRYPTION_KEY_RING, NESSIE_ENCRYPTION_ACTIVE_KEY_VERSIONJSON biçiminde bir anahtar halkası ve etkin kökü seçen etiket; local dışında gereklidir. Bu, imzalama sırrından ayrı bir köktür — halka Nessie’nin sakladığı her kalıcı sırrı şifreler. Birini diğeri yerine kullanmayın.
NESSIE_STORAGE_PROVIDERs3 olmalıdır. filesystem varsayılandır ve hosted ile selfHosted modlarında reddedilir; böylece burada hiçbir şey ayarlanmamış bir dağıtım, yüklemeleri başka hiçbir konteynerin okuyamadığı bir diske yazmak yerine başlamaz.
NESSIE_CORS_ORIGINSYönetim arayüzünün origin’i. Yönetim arayüzü ile API ayrı origin’lerdir ve API, sunduğu origin’i izin listesine eklemelidir.
NESSIE_API_PUBLIC_URL, NESSIE_ADMIN_PUBLIC_URLOAuth yönlendirme URI’lerini bir HTTP isteği dışında üretmek için kullanılır. İlki olmadan API, istek anında hata verir.
NESSIE_MODEL_PROVIDER, _BASE_URL, _API_KEYÇıkarımın nereye gideceği. Aşağıya bakın.

infrastructure/compose/.env.prod.example bunların tümünün tam biçimini içerir; isteğe bağlı bloklar — nesne depolama, sır kasası, SSO, bağlı e-posta — yerinde yorum satırı olarak bırakılmıştır. Her isteğe bağlı ayarı içeren tam liste docs/deployment/configuration.md dosyasındadır.

Docker Compose ile dağıtmak

.env.prod.example dosyasını docker-compose.prod.yml dosyasının yanına .env olarak kopyalayın ve doldurun; ardından veritabanını ayağa kaldırın, derleyin, geçişleri uygulayın ve başlatın. Sıra önemlidir: geçişler ve tohum (seed) verileri, hiçbir servis hizmet vermeden önce, zaten çalışan bir veritabanına karşı çalışır.

COMPOSE="docker compose -f infrastructure/compose/docker-compose.prod.yml"

bash infrastructure/compose/ensure-encryption-key-ring.sh infrastructure/compose/.env
$COMPOSE up -d nessie-postgres
$COMPOSE build nessie-api nessie-admin nessie-web
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api prisma:migrate:deploy
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api seed:connectors
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api seed:apps
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api reconcile
$COMPOSE up -d

Üretim Dockerfile’ları her paketi derlemeden önce lint’ten geçirir; dolayısıyla lint hatası bir derleme hatasıdır.

Reconcile adımı isteğe bağlı değildir

reconcile, her kuruluşun varsayılan politika kurallarını tohumlar ve korumalı MCP ile Kişisel Asistan araç izinlerini geriye dönük olarak doldurur. API bunu eskiden her replikada başlangıçta yapardı; artık yalnızca bağlanır, dinler ve başka bir şey yapmaz. Bu nedenle bu adım olmadan ilk kuruluşun hiç politika kuralı olmaz ve her ajan bağlantısı reddedilir. İdempotenttir; bu yüzden her dağıtımda çalıştırmak bedavadır. Elle uygulanan bir güncelleme de bunu çalıştırmak zorundadır.

İlk sahip hesabı

Yeni bir selfHosted kurulumda hiç kullanıcı yoktur; API tek kullanımlık bir önyükleme belirteci üretir ve bir kurulum URL’si kaydeder. Belirteç bir sürece değil Postgres’e yazılır; böylece her replika onun üzerinde anlaşır.

docker compose -f infrastructure/compose/docker-compose.prod.yml logs nessie-api 2>&1 | grep bootstrap

https://<your-admin-host>/bootstrap?token=<token> adresini açın ve sahip hesabını oluşturun. Belirtecin süresi 15 dakikada dolar; yenisini üretmek için API servisini yeniden başlatın.

SSO yapılandırırsanız hiçbir önyükleme adımı yoktur. Harici bir kimlik sağlayıcı etkinleştirildiği anda önyükleme modu bastırılır — aksi halde giriş ekranını ele geçirirdi — ve SSO ile ilk giriş yapan kişi varsayılan ekibi oluşturur ve onun sahibi olur.

Çıkarımın yapılandırılması

Sohbet OpenAI uyumludur. NESSIE_MODEL_BASE_URL uç noktadır, NESSIE_MODEL_API_KEY bearer anahtarıdır ve NESSIE_MODEL_PROVIDER adaptörü adlandırır — Nessie openai, kimi ve deepseek için adaptörleri derler, diğer her şeye ise genel OpenAI uyumlu bağlayıcı üzerinden ulaşır. NESSIE_MODEL_NAME dağıtımın varsayılan modelini belirler; tek bir ajanın kendi model seçimi ise bu varsayılanın önüne geçer.

Embedding’ler ayrı yönlendirilir, çünkü sohbet sağlayıcısı bunları hiç sunmayabilir — örneğin DeepSeek’in bir embedding uç noktası yoktur. Ayarlanmamış her NESSIE_EMBEDDING_* alanı sohbet sağlayıcısını devralır; yani bunlardan hiçbirini ayarlamayan bir dağıtım, sohbet uç noktası üzerinden embedding yapar. Sohbet sağlayıcısı embedding yapamıyorsa NESSIE_EMBEDDING_PROVIDER ve NESSIE_EMBEDDING_MODEL ile, hizmete göre yönlendiren bir proxy’de hizmet segmentini de ayarlayın. Bunu yanlış yapmak yüksek sesle değil sessizce başarısız olur: bellek geri çağırma ve bilgi tabanı araması sözcüksel bir kanala geçer ve çalışmaya devam eder; bu sırada kb_search: query embedding failed kaydı düşer.

Nessie’nin kendi harcama muhasebesi — kuruluş başına token defteri ve bütçe kapısı — hangi uç noktaya yönlendirdiğinizden etkilenmez ve imzalı çağrı başına atıf yapılandırılmış olup olmamasından bağımsız olarak aynı çalışır.

Giriş yapmak

Nessie, kişileri UnlikeOtherAI üzerinden doğrular; kuruluş ve ekip yapısını da o yönetir. Yönetim arayüzünün giriş sayfasında tek bir “Login / Register” düğmesi görünür.

Entegrasyon standart OIDC değil, bir config-JWT akışıdır: API, GET /api/auth/sso/config adresinde imzalı bir RS256 yapılandırma belgesi sunar ve eşleşen JWKS’i GET /.well-known/jwks.json adresinde sunar; ikisi de API sunucusunda bulunur. Bunu kurmak tek seferlik bir sıralamadır: bir RSA-2048 anahtar çifti üretin ve UOA_CONFIG_JWT_PRIVATE_KEY_B64, UOA_CONFIG_JWT_KID, UOA_DOMAIN, UOA_CONFIG_URL, UOA_JWKS_URL, UOA_REDIRECT_URL ve UOA_CONTACT_EMAIL değerlerini ayarlayın; düğmeye bir kez tıklayın, bu bir entegrasyon isteği açar; isteğin onaylanmasını bekleyin, bu da istemci sırrını taşıyan tek kullanımlık bir bağlantıyı iletişim adresine gönderir; ardından UOA_CLIENT_SECRET değerini ayarlayın ve API’yi yeniden başlatın. kid her alan adı için benzersiz olmalıdır.

Bir alan adının arkasında, TLS ile yayımlamak

Bir dağıtım üç adı sunar: herkese açık site, yönetim arayüzü ve API. Yönetim arayüzü ve API origin’leri birbirinin yerine kullanılamaz. Dockerfile.admin, VITE_API_BASE_URL değerini derleme zamanında pakete gömer; bu yüzden gömülü bir masaüstü derlemesi dahil her yönetim arayüzü çıktısı API origin’ine karşı derlenmelidir. Yönetim arayüzünün kendi origin’ine karşı derlerseniz /api/auth/providers yönetim arayüzünün HTML kabuğuna çözümlenir ve giriş “Loading providers...” ekranında takılı kalır.

Üretimde TLS, Caddy tarafından sonlandırılır; Caddy her ana makine adı için HTTP-01 üzerinden sertifika alır ve bunun için bir DNS sağlayıcı eklentisine ihtiyaç duymaz. Proxy’yi yönetim ve site konteynerlerinin 80. portuna, API’yi ise iç portuna yönlendirin.

NESSIE_API_TRUSTED_PROXY_HOPS değerini API’nin önündeki proxy sayısına ayarlayın — tek bir ters proxy arkasında 1. Varsayılanı 0’dır ve bu, X-Forwarded-For başlığını tamamen yok sayar. Bu tek bir karardır ve iki sonucu vardır: kimlik doğrulama hız sınırlarının da anahtarını oluşturur. Bu yüzden çok düşükse her istemci proxy’nin kovasını paylaşır, çok yüksekse bir istemci kendi adresini taklit edebilir. Düşük tarafta hata yapın ve ölçün.

Her kuruluşu ve ekibi kendi alt alan adında sunmak mümkündür ve varsayılan olarak kapalıdır. NESSIE_TEAM_HOST_BASE_DOMAIN tarafından yönetilir; ayarlanmamışsa kiracılar hiç ana makine adına göre yönlendirilmez. Sertifika verme kapısı NESSIE_TLS_CHECK_KEY ise bu ayar yapılmadığı sürece her şeyi reddeder — özelliği kullanmayan bir dağıtım için doğru varsayılan budur.

Sağlık denetimleri

Uç noktaYanıtladığı soru
GET /api/healthBu süreç hayatta mı? Yalnızca boşaltmaya başladığında başarısız olur.
GET /api/health/readyBu replika yeni istekleri alabilir mi? Yük dengeleyicinizin yönelteceği uç nokta budur.
GET /api/ops/healthDağıtım nasıl gidiyor? Bir kişi için bir rapor — worker kalp atışları, kuyruk derinliği, ölü işler — bir probe değil.

SIGTERM alındığında API, olduğu yerde ölmek yerine boşaltır. NESSIE_SHUTDOWN_TIMEOUT_MS bu boşaltmayı sınırlar ve varsayılanı 25 saniyedir; bunu orkestratörünüzün konteynere tanıdığı bekleme süresinin altında tutun, yoksa çalışma zamanı süreci önce öldürür ve boşaltmanın hiçbir faydası kalmaz.

Yükseltme

Yükseltme, mevcut veritabanına karşı prisma migrate deploy, ardından tohum verileri ve reconcile çalıştırmaktır. İlk dağıtımdaki dört komutun aynısıdır.

Yol, taze bir veritabanına karşı değil, kendi sunucusunu işleten birinin gerçekten izleyeceği rota için test edilir: CI, yirmi geçiş geride kalmış bir anlık görüntüyü geri yükler, en son sürüme geçirir, şemayı doğrular ve temel tablolar üzerinde bir duman testi çalıştırır. Bu kayan pencere içindeki her sürüm kanıtlanmış bir yükseltme kaynağıdır. Geçiş klasörleri commit edildikten sonra değişmez; biri yeniden adlandırılır, yeniden numaralandırılır, silinir veya değiştirilirse lint adımı derlemeyi başarısız kılar, çünkü bunların dördü de eski satırı kaydetmiş bir veritabanı için migrate deploy komutunu bozar.

Tek bir başarısız geçiş, ondan sonraki her dağıtımı durdurur. migrate deploy ilk hatada durur ve sonraki her geçişi P3009 ile reddeder; bu yüzden kurulum, biri elle temizleyene kadar eski sürümde kalır. Projenin kendi üretim ortamı bir gün boyunca her dağıtımı bu şekilde reddetti. Birini temizlemek, başarısız geçişin gerçekten geri alındığını doğrulamak demektir — oluşturduğu nesnelerin hiçbiri var olmamalı, değiştirdiği her şey özgün biçimini korumalıdır — ve ancak bundan sonra geri alınmış olarak çözümleyin. Yarı uygulanmış bir geçiş aday değildir.

Kendi sunucusunda Compose ile çalışan dağıtım için yedekleme ve geri yükleme depoda belgelenmemiştir; bu nedenle bu sayfa bunun için bir prosedür tanımlamaz.

Tek makine mi, yönetilen bulut mu

Yukarıdaki tek sunuculu Docker Compose yolu kanıtlanmış olandır: projenin kendi üretim ortamı da bunu çalıştırır; tek bir sunucuda veritabanı, nesne depolama, API, worker, yönetim arayüzü ve site, paylaşılan bir ters proxy arkasında konteyner olarak çalışır.

Tek makineden ölçeklendirmek üç şeyi değiştirir ve bunların hepsi tavsiye değil, zorunlu kılınır. local modu dışında Nessie API’yi ve worker’ı ayrı süreçler olarak, her birinden birden fazla kopyayla çalıştırır; bu yüzden makinenin diskine tek bir sürecin sahip olduğunu varsayan her yetenek reddedilir: dosya sistemi nesne depolama (başlatma hatası), docker sağlayıcılı yürütme ortamı şablonları (etkisiz ve provizyon yüksek sesle başarısız olur) ve file_read, file_write ile file_glob yerleşik araçları (ajanın okuyabileceği başarısız bir araç sonucu). Her ret, ayarı, modu ve bunun yerine ne kullanılacağını adlandırır.

Yönetilen bir bulut için depo, Google Cloud’u hedefleyen bir Terraform ağacı içerir (infrastructure/terraform/): API, en az bir örnekle bir Cloud Run servisi olarak çalışır — kalıcı bir Postgres LISTEN istemcisi tutar ve bakım taramaları çalıştırır, bu yüzden sıfıra ölçeklemek gerçek zamanlı iletimi durdurur. Worker, bir Cloud Run worker havuzu olarak çalışır, çünkü bir bağlantı noktası dinlemez ve bir Service hiç hazır olmaz. Ayrıca her dağıtımı kapılayan bir migrate işi, Cloud SQL for PostgreSQL 17 ve S3 uyumlu arka uç üzerinden erişilen bir GCS kovası bulunur.

Bu yol yazılmış, ama henüz denenmemiştir. Depo bunu açıkça söyler ve bu sayfa da öyle söyler: bunun için bir Google Cloud projesi yoktur, ağaçtaki hiçbir şey gerçek bir projeye karşı planlanmamış ya da uygulanmamıştır, GCS’ye çok parçalı yükleme yolu gerçek bir kovaya karşı test edilmemiştir, worker havuzu kaynak türü doğrulanmamıştır ve buradaki güvenilir proxy hop sayısı bir ölçüm değil, ölçülmesi gereken bir yer tutucudur. Yönetim arayüzü ve herkese açık site burada hiç modellenmemiştir. Bunu desteklenen bir dağıtım değil, doğrulayacağınız bir başlangıç noktası olarak görün.

Bir dağıtımın verilerinin nerede durduğu, yazılımın neyi tuttuğu ve bilerek neyi tutmadığı ayrı bir sayfadadır: AB’de üretildi ve verileriniz nerede.