chore(release): remove legacy runtime dependencies

This commit is contained in:
poyrazavsever
2026-07-17 09:13:23 +03:00
parent 5948907e5d
commit 8cd3de8e1f
42 changed files with 910 additions and 6207 deletions
+3 -5
View File
@@ -20,9 +20,7 @@ DATA_DIR=.data
# Optional explicit SQLite database path. Defaults to DATA_DIR/neta.db. # Optional explicit SQLite database path. Defaults to DATA_DIR/neta.db.
DATABASE_PATH= DATABASE_PATH=
# Legacy Supabase values are kept only while old feature data screens are being migrated. # Optional local OpenAI-compatible Ollama endpoint and AI request timeout.
NEXT_PUBLIC_SUPABASE_URL= OLLAMA_BASE_URL=http://127.0.0.1:11434/v1
NEXT_PUBLIC_SUPABASE_ANON_KEY= AI_REQUEST_TIMEOUT_MS=30000
SUPABASE_SERVICE_ROLE_KEY=
+135 -66
View File
@@ -1,106 +1,175 @@
<img src="public/logo/lightLogoLong.png" height="200" alt="Neta Icon" /> <img src="public/logo/lightLogoLong.png" height="160" alt="Neta" />
# Neta # Neta
Neta is a freelancer operating system built with Next.js and Supabase. It manages clients, projects, tasks, finance, daily logs, analytics, AI chat, and a limited client portal. Neta; freelancer'ların müşteri, proje, görev, takvim, finans, günlük, AI ve sınırlı müşteri portalı akışlarını kendi sunucularında yönetebildiği bir Next.js uygulamasıdır.
This repository now ships only the web application. It does not bundle Supabase, PostgreSQL, Docker Compose, installers, migration runners, or backup scripts. Bring your own Supabase project and provide the required environment variables in the deploy platform. Self-hosted v3 runtime'ı harici bir BaaS istemez:
## Live Demo - Next.js App Router ve React
- Better Auth
- SQLite (`better-sqlite3`) ve Drizzle ORM
- Yerel persistent dosya alanı
- Poyraz UI v3
- İsteğe bağlı Google, OpenAI, Groq veya Ollama AI sağlayıcısı
You can try the demo here: Supabase yalnızca eski bir Neta kurulumundan veri aktarmak için opsiyonel kaynak olabilir. Uygulamanın build veya runtime aşamasında Supabase projesi, paketi ya da environment değişkeni gerekmez.
```txt ## Çalışma modeli
https://demo.takeneta.com
Bir Neta instance'ı tek freelancer/owner ve birden fazla davetli müşteri hesabı için tasarlanmıştır. Uygulama tek bir uzun ömürlü Node.js process'i ve tek bir persistent data volume ile çalışır; aynı SQLite dosyasına yazan yatay ölçekli birden fazla replica desteklenmez.
Kalıcı veri ağacı:
```text
/app/data/
neta.db
uploads/
backups/
tmp/
``` ```
Demo account: ## Gereksinimler
```txt - Node.js 22
Email: test@takeneta.com - pnpm 11 (lokal geliştirme için)
Password: 123456 - Production'da kalıcı disk/volume
``` - Localhost dışındaki production kurulumunda HTTPS reverse proxy
## Stack ## Lokal kurulum
- Next.js App Router
- React
- Tailwind CSS
- Poyraz UI
- Supabase Auth, Postgres, Storage, and RLS
- Vercel AI SDK
## Requirements
1. A Supabase project that already contains Neta's database schema, RLS policies, RPC functions, and storage buckets.
2. Supabase project credentials:
- Project URL
- Anon/public key
- Service role key
3. Node.js 20 or newer.
See `docs/04-supabase-kurulumu.md` for the expected Supabase-side resources.
For a fresh Supabase project, run the one-shot setup SQL:
```bash ```bash
psql "postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres" -v ON_ERROR_STOP=1 -f supabase/setup.sql pnpm install --frozen-lockfile
cp .env.example .env.local
openssl rand -base64 32
``` ```
You can also paste the full contents of `supabase/setup.sql` into Supabase SQL Editor and run it once. Üretilen secret'ı `.env.local` içindeki `BETTER_AUTH_SECRET` alanına koyun, ardından:
## Environment Variables ```bash
pnpm db:migrate
pnpm dev
```
Copy `.env.example` to `.env.local` for local development, or add the same values in Vercel, Coolify, Dokploy, or your hosting provider. `http://localhost:3000/register` adresinden ilk owner hesabını oluşturun. İlk başarılı kurulumdan sonra public kayıt atomik olarak kapanır.
## Environment sözleşmesi
Minimum production örneği:
```env ```env
NEXT_PUBLIC_SITE_URL=https://your-domain.com NODE_ENV=production
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co NEXT_PUBLIC_SITE_URL=https://neta.example.com
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key APP_URL=https://neta.example.com
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key BETTER_AUTH_SECRET=openssl-ile-uretilmis-en-az-32-karakter-secret
DATA_DIR=/app/data
``` ```
`SUPABASE_SERVICE_ROLE_KEY` is server-only. Do not expose it with a `NEXT_PUBLIC_` prefix. Opsiyonel alanlar:
## Local Development - `BETTER_AUTH_URL`: Auth callback base URL override'ı.
- `TRUSTED_ORIGINS`: Virgülle ayrılmış ek güvenilir origin listesi; wildcard reddedilir.
- `DATABASE_PATH`: Varsayılan `DATA_DIR/neta.db` yerine özel SQLite yolu.
- `OLLAMA_BASE_URL`: Varsayılan `http://127.0.0.1:11434/v1`.
- `AI_REQUEST_TIMEOUT_MS`: AI istek timeout'u; varsayılan `30000`.
AI provider API key'leri environment'a yazılmaz; owner ayarından girilir, server-side şifreli saklanır ve browser'a geri dönmez.
## Docker ile production
```bash ```bash
npm install export BETTER_AUTH_SECRET="$(openssl rand -base64 32)"
npm run dev export APP_URL="https://neta.example.com"
export NEXT_PUBLIC_SITE_URL="$APP_URL"
docker compose up -d --build
``` ```
Open `http://localhost:3000`. Compose; `/app/data` için named volume bağlar, migration'ları uygulamadan önce çalıştırır, non-root user kullanır ve readiness healthcheck tanımlar. Domain/HTTPS sonlandırmasını Caddy, Traefik, Nginx, Coolify veya Dokploy üzerinden yapın.
## Production Build Health endpoint'leri:
- `/api/health/live`: Process liveness.
- `/api/health/ready`: SQLite, data directory ve migration readiness.
- `/api/health`: Hafif uyumluluk endpoint'i.
Coolify ve Dokploy'da repository'nin `Dockerfile` dosyasını kullanın, internal portu `3000` seçin ve `/app/data` yoluna persistent volume bağlayın. Tek replica kullanın. Ayrıntılı production ve upgrade runbook'u: [Faz 8 import/release rehberi](docs/self-hosted-redesign/phase-8-import-release.md).
## İlk owner ve müşteri daveti
İlk açılışta `/register` üzerinden freelancer hesabı oluşturulur. Sonraki kullanıcılar public kayıt olamaz.
Müşteri erişimi için:
1. Owner müşteri kaydını oluşturur.
2. Müşteri detayından süreli, tek kullanımlık davet üretir.
3. Müşteri linki açıp kendi şifresini belirler.
4. Better Auth hesabı ilgili müşteri kaydına transaction içinde bağlanır.
Davet token'ının yalnızca hash'i saklanır. Eski Supabase Auth şifre/session verileri import edilmez; taşınan müşteriler yeniden davet edilmelidir.
## Marka özelleştirmesi
Instance adı, kısa ad, açık/koyu logo, ikon, primary/accent renk, varsayılan görünüm ve radius yoğunluğu SQLite'ta tutulur ve root layout'a server-side uygulanır. Görseller yerel upload alanında saklanır. Branding mutation'ı yalnızca owner rolüne açıktır; portal aynı güvenli public marka çıktısını kullanır.
## Backup ve restore
Online SQLite snapshot ve upload ağacı:
```bash ```bash
npm run build pnpm db:backup
npm run start pnpm db:backup -- --retention-count 14
``` ```
## Deploy `BACKUP_RETENTION_COUNT=14` aynı retention politikasını cron ortamından verebilir. Her backup; byte size ve SHA-256 içeren bir manifest üretir.
### Vercel Restore sırasında uygulamayı durdurun:
1. Import the GitHub repository. ```bash
2. Add the environment variables from `.env.example`. pnpm db:restore -- --from /path/to/neta-backup --force
3. Deploy with the default Next.js settings. ```
### Coolify or Dokploy Farklı bir data directory'ye prova:
1. Create a standard Next.js application from this GitHub repository. ```bash
2. Use the platform's normal install/build/start commands: pnpm db:restore -- --from /path/to/neta-backup --target /tmp/neta-restore-test --force
- Install: `npm install` ```
- Build: `npm run build`
- Start: `npm run start`
3. Add the environment variables from `.env.example`.
No Dockerfile or Compose file is required. Restore önce manifest bütünlüğünü doğrular, dosyaları stage eder ve DB/upload ağacını aynı filesystem üzerinde atomik swap ile değiştirir. Hata olursa önceki hedef geri alınır. Backup'ları ayrıca host dışındaki şifreli bir konuma kopyalayın.
## First Admin ## Upgrade
After deploying against a prepared Supabase project, open `/register` once to create the first freelancer/admin account. Registration is locked after the first admin profile exists. 1. Mevcut sürümde backup alın ve geri yükleme provasını yapın.
2. Yeni image/tag'i indirin veya build edin.
3. Uygulamayı tek replica ile başlatın; container startup migration'ları deterministik uygular.
4. `/api/health/ready`, login, müşteri, proje ve portal akışlarını kontrol edin.
5. Sorunda eski image'i ve upgrade öncesi backup'ı kullanarak rollback yapın.
## License SQLite şema downgrade'i desteklenmez; yalnızca eski application image'ine dönmek yeterli değildir.
This project is proprietary and intended for personal self-hosting with an external Supabase project. ## Eski Supabase verisini aktarma
Önce bu instance'ta owner hesabını oluşturun, ardından export bundle üzerinde dry-run çalıştırın:
```bash
pnpm db:import:supabase -- \
--from /secure/path/neta-export \
--owner-user-id BETTER_AUTH_OWNER_ID \
--dry-run
```
Raporu doğruladıktan ve backup aldıktan sonra aynı komutu `--dry-run` olmadan çalıştırın. Bundle formatı, normalization kararları, dosya yapısı ve production cutover/rollback adımları [Faz 8 rehberinde](docs/self-hosted-redesign/phase-8-import-release.md) tanımlıdır.
## Kalite kontrolleri
```bash
pnpm typecheck
pnpm phase8:release-boundary
pnpm phase8:import-smoke
pnpm build
```
`phase8:release-boundary`; Supabase, PWA ve browser database bağımlılıklarının runtime'a geri dönmesini engeller.
## Lisans
Bu proje kişisel self-hosting amacıyla geliştirilen proprietary bir projedir.
+3 -4
View File
@@ -6,9 +6,8 @@ import {
import { getSessionContextFromHeaders } from "@/server/auth/session"; import { getSessionContextFromHeaders } from "@/server/auth/session";
/** /**
* Legacy adapter for the current client detail screen. * Compatibility adapter for the current client detail screen.
* The old endpoint created a Supabase Auth user with a freelancer-chosen password. * It issues a one-time Better Auth invitation and never accepts a password.
* It now issues a one-time Better Auth invitation and never accepts a password.
*/ */
export async function POST(request: Request) { export async function POST(request: Request) {
const actor = await getSessionContextFromHeaders(new Headers(request.headers)); const actor = await getSessionContextFromHeaders(new Headers(request.headers));
@@ -31,7 +30,7 @@ export async function POST(request: Request) {
return NextResponse.json({ error: error.message, code: error.code }, { status }); return NextResponse.json({ error: error.message, code: error.code }, { status });
} }
console.error("Legacy client invitation adapter failed", error); console.error("Client invitation adapter failed", error);
return NextResponse.json({ error: "Müşteri daveti oluşturulamadı." }, { status: 500 }); return NextResponse.json({ error: "Müşteri daveti oluşturulamadı." }, { status: 500 });
} }
} }
-2
View File
@@ -3,7 +3,6 @@ import type { CSSProperties } from "react";
import "./globals.css"; import "./globals.css";
import { Geist } from "next/font/google"; import { Geist } from "next/font/google";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { OfflineIndicator } from "@/components/ui/offline-indicator";
import { Toaster } from "poyraz-ui/molecules"; import { Toaster } from "poyraz-ui/molecules";
import { getPublicBranding } from "@/server/branding/runtime"; import { getPublicBranding } from "@/server/branding/runtime";
@@ -54,7 +53,6 @@ export default function RootLayout({
</head> </head>
<body> <body>
{children} {children}
<OfflineIndicator />
<Toaster closeButton richColors position="top-right" /> <Toaster closeButton richColors position="top-right" />
</body> </body>
</html> </html>
-28
View File
@@ -1,28 +0,0 @@
"use client";
import { useSyncExternalStore } from "react";
import { WifiOff } from "lucide-react";
export function OfflineIndicator() {
const isOnline = useSyncExternalStore(
(onStoreChange) => {
window.addEventListener("online", onStoreChange);
window.addEventListener("offline", onStoreChange);
return () => {
window.removeEventListener("online", onStoreChange);
window.removeEventListener("offline", onStoreChange);
};
},
() => navigator.onLine,
() => true,
);
if (isOnline) return null;
return (
<div className="fixed bottom-4 right-4 z-50 flex items-center gap-2 rounded-lg bg-destructive px-4 py-2 text-sm font-medium text-destructive-foreground shadow-lg animate-in fade-in slide-in-from-bottom-4">
<WifiOff className="h-4 w-4" />
Çevrimdışı moddasınız. Değişiklikler senkronize edilmeyecek.
</div>
);
}
+3
View File
@@ -2,10 +2,13 @@
title: Giriş title: Giriş
description: Neta'nın ne olduğunu, kimler için tasarlandığını ve hangi problemi çözdüğünü anlatır. description: Neta'nın ne olduğunu, kimler için tasarlandığını ve hangi problemi çözdüğünü anlatır.
order: 1 order: 1
status: legacy-v2-archive
--- ---
# Giriş # Giriş
> Arşiv: Bu belge Supabase tabanlı Neta v2'yi anlatır. Güncel self-hosted v3 kaynağı repository `README.md` dosyası ve `docs/self-hosted-redesign/phase-8-import-release.md` belgesidir.
Neta'yı freelancer olarak çalışan birinin işlerini tek yerden yönetebilmesi için tasarladım. Gün içinde müşteri takibi, proje ilerlemesi, görevler, finansal durum, kişisel performans ve bazen de hızlıca soru sorabileceğim bir AI asistan ihtiyacı birbirinden kopuk araçlara dağılıyordu. Neta'nın çıkış noktası bu dağınıklığı azaltmak. Neta'yı freelancer olarak çalışan birinin işlerini tek yerden yönetebilmesi için tasarladım. Gün içinde müşteri takibi, proje ilerlemesi, görevler, finansal durum, kişisel performans ve bazen de hızlıca soru sorabileceğim bir AI asistan ihtiyacı birbirinden kopuk araçlara dağılıyordu. Neta'nın çıkış noktası bu dağınıklığı azaltmak.
Bu proje bir ajans yönetim paneli olmaktan çok, bireysel çalışan bir freelancerın kendi operasyonunu düzenli tutması için hazırlanmış bir çalışma alanı. Temel fikir şu: müşterilerimi, projelerimi, görevlerimi, gelir-giderimi, günlük notlarımı ve müşteri portalını aynı sistem içinde görebileyim. Bu proje bir ajans yönetim paneli olmaktan çok, bireysel çalışan bir freelancerın kendi operasyonunu düzenli tutması için hazırlanmış bir çalışma alanı. Temel fikir şu: müşterilerimi, projelerimi, görevlerimi, gelir-giderimi, günlük notlarımı ve müşteri portalını aynı sistem içinde görebileyim.
+3
View File
@@ -2,10 +2,13 @@
title: Özellikler title: Özellikler
description: Neta'nın freelancerlar için sunduğu temel özellikler. description: Neta'nın freelancerlar için sunduğu temel özellikler.
order: 2 order: 2
status: legacy-v2-archive
--- ---
# Özellikler # Özellikler
> Arşiv: Bu belge Supabase tabanlı Neta v2'yi anlatır. Güncel self-hosted v3 kaynağı repository `README.md` dosyası ve `docs/self-hosted-redesign/phase-8-import-release.md` belgesidir.
Neta'yı parça parça özellik eklenmiş bir panel gibi değil, günlük iş akışımı toparlayan bir işletim alanı gibi düşünerek geliştirdim. Her modül tek başına işe yarıyor, ama asıl değer bu modüllerin birbirine bağlanmasında ortaya çıkıyor. Neta'yı parça parça özellik eklenmiş bir panel gibi değil, günlük iş akışımı toparlayan bir işletim alanı gibi düşünerek geliştirdim. Her modül tek başına işe yarıyor, ama asıl değer bu modüllerin birbirine bağlanmasında ortaya çıkıyor.
## Dashboard ## Dashboard
+3
View File
@@ -2,10 +2,13 @@
title: Mimari title: Mimari
description: Neta'nın teknik mimarisi, frontend/backend ayrımı ve Supabase bağlantısı. description: Neta'nın teknik mimarisi, frontend/backend ayrımı ve Supabase bağlantısı.
order: 3 order: 3
status: legacy-v2-archive
--- ---
# Mimari # Mimari
> Arşiv: Bu mimari Supabase tabanlı Neta v2'ye aittir. Güncel SQLite/Better Auth mimarisi repository `README.md` dosyasında ve ana dönüşüm planında tanımlıdır.
Neta'yı klasik bir frontend-backend ayrımından çok, Next.js App Router etrafında şekillenen bir uygulama olarak kurguladım. Uygulamanın backend işlerinin büyük bölümü Supabase üzerinde duruyor. Next.js tarafı ise hem arayüzü hem de server action ve API route gibi uygulama mantığını taşıyor. Neta'yı klasik bir frontend-backend ayrımından çok, Next.js App Router etrafında şekillenen bir uygulama olarak kurguladım. Uygulamanın backend işlerinin büyük bölümü Supabase üzerinde duruyor. Next.js tarafı ise hem arayüzü hem de server action ve API route gibi uygulama mantığını taşıyor.
## Ana Teknolojiler ## Ana Teknolojiler
+3
View File
@@ -2,10 +2,13 @@
title: Supabase Kurulumu title: Supabase Kurulumu
description: Neta için gerekli Supabase tablo, policy, function ve storage gereksinimleri. description: Neta için gerekli Supabase tablo, policy, function ve storage gereksinimleri.
order: 4 order: 4
status: legacy-v2-archive
--- ---
# Supabase Kurulumu # Supabase Kurulumu
> Arşiv: Self-hosted v3 çalışmak için Supabase kurulumu istemez. Bu içerik yalnızca eski bir v2 instance'ını anlamak içindir; güncel aktarım rehberi `docs/self-hosted-redesign/phase-8-import-release.md` dosyasındadır.
Neta'nın çalışması için hazır bir Supabase projesine ihtiyaç var. Bu repo artık Supabase'i beraberinde getirmiyor. Yani uygulama deploy edilirken veritabanı, auth veya storage otomatik kurulmaz. Ben burada web uygulamasını sade tutmayı tercih ettim. Supabase tarafı ayrı bir altyapı olarak yönetilir. Neta'nın çalışması için hazır bir Supabase projesine ihtiyaç var. Bu repo artık Supabase'i beraberinde getirmiyor. Yani uygulama deploy edilirken veritabanı, auth veya storage otomatik kurulmaz. Ben burada web uygulamasını sade tutmayı tercih ettim. Supabase tarafı ayrı bir altyapı olarak yönetilir.
> Şuan nestjs ile backend geliştiriyorum, çok yakında tam self host olacak :) > Şuan nestjs ile backend geliştiriyorum, çok yakında tam self host olacak :)
+3
View File
@@ -2,10 +2,13 @@
title: Environment Ayarları title: Environment Ayarları
description: Neta'yı çalıştırmak için gereken ortam değişkenleri. description: Neta'yı çalıştırmak için gereken ortam değişkenleri.
order: 5 order: 5
status: legacy-v2-archive
--- ---
# Environment Ayarları # Environment Ayarları
> Arşiv: Aşağıdaki Supabase env sözleşmesi v2'ye aittir. Güncel environment sözleşmesi `.env.example`, repository `README.md` ve Faz 8 runbook'unda tanımlıdır.
Neta'nın çalışması için az sayıda ama kritik ortam değişkeni gerekiyor. Uygulama artık Supabase'i kendi içinde ayağa kaldırmadığı için bütün Supabase bağlantı bilgileri dışarıdan verilir. Neta'nın çalışması için az sayıda ama kritik ortam değişkeni gerekiyor. Uygulama artık Supabase'i kendi içinde ayağa kaldırmadığı için bütün Supabase bağlantı bilgileri dışarıdan verilir.
Local geliştirme için `.env.example` dosyasını `.env.local` olarak kopyalayabilirsiniz. Production tarafında ise aynı değerleri Vercel, Coolify veya Dokploy panelinden environment variable olarak eklemek gerekir. Local geliştirme için `.env.example` dosyasını `.env.local` olarak kopyalayabilirsiniz. Production tarafında ise aynı değerleri Vercel, Coolify veya Dokploy panelinden environment variable olarak eklemek gerekir.
+3
View File
@@ -2,10 +2,13 @@
title: Vercel ile Deploy title: Vercel ile Deploy
description: Neta'yı Vercel üzerinde yayınlama adımları. description: Neta'yı Vercel üzerinde yayınlama adımları.
order: 6 order: 6
status: legacy-v2-archive
--- ---
# Vercel ile Deploy # Vercel ile Deploy
> Arşiv: SQLite ve persistent local volume kullanan self-hosted v3 için Vercel hedef runtime değildir. Docker tabanlı güncel kurulum repository `README.md` dosyasındadır.
Neta'yı Vercel üzerinde yayınlamak en sade yollardan biri. Çünkü proje standart bir Next.js uygulaması olarak çalışır. Dockerfile, Compose veya özel installer gerekmez. Neta'yı Vercel üzerinde yayınlamak en sade yollardan biri. Çünkü proje standart bir Next.js uygulaması olarak çalışır. Dockerfile, Compose veya özel installer gerekmez.
Benim önerdiğim akış şu: Supabase projesini önce hazırlayın, sonra GitHub reposunu Vercel'e bağlayın. Benim önerdiğim akış şu: Supabase projesini önce hazırlayın, sonra GitHub reposunu Vercel'e bağlayın.
+3
View File
@@ -2,10 +2,13 @@
title: Coolify ile Deploy title: Coolify ile Deploy
description: Neta'yı bir VPS üzerinde Coolify kullanarak yayınlama. description: Neta'yı bir VPS üzerinde Coolify kullanarak yayınlama.
order: 7 order: 7
status: legacy-v2-archive
--- ---
# Coolify ile Deploy # Coolify ile Deploy
> Arşiv: Aşağıdaki harici Supabase/Nixpacks akışı v2'ye aittir. v3 için Dockerfile, tek replica ve `/app/data` persistent volume sözleşmesini `docs/self-hosted-redesign/phase-8-import-release.md` belgesinden uygulayın.
Coolify, kendi VPS'im üzerinde uygulama yayınlamak istediğimde pratik bir seçenek. Neta artık Docker Compose ile gelen full-stack bir paket olmadığı için Coolify üzerinde standart bir Next.js uygulaması olarak deploy edilebilir. Coolify, kendi VPS'im üzerinde uygulama yayınlamak istediğimde pratik bir seçenek. Neta artık Docker Compose ile gelen full-stack bir paket olmadığı için Coolify üzerinde standart bir Next.js uygulaması olarak deploy edilebilir.
Buradaki temel fikir şu: Coolify sadece Neta web uygulamasını çalıştırır. Supabase ayrı bir servis olarak dışarıdadır. Buradaki temel fikir şu: Coolify sadece Neta web uygulamasını çalıştırır. Supabase ayrı bir servis olarak dışarıdadır.
+3
View File
@@ -2,10 +2,13 @@
title: Dokploy ile Deploy title: Dokploy ile Deploy
description: Neta'yı Dokploy üzerinde Docker Compose olmadan yayınlama. description: Neta'yı Dokploy üzerinde Docker Compose olmadan yayınlama.
order: 8 order: 8
status: legacy-v2-archive
--- ---
# Dokploy ile Deploy # Dokploy ile Deploy
> Arşiv: Aşağıdaki harici Supabase/ephemeral akış v2'ye aittir. v3 için Dockerfile, tek replica ve `/app/data` persistent volume sözleşmesini `docs/self-hosted-redesign/phase-8-import-release.md` belgesinden uygulayın.
Dokploy üzerinde Neta'yı yayınlarken artık özel Dockerfile veya Compose dosyasına ihtiyaç yok. Bu projeyi standart bir Next.js repo deploy'u gibi ele almak yeterli. Dokploy üzerinde Neta'yı yayınlarken artık özel Dockerfile veya Compose dosyasına ihtiyaç yok. Bu projeyi standart bir Next.js repo deploy'u gibi ele almak yeterli.
Benim önerdiğim yapı şu: Dokploy sadece web uygulamasını çalıştırır, Supabase ise dışarıdaki hazır proje olarak kullanılır. Benim önerdiğim yapı şu: Dokploy sadece web uygulamasını çalıştırır, Supabase ise dışarıdaki hazır proje olarak kullanılır.
+3
View File
@@ -2,10 +2,13 @@
title: İlk Admin Kurulumu title: İlk Admin Kurulumu
description: Neta'da ilk yönetici hesabının nasıl oluşturulduğu. description: Neta'da ilk yönetici hesabının nasıl oluşturulduğu.
order: 9 order: 9
status: legacy-v2-archive
--- ---
# İlk Admin Kurulumu # İlk Admin Kurulumu
> Arşiv: Aşağıdaki Supabase Auth kurulumu v2'ye aittir. v3 ilk owner hesabını `/register` üzerinden Better Auth + SQLite transaction'ıyla oluşturur; güncel akış repository `README.md` dosyasındadır.
Neta'yı kişisel bir freelancer çalışma alanı olarak düşündüğüm için sistemde herkesin serbestçe kayıt olmasını istemedim. Bu yüzden ilk admin oluşturulduktan sonra public kayıt akışı kapanır. Neta'yı kişisel bir freelancer çalışma alanı olarak düşündüğüm için sistemde herkesin serbestçe kayıt olmasını istemedim. Bu yüzden ilk admin oluşturulduktan sonra public kayıt akışı kapanır.
İlk kurulumun temel akışı şudur: İlk kurulumun temel akışı şudur:
+3
View File
@@ -2,10 +2,13 @@
title: AI Asistan title: AI Asistan
description: Neta'nın AI sohbet ve analiz özelliklerinin nasıl çalıştığı. description: Neta'nın AI sohbet ve analiz özelliklerinin nasıl çalıştığı.
order: 10 order: 10
status: legacy-v2-archive
--- ---
# AI Asistan # AI Asistan
> Arşiv: Bu belge v2 veri erişimini anlatır. v3 AI provider ve context katmanı server-side çalışır; secret browser'a dönmez. Güncel teknik kayıt `docs/self-hosted-redesign/phase-7-ai-business-backend.md` dosyasındadır.
Neta'daki AI asistanı, uygulamanın içindeki veriler hakkında hızlıca soru sorabilmek için ekledim. Bu asistanın amacı genel bir chatbot olmak değil; görevler, projeler, finans kayıtları ve günlük notları üzerinden bana bağlama dayalı cevap verebilmesi. Neta'daki AI asistanı, uygulamanın içindeki veriler hakkında hızlıca soru sorabilmek için ekledim. Bu asistanın amacı genel bir chatbot olmak değil; görevler, projeler, finans kayıtları ve günlük notları üzerinden bana bağlama dayalı cevap verebilmesi.
## Chat Ekranı ## Chat Ekranı
+3
View File
@@ -2,10 +2,13 @@
title: Client Portal title: Client Portal
description: Müşteri portalının amacı, erişim modeli ve kullanım akışı. description: Müşteri portalının amacı, erişim modeli ve kullanım akışı.
order: 11 order: 11
status: legacy-v2-archive
--- ---
# Client Portal # Client Portal
> Arşiv: Bu belge v2 portalını anlatır. Güncel Better Auth/SQLite portal sözleşmesi `docs/self-hosted-redesign/phase-6-portal-backend.md` dosyasındadır.
Client portal, müşteriye sınırlı ve güvenli bir görünüm sunmak için var. Neta'nın ana dashboard'u freelancer içindir. Müşteriye bu dashboard'u açmak doğru olmaz. Bunun yerine müşteri sadece kendisini ilgilendiren proje, görev ve revizyon bilgilerini görür. Client portal, müşteriye sınırlı ve güvenli bir görünüm sunmak için var. Neta'nın ana dashboard'u freelancer içindir. Müşteriye bu dashboard'u açmak doğru olmaz. Bunun yerine müşteri sadece kendisini ilgilendiren proje, görev ve revizyon bilgilerini görür.
## Portalın Amacı ## Portalın Amacı
+3
View File
@@ -2,10 +2,13 @@
title: Storage ve Dosyalar title: Storage ve Dosyalar
description: Avatar ve proje görselleri için Supabase Storage kullanımı. description: Avatar ve proje görselleri için Supabase Storage kullanımı.
order: 12 order: 12
status: legacy-v2-archive
--- ---
# Storage ve Dosyalar # Storage ve Dosyalar
> Arşiv: Aşağıdaki Supabase Storage akışı v2'ye aittir. v3 dosyaları `DATA_DIR/uploads` altında ve checksum'lı metadata ile tutar; güncel kayıt `docs/self-hosted-redesign/phase-3-storage-branding.md` dosyasındadır.
Neta'da dosya saklama için Supabase Storage kullanılır. Şu an iki temel dosya ihtiyacı var: profil fotoğrafları ve proje kapak görselleri. Neta'da dosya saklama için Supabase Storage kullanılır. Şu an iki temel dosya ihtiyacı var: profil fotoğrafları ve proje kapak görselleri.
Bu dosyaları uygulama reposu içinde tutmuyorum. Çünkü production ortamında dosya upload'larının kalıcı ve güvenli bir storage alanında durması gerekir. Supabase Storage bu iş için yeterli ve pratik bir çözüm sağlıyor. Bu dosyaları uygulama reposu içinde tutmuyorum. Çünkü production ortamında dosya upload'larının kalıcı ve güvenli bir storage alanında durması gerekir. Supabase Storage bu iş için yeterli ve pratik bir çözüm sağlıyor.
+3
View File
@@ -2,10 +2,13 @@
title: Geliştirme title: Geliştirme
description: Neta üzerinde lokal geliştirme yapma ve kod yapısını anlama. description: Neta üzerinde lokal geliştirme yapma ve kod yapısını anlama.
order: 13 order: 13
status: legacy-v2-archive
--- ---
# Geliştirme # Geliştirme
> Arşiv: Aşağıdaki Supabase geliştirme akışı v2'ye aittir. Güncel lokal kurulum ve kalite komutları repository `README.md` dosyasındadır.
Neta'yı geliştirmek için önce standart bir Next.js uygulaması gibi düşünmek yeterli. Uygulama Supabase'e dışarıdan bağlanır; local geliştirme sırasında da aynı şekilde bir Supabase projesine ihtiyaç vardır. Neta'yı geliştirmek için önce standart bir Next.js uygulaması gibi düşünmek yeterli. Uygulama Supabase'e dışarıdan bağlanır; local geliştirme sırasında da aynı şekilde bir Supabase projesine ihtiyaç vardır.
## Kurulum ## Kurulum
+3
View File
@@ -2,10 +2,13 @@
title: Özelleştirme title: Özelleştirme
description: Neta'nın marka, arayüz, modül ve iş akışı açısından nasıl özelleştirileceği. description: Neta'nın marka, arayüz, modül ve iş akışı açısından nasıl özelleştirileceği.
order: 14 order: 14
status: legacy-v2-archive
--- ---
# Özelleştirme # Özelleştirme
> Arşiv: Bu kod tabanlı v2 özelleştirme rehberidir. v3 instance branding'i SQLite/local file service ve server-rendered Poyraz semantic tokenları üzerinden uygular; güncel özet repository `README.md` dosyasındadır.
Neta'yı kendi kullanım şeklime göre geliştirdiğim için özelleştirilebilir kalmasına dikkat ettim. Renkler, logo, menüler, modüller, AI prompt'ları ve portal görünümü ihtiyaçlara göre değiştirilebilir. Neta'yı kendi kullanım şeklime göre geliştirdiğim için özelleştirilebilir kalmasına dikkat ettim. Renkler, logo, menüler, modüller, AI prompt'ları ve portal görünümü ihtiyaçlara göre değiştirilebilir.
## Logo Değiştirme ## Logo Değiştirme
+3
View File
@@ -2,10 +2,13 @@
title: Sorun Giderme title: Sorun Giderme
description: Kurulum, deploy, Supabase ve giriş problemlerinde kontrol edilmesi gerekenler. description: Kurulum, deploy, Supabase ve giriş problemlerinde kontrol edilmesi gerekenler.
order: 15 order: 15
status: legacy-v2-archive
--- ---
# Sorun Giderme # Sorun Giderme
> Arşiv: Aşağıdaki Supabase/RLS sorun giderme akışı v2'ye aittir. v3 operasyon kontrolleri ve health endpoint'leri Faz 8 runbook'unda tanımlıdır.
Neta bir Next.js uygulaması gibi deploy edilse de Supabase, RLS, Auth ve Storage bağlantıları olduğu için sorunları doğru katmanda aramak önemli. Bu sayfada en sık karşılaşılabilecek durumları topladım. Neta bir Next.js uygulaması gibi deploy edilse de Supabase, RLS, Auth ve Storage bağlantıları olduğu için sorunları doğru katmanda aramak önemli. Bu sayfada en sık karşılaşılabilecek durumları topladım.
## Login Sayfası Açılmıyor ## Login Sayfası Açılmıyor
+3
View File
@@ -2,10 +2,13 @@
title: Güvenlik Notları title: Güvenlik Notları
description: Neta'yı güvenli şekilde kullanmak için dikkat edilmesi gerekenler. description: Neta'yı güvenli şekilde kullanmak için dikkat edilmesi gerekenler.
order: 16 order: 16
status: legacy-v2-archive
--- ---
# Güvenlik Notları # Güvenlik Notları
> Arşiv: Bu belgenin Supabase/RLS maddeleri v2'ye aittir. Güncel Better Auth, service authorization, filesystem ve secret kararları ana dönüşüm planında tanımlıdır.
Neta kişisel kullanım ve self-host mantığıyla tasarlandı, ama yine de hassas veriler tutar. Müşteri bilgileri, proje detayları, finans kayıtları, AI API key'leri ve portal erişimleri doğru korunmalıdır. Neta kişisel kullanım ve self-host mantığıyla tasarlandı, ama yine de hassas veriler tutar. Müşteri bilgileri, proje detayları, finans kayıtları, AI API key'leri ve portal erişimleri doğru korunmalıdır.
Bu sayfada projeyi kullanırken özellikle dikkat ettiğim güvenlik noktalarını topladım. Bu sayfada projeyi kullanırken özellikle dikkat ettiğim güvenlik noktalarını topladım.
+3
View File
@@ -2,10 +2,13 @@
title: Performans ve UX Planı title: Performans ve UX Planı
description: Neta içindeki yavaş navigasyon, aksiyon geri bildirimi ve sayfa bazlı performans iyileştirmeleri için faz bazlı çalışma planı. description: Neta içindeki yavaş navigasyon, aksiyon geri bildirimi ve sayfa bazlı performans iyileştirmeleri için faz bazlı çalışma planı.
order: 17 order: 17
status: legacy-v2-archive
--- ---
# Performans ve UX Planı # Performans ve UX Planı
> Arşiv: Bu v2 UX planı aktif çalışma planı değildir. Backend-first sıra ve kullanıcı yönlendirmeli Faz 10 tasarım süreci ana dönüşüm planında tanımlıdır.
Bu planı, uygulamada hissedilen iki ana problemi çözmek için hazırladım: Bu planı, uygulamada hissedilen iki ana problemi çözmek için hazırladım:
1. Butona ya da linke tıklayınca kullanıcıya hemen geri bildirim gelmemesi. 1. Butona ya da linke tıklayınca kullanıcıya hemen geri bildirim gelmemesi.
+9 -39
View File
@@ -1,44 +1,14 @@
# Database Change Process # Legacy PostgreSQL database documentation
This directory records every database change that should be run against Supabase/PostgreSQL. Bu klasördeki `0001``0011`, query log/order ve seed belgeleri Neta v2 Supabase/PostgreSQL geçmişinin arşividir. Güncel runtime veya migration talimatı değildir.
The project currently starts with `supabase/schema.sql` as the first database query file. Future database changes must be added as separate SQL files and registered here before they are run. Self-hosted v3'te:
## Rules - schema kaynağı `server/db/schema`,
- migration kaynağı `server/db/migrations`,
- migration runner `pnpm db:migrate`,
- veri aktarım runbook'u `docs/self-hosted-redesign/phase-8-import-release.md`
1. Every SQL change must have a stable order number. olarak kullanılır.
2. Every SQL file must be listed in `query-order.md`.
3. Every executed query must be recorded in `query-log.md`.
4. Every meaningful schema addition must have a short documentation file under this directory.
5. Do not edit an already executed SQL file silently. Add a new ordered SQL file instead.
## Current Files Arşiv dosyaları yalnızca eski kolon/policy davranışlarını import sırasında karşılaştırmak için korunur. Yeni migration veya seed bu klasöre eklenmemelidir.
- `supabase/schema.sql`: Initial legacy schema. It creates the current auth/profile, journal, task, chat, and avatar storage structure.
- `supabase/migrations/0002_add_freelancer_os_core_tables.sql`: Freelancer OS MVP core schema.
- `supabase/seeds/0001_demo_freelancer_os_data.sql`: Optional local/demo data for the MVP schema.
- `docs/database/0001-initial-schema.md`: Explanation for the initial schema.
- `docs/database/0002-freelancer-os-core-tables.md`: Explanation for the MVP schema migration.
- `docs/database/seed-0001-demo-freelancer-os-data.md`: Explanation for the demo seed file.
- `docs/database/query-order.md`: Canonical order of SQL files.
- `docs/database/query-log.md`: Manual execution log for SQL files that were run against an environment.
## Next Migration Naming
Use this pattern for future SQL files:
```text
supabase/migrations/0002_short_description.sql
```
Example:
```text
supabase/migrations/0002_add_freelancer_os_core_tables.sql
```
Use this pattern for future seed files:
```text
supabase/seeds/0002_short_description.sql
```
@@ -2,8 +2,8 @@
title: Neta Self-Hosted v3 Ana Dönüşüm Planı title: Neta Self-Hosted v3 Ana Dönüşüm Planı
description: Supabase çıkışı, SQLite tabanlı backend, Better Auth, Poyraz UI v3 ve instance özelleştirmesi için ana yol haritası. description: Supabase çıkışı, SQLite tabanlı backend, Better Auth, Poyraz UI v3 ve instance özelleştirmesi için ana yol haritası.
status: active status: active
current_phase: "7AI ve gelişmiş modüller backend geçişi" current_phase: "9Mobil API hazırlığı"
last_updated: 2026-07-16 last_updated: 2026-07-17
--- ---
# Neta Self-Hosted v3 Ana Dönüşüm Planı # Neta Self-Hosted v3 Ana Dönüşüm Planı
@@ -525,8 +525,8 @@ Faz 5'in başlangıç noktası freelancer runtime'ındaki Supabase erişimleridi
### 14.6. Portal, AI ve business devam sırası ### 14.6. Portal, AI ve business devam sırası
- [x] Portal backend'i Faz 6 sözleşmesine göre tamamlandı. - [x] Portal backend'i Faz 6 sözleşmesine göre tamamlandı.
- [ ] AI/chat ve business backend'i Faz 7 sözleşmesine göre tamamlandı. - [x] AI/chat ve business backend'i Faz 7 sözleşmesine göre tamamlandı.
- [ ] Import ve runtime Supabase temizliği Faz 8'de tamamlandı. - [x] Import ve runtime Supabase temizliği Faz 8'de tamamlandı.
- [ ] Mobil API sınırı Faz 9'da tamamlandı. - [ ] Mobil API sınırı Faz 9'da tamamlandı.
## 15. Revizyon güvenliği ve kota işlemi ## 15. Revizyon güvenliği ve kota işlemi
@@ -592,20 +592,20 @@ Mobil hazırlık checklist'i:
### 17.1. Import aracı ### 17.1. Import aracı
- [ ] Supabase tablolarının kaynak mapping'i güncellendi. - [x] Supabase tablolarının kaynak mapping'i güncellendi.
- [ ] Export formatı tanımlandı. - [x] Export formatı tanımlandı.
- [ ] Import dry-run modu var. - [x] Import dry-run modu var.
- [ ] Kaynak ve hedef satır sayıları raporlanıyor. - [x] Kaynak ve hedef satır sayıları raporlanıyor.
- [ ] Foreign key tutarsızlıkları raporlanıyor. - [x] Foreign key tutarsızlıkları raporlanıyor.
- [ ] Bilinmeyen enum/status değerlerinde import fail ediyor. - [x] Bilinmeyen enum/status değerlerinde import fail ediyor.
- [ ] `completed` görev status'ü `done` olarak normalize ediliyor. - [x] `completed` görev status'ü `done` olarak normalize ediliyor.
- [ ] Para değerleri minor unit'e güvenli dönüştürülüyor. - [x] Para değerleri minor unit'e güvenli dönüştürülüyor.
- [ ] `journals` ve `daily_logs` merge kuralı uygulanıyor. - [x] `journals` ve `daily_logs` merge kuralı uygulanıyor.
- [ ] AI API key'leri taşınmıyor. - [x] AI API key'leri taşınmıyor.
- [ ] Auth password/session verileri taşınmıyor. - [x] Auth password/session verileri taşınmıyor.
- [ ] Client kullanıcıları yeniden davet ediliyor. - [x] Client kullanıcıları yeniden davet ediliyor.
- [ ] Storage dosyaları metadata ve checksum ile aktarılıyor. - [x] Storage dosyaları metadata ve checksum ile aktarılıyor.
- [ ] Import tekrar çalıştırıldığında davranış tanımlı. - [x] Import tekrar çalıştırıldığında davranış tanımlı.
### 17.2. Production cutover ### 17.2. Production cutover
@@ -617,32 +617,32 @@ Mobil hazırlık checklist'i:
- [ ] Satır sayısı doğrulandı. - [ ] Satır sayısı doğrulandı.
- [ ] Dosya sayısı ve checksum doğrulandı. - [ ] Dosya sayısı ve checksum doğrulandı.
- [ ] İlk admin Better Auth hesabı hazırlandı. - [ ] İlk admin Better Auth hesabı hazırlandı.
- [ ] Client re-invite planı hazırlandı. - [x] Client re-invite planı hazırlandı.
- [ ] Kritik kullanıcı akışları smoke test edildi. - [ ] Kritik kullanıcı akışları smoke test edildi.
- [ ] DNS/deploy geçişi yapıldı. - [ ] DNS/deploy geçişi yapıldı.
- [ ] Rollback penceresi ve yöntemi belgelendi. - [x] Rollback penceresi ve yöntemi belgelendi.
- [ ] Supabase hemen silinmedi; tanımlı süre read-only backup olarak tutuldu. - [ ] Supabase hemen silinmedi; tanımlı süre read-only backup olarak tutuldu.
## 18. Dependency azaltma planı ## 18. Dependency azaltma planı
### 18.1. Supabase çıkışı tamamlandığında kaldırılacaklar ### 18.1. Supabase çıkışı tamamlandığında kaldırılacaklar
- [ ] `@supabase/ssr` - [x] `@supabase/ssr`
- [ ] `@supabase/supabase-js` - [x] `@supabase/supabase-js`
- [ ] `lib/supabase/*` - [x] `lib/supabase/*`
- [ ] Legacy Supabase auth helper'ları - [x] Legacy Supabase auth helper'ları
- [ ] Supabase service-role client kullanımları - [x] Supabase service-role client kullanımları
- [ ] Runtime Supabase environment değişkenleri - [x] Runtime Supabase environment değişkenleri
### 18.2. Offline/PWA temizliği ### 18.2. Offline/PWA temizliği
- [ ] `@ducanh2912/next-pwa` - [x] `@ducanh2912/next-pwa`
- [ ] `dexie` - [x] `dexie`
- [ ] `dexie-react-hooks` - [x] `dexie-react-hooks`
- [ ] Legacy `lib/db.ts` - [x] Legacy `lib/db.ts`
- [ ] Offline indicator, kapsam dışıysa - [x] Offline indicator, kapsam dışıysa
- [ ] Service worker çıktıları - [x] Service worker çıktıları
- [ ] PWA manifest kararı güncellendi - [x] PWA manifest kararı güncellendi
### 18.3. Poyraz UI v3 sonrası değerlendirilecekler ### 18.3. Poyraz UI v3 sonrası değerlendirilecekler
@@ -651,9 +651,9 @@ Mobil hazırlık checklist'i:
- [x] `radix-ui` - [x] `radix-ui`
- [x] `shadcn` - [x] `shadcn`
- [x] Kullanılmayan local UI primitive'leri - [x] Kullanılmayan local UI primitive'leri
- [ ] `framer-motion`, kullanım kalmadıysa - [x] `framer-motion` değerlendirildi; auth shell'deki reduced-motion uyumlu aktif kullanım nedeniyle korundu.
- [x] `next-themes`, tema başka şekilde çözüldüyse - [x] `next-themes`, tema başka şekilde çözüldüyse
- [ ] Kullanılmayan icon/form/theme yardımcıları - [x] Kullanılmayan icon/form/theme yardımcıları
### 18.4. İşlevsel gerekçeyle korunabilecekler ### 18.4. İşlevsel gerekçeyle korunabilecekler
@@ -664,18 +664,17 @@ Mobil hazırlık checklist'i:
- Drizzle ORM - Drizzle ORM
- Zod - Zod
- `date-fns` - `date-fns`
- Kanban için `dnd-kit`
- Grafikler için Recharts - Grafikler için Recharts
- Gerçekten kullanılan AI provider paketleri - Gerçekten kullanılan AI provider paketleri
Dependency kalite kapısı: Dependency kalite kapısı:
- [ ] Her production dependency için aktif import veya açık gerekçe var. - [x] Her production dependency için aktif import veya açık gerekçe var.
- [x] Aynı işi yapan iki UI primitive sistemi yok. - [x] Aynı işi yapan iki UI primitive sistemi yok.
- [ ] Aynı işi yapan iki auth sistemi yok. - [x] Aynı işi yapan iki auth sistemi yok.
- [ ] Aynı işi yapan iki runtime database sistemi yok. - [x] Aynı işi yapan iki runtime database sistemi yok.
- [ ] Browser database bağımlılığı yok. - [x] Browser database bağımlılığı yok.
- [ ] Build çıktısında Supabase referansı yok. - [x] Build çıktısında Supabase referansı yok.
- [x] Build çıktısında Poyraz UI v2 referansı yok. - [x] Build çıktısında Poyraz UI v2 referansı yok.
## 19. Test stratejisi ## 19. Test stratejisi
@@ -699,7 +698,7 @@ Mümkün olduğunda küçük ve doğrudan test araçları tercih edilir; test al
- [x] Path traversal negatif testi - [x] Path traversal negatif testi
- [x] Backup oluşturma testi - [x] Backup oluşturma testi
- [x] Restore ve checksum testi - [x] Restore ve checksum testi
- [ ] Supabase import fixture testi - [x] Supabase import fixture testi
- [x] API response/error contract testi - [x] API response/error contract testi
- [x] Kritik sayfalar için SSR smoke testi - [x] Kritik sayfalar için SSR smoke testi
@@ -728,27 +727,27 @@ Mümkün olduğunda küçük ve doğrudan test araçları tercih edilir; test al
- [x] Backup SQLite online backup API kullanıyor. - [x] Backup SQLite online backup API kullanıyor.
- [x] Backup upload klasörünü içeriyor. - [x] Backup upload klasörünü içeriyor.
- [x] Backup manifest dosya boyutu ve SHA-256 içeriyor. - [x] Backup manifest dosya boyutu ve SHA-256 içeriyor.
- [ ] Restore manifest checksum'larını doğruluyor. - [x] Restore manifest checksum'larını doğruluyor.
- [x] Restore canlı DB üzerine kontrolsüz yazmıyor. - [x] Restore canlı DB üzerine kontrolsüz yazmıyor.
- [ ] Backup retention politikası belgelendi. - [x] Backup retention politikası belgelendi.
- [ ] Reverse proxy ve HTTPS kurulumu belgelendi. - [x] Reverse proxy ve HTTPS kurulumu belgelendi.
## 21. Dokümantasyon planı ## 21. Dokümantasyon planı
- [ ] README yeni SQLite/Better Auth mimarisini anlatıyor. - [x] README yeni SQLite/Better Auth mimarisini anlatıyor.
- [ ] Supabase'in artık runtime gereksinimi olmadığı açık. - [x] Supabase'in artık runtime gereksinimi olmadığı açık.
- [ ] Docker ile kurulum belgelendi. - [x] Docker ile kurulum belgelendi.
- [ ] Coolify/Dokploy kurulumu belgelendi. - [x] Coolify/Dokploy kurulumu belgelendi.
- [x] Environment değişkenleri güncellendi. - [x] Environment değişkenleri güncellendi.
- [x] İlk admin kurulumu belgelendi. - [x] İlk admin kurulumu belgelendi.
- [x] Client invitation akışı belgelendi. - [x] Client invitation akışı belgelendi.
- [ ] Branding ayarları belgelendi. - [x] Branding ayarları belgelendi.
- [x] Backup/restore belgelendi. - [x] Backup/restore belgelendi.
- [ ] Upgrade/migration akışı belgelendi. - [x] Upgrade/migration akışı belgelendi.
- [ ] Mobil API sınırı belgelendi. - [ ] Mobil API sınırı belgelendi.
- [ ] Eski ve çelişkili Supabase belgeleri archive veya kaldırıldı. - [x] Eski ve çelişkili Supabase belgeleri archive veya kaldırıldı.
- [x] ADR-0006 Poyraz UI v3 kararıyla güncellendi. - [x] ADR-0006 Poyraz UI v3 kararıyla güncellendi.
- [ ] ADR-0007 ile PWA runtime durumu uyumlu hale getirildi. - [x] ADR-0007 ile PWA runtime durumu uyumlu hale getirildi.
## 22. Uygulama fazları ## 22. Uygulama fazları
@@ -935,12 +934,21 @@ Faz 6 tamamlanma notu (2026-07-16):
Amaç: AI/chat ve kapsamda kalan business modüllerini yeni backend'e taşımak. Amaç: AI/chat ve kapsamda kalan business modüllerini yeni backend'e taşımak.
- [ ] Chat session/message verileri SQLite'a taşındı. - [x] Chat session/message verileri SQLite'a taşındı.
- [ ] AI secrets browser'dan kaldırıldı. - [x] AI secrets browser'dan kaldırıldı.
- [ ] Context builder service katmanına taşındı. - [x] Context builder service katmanına taşındı.
- [ ] Finans analizi taşındı. - [x] Finans analizi taşındı.
- [ ] Proje risk analizi taşındı. - [x] Proje risk analizi taşındı.
- [ ] Kapsamdaki business modülleri tamamlandı. - [x] Kapsamdaki business modülleri tamamlandı.
Faz 7 tamamlanma notu (2026-07-17):
- Chat sayfasındaki browser Supabase auth/tablo çağrıları owner-scoped Server Action ve domain service sözleşmelerine taşındı. Chat route'u session sahipliğini doğrular, geçmişi istemciden değil SQLite'tan kurar ve başarılı user/assistant mesajlarını kalıcılaştırır.
- AI provider seçimi ve encrypted API key çözümü `server/ai/provider.ts` altında server-only merkezileştirildi. Browser request'inden key/provider override kaldırıldı; Ollama için key gerektirmeyen ve environment ile ayarlanabilen local endpoint desteği eklendi.
- Chat, finans ve proje risk context'leri owner-scoped domain service okumaları, kayıt/karakter sınırları ve currency-aware finans toplamlarıyla ortak context builder'a taşındı.
- Finans analizi ve proje risk route'ları Better Auth freelancer guard, merkezi validation, provider timeout ve secretsız `400/502/504` hata sözleşmesi kullanır.
- Teklif, sözleşme, fatura ve abonelik için owner-scoped list/get/create/update/delete servisleri tamamlandı. Aktif teklif, fatura ve abonelik sayfaları SQLite SSR okumalarına bağlandı; repo içinde aktif sözleşme sayfası bulunmadığı için yeni tasarım route'u eklenmedi.
- `phase7:backend-boundary`, temiz SQLite domain smoke ve gerçek Better Auth cookie'li SSR/API smoke başarılıdır. Ayrıntılar `phase-7-ai-business-backend.md` belgesindedir.
Çıkış kriteri: Runtime AI özelliklerinde Supabase bağımlılığı yok. Çıkış kriteri: Runtime AI özelliklerinde Supabase bağımlılığı yok.
@@ -948,15 +956,27 @@ Amaç: AI/chat ve kapsamda kalan business modüllerini yeni backend'e taşımak.
Amaç: Production geçişini güvenli hale getirmek ve legacy bağımlılıkları kaldırmak. Amaç: Production geçişini güvenli hale getirmek ve legacy bağımlılıkları kaldırmak.
- [ ] Supabase import aracı tamamlandı. - [x] Supabase import aracı tamamlandı.
- [ ] Import rehearsal tamamlandı. - [x] Import rehearsal tamamlandı.
- [ ] Supabase runtime paketleri kaldırıldı. - [x] Supabase runtime paketleri kaldırıldı.
- [ ] PWA/Dexie legacy kodu kaldırıldı. - [x] PWA/Dexie legacy kodu kaldırıldı.
- [ ] Kullanılmayan UI bağımlılıkları kaldırıldı. - [x] Kullanılmayan UI bağımlılıkları kaldırıldı.
- [ ] Backup/restore doğrulandı. - [x] Backup/restore doğrulandı.
- [ ] Docker production smoke tamamlandı. - [x] Docker production smoke tamamlandı.
- [ ] Dokümantasyon güncellendi. - [x] Dokümantasyon güncellendi.
- [ ] Cutover ve rollback provası tamamlandı. - [x] Cutover ve rollback provası tamamlandı.
Faz 8 tamamlanma notu (2026-07-17):
- `neta-supabase-export` v1 offline bundle importer'ı; owner scope, enum, tarih, exact para/basis-point, foreign key, dosya path/magic-byte/size/SHA-256 kontrolleriyle tamamlandı. Dry-run ve `0600` rapor, boş hedef koruması, kontrollü `--allow-existing` upsert ve DB hatasında staged file rollback davranışı eklendi.
- Görev `completed -> done`, `journals + daily_logs` birleşimi, kanonik journal referansı, business kayıtları, user preference/AI provider ayarları ve storage URL yeniden yazımı fixture üzerinde doğrulandı. AI key, auth password/session, eski client auth bağı ve embeddings runtime'a taşınmıyor.
- Supabase SDK/helper/env; PWA wrapper, Dexie, offline indicator, legacy browser DB ve service-worker çıktıları kaldırıldı. Kullanılmayan DnD/resolver/UUID paketleri temizlendi; temiz Docker build'in doğruladığı `react-hook-form` ve `mermaid` Poyraz UI runtime peer'i olarak gerekçeli biçimde korundu.
- Backup'a versioned manifest, symlink reddi ve sayıya dayalı retention eklendi. Restore, manifest completeness/size/SHA-256 kontrolünden sonra DB ve upload ağacını staged atomik swap ile değiştirir ve hata halinde önceki hedefi geri alır.
- Pre-import backup, final import, idempotent tekrar ve ayrı data directory'ye rollback fixture provası geçti. Bu prova gerçek production maintenance/DNS cutover yerine geçmez; Bölüm 17.2'de dış sistem yetkisi isteyen maddeler açık bırakıldı.
- README ve Faz 8 runbook; SQLite/Better Auth mimarisi, env, ilk owner/client daveti, branding, Docker/Coolify/Dokploy, HTTPS, backup retention, import, upgrade, cutover ve rollback'i anlatır. Eski numaralı Supabase belgeleri ve PostgreSQL SQL kayıtları `legacy-v2-archive` sınırına alındı.
- Supabase env'leri unset durumda typecheck, production build, source/build artifact boundary, standalone liveness/readiness ve `/register` SSR başarılıdır. Temiz Docker `npm ci` + build, non-root user, startup migration, persistent volume readiness ve restart smoke geçti.
- Faz 27 boundary/smoke regresyonları ve Faz 8 hedefli ESLint başarılıdır. Repo genel ESLint'i Faz 10'da ele alınacak mevcut client-component borçlarında 14 hata/14 warning üretmeye devam ettiği için genel lint kalite kapısı işaretlenmedi.
- Production dependency audit'inde high/critical bulgu yoktur; npm altı moderate advisory raporlar. Bunlar Next'in bundled PostCSS'i ve development migration toolchain'inin eski esbuild loader'ı kaynaklıdır; npm'in önerdiği uyumsuz downgrade otomatik uygulanmadı.
Çıkış kriteri: Uygulama Supabase environment değişkenleri olmadan build ve runtime smoke testini geçiyor. Çıkış kriteri: Uygulama Supabase environment değişkenleri olmadan build ve runtime smoke testini geçiyor.
@@ -980,8 +1000,8 @@ Başlangıç koşulları:
- [x] Faz 5 freelancer backend geçişi tamamlandı. - [x] Faz 5 freelancer backend geçişi tamamlandı.
- [x] Faz 6 portal backend geçişi tamamlandı. - [x] Faz 6 portal backend geçişi tamamlandı.
- [ ] Faz 7 kapsamındaki runtime modülleri tamamlandı veya açıkça ertelendi. - [x] Faz 7 kapsamındaki runtime modülleri tamamlandı veya açıkça ertelendi.
- [ ] Faz 8 Supabase runtime temizliği ve release hardening tamamlandı. - [x] Faz 8 Supabase runtime temizliği ve release hardening tamamlandı.
- [ ] Faz 9 mobil API hazırlığı tamamlandı. - [ ] Faz 9 mobil API hazırlığı tamamlandı.
- [ ] Tasarım sırasında kullanılacak backend veri sözleşmeleri stabil. - [ ] Tasarım sırasında kullanılacak backend veri sözleşmeleri stabil.
@@ -1028,20 +1048,20 @@ Her sayfa için tasarım kabul checklist'i:
### Mimari ### Mimari
- [x] Ürün kararları kilitlendi. - [x] Ürün kararları kilitlendi.
- [ ] Hedef schema tamamlandı. - [x] Hedef schema tamamlandı.
- [ ] Service/repository sınırı tamamlandı. - [x] Service/repository sınırı tamamlandı.
- [ ] Server-side authorization tamamlandı. - [x] Server-side authorization tamamlandı.
- [ ] API v1 sınırı hazırlandı. - [ ] API v1 sınırı hazırlandı.
### Supabase çıkışı ### Supabase çıkışı
- [ ] Auth taşındı. - [x] Auth taşındı.
- [ ] Database taşındı. - [x] Database taşındı.
- [ ] Storage taşındı. - [x] Storage taşındı.
- [ ] RLS kuralları server-side testlere çevrildi. - [x] RLS kuralları server-side testlere çevrildi.
- [ ] Import aracı tamamlandı. - [x] Import aracı tamamlandı.
- [ ] Supabase paketleri kaldırıldı. - [x] Supabase paketleri kaldırıldı.
- [ ] Supabase env değişkenleri kaldırıldı. - [x] Supabase env değişkenleri kaldırıldı.
### UI ### UI
@@ -1067,26 +1087,26 @@ Her sayfa için tasarım kabul checklist'i:
### Operasyon ### Operasyon
- [ ] Docker kurulumu çalışıyor. - [x] Docker kurulumu çalışıyor.
- [ ] Persistent volume doğrulandı. - [x] Persistent volume doğrulandı.
- [ ] Migration güvenli. - [x] Migration güvenli.
- [x] Backup çalışıyor. - [x] Backup çalışıyor.
- [x] Restore ve checksum doğrulaması çalışıyor. - [x] Restore ve checksum doğrulaması çalışıyor.
- [ ] Health endpoint'leri çalışıyor. - [x] Health endpoint'leri çalışıyor.
- [ ] Upgrade dokümantasyonu hazır. - [x] Upgrade dokümantasyonu hazır.
- [ ] Rollback planı hazır. - [x] Rollback planı hazır.
### Release ### Release
- [ ] Typecheck başarılı. - [x] Typecheck başarılı.
- [ ] Lint başarılı. - [ ] Lint başarılı.
- [ ] Build başarılı. - [x] Build başarılı.
- [ ] Tüm smoke testler başarılı. - [x] Tüm smoke testler başarılı.
- [ ] Kritik authorization negatif testleri başarılı. - [x] Kritik authorization negatif testleri başarılı.
- [ ] Import rehearsal başarılı. - [x] Import rehearsal başarılı.
- [ ] Production Docker smoke başarılı. - [x] Production Docker smoke başarılı.
- [ ] README güncel. - [x] README güncel.
- [ ] Supabase runtime referansı kalmadı. - [x] Supabase runtime referansı kalmadı.
- [x] Poyraz UI v2 referansı kalmadı. - [x] Poyraz UI v2 referansı kalmadı.
## 24. Definition of Done ## 24. Definition of Done
@@ -1110,16 +1130,16 @@ Neta Self-Hosted v3 aşağıdaki koşulların tümü sağlandığında tamamlanm
- Gelecekteki mobil istemci için service ve API sınırları belgelenmiştir. - Gelecekteki mobil istemci için service ve API sınırları belgelenmiştir.
- Sayfa tasarımları backend ve runtime Supabase temizliği tamamlandıktan sonra yapılmış, kullanıcı tarafından tek tek kabul edilmiştir. - Sayfa tasarımları backend ve runtime Supabase temizliği tamamlandıktan sonra yapılmış, kullanıcı tarafından tek tek kabul edilmiştir.
## 25. Sıradaki çalışma paketi — Faz 7 ## 25. Sıradaki çalışma paketi — Faz 8
Faz 06 tamamlandı. Sıradaki çalışma paketi chat, AI analizleri ve kapsamda kalan business modüllerinin backend geçişidir: Faz 07 tamamlandı. Sıradaki çalışma paketi production import, runtime Supabase temizli ve release hardening'dir:
1. Chat sayfası, chat route'u, finans analizi, proje risk analizi ve business route'larındaki Supabase erişimlerini envanterlemek. 1. Faz 0 schema mapping'ini temel alan tekrar çalıştırılabilir Supabase export/import aracını dry-run, satır sayısı, foreign key ve enum raporlarıyla tamamlamak.
2. Chat session/message okuma ve mutation sözleşmelerini domain service'e bağlamak. 2. Chat ve business dahil korunacak production verisini fixture ve import rehearsal ile doğrulamak; AI key, auth password/session ve raw invitation token taşımamak.
3. AI provider key'lerini browser request/localStorage akışından tamamen kaldırıp Faz 5'teki encrypted server-side settings service'i kullanmak. 3. Kalan runtime Supabase importlarını ve kullanılmayan legacy helper'ları kaldırmak; `@supabase/ssr` ile `@supabase/supabase-js` paketlerini silmek.
4. AI context builder'ı owner-scoped proje, görev, finans ve günlük service okumalarıyla yeniden kurmak. 4. PWA/Dexie runtime kararını uygulamak ve kapsam dışı offline kod/paketleri temizlemek.
5. Finans analizi ve proje risk route'larını local backend'e taşımak; provider timeout/error sözleşmelerini standartlaştırmak. 5. Backup/restore checksum, retention, upgrade/migration ve rollback prosedürlerini production sözleşmesine bağlamak.
6. Release kapsamında tutulacak business modüllerinin repository/service ve runtime adapter'larını tamamlamak. 6. Supabase environment değişkenleri olmadan production build, standalone/Docker runtime ve kritik cutover smoke testlerini çalıştırmak.
7. Supabase boundary, secret leakage, cross-owner, AI failure ve authenticated SSR/API smoke testlerini çalıştırmak. 7. README, self-host kurulum, reverse proxy/HTTPS, branding, backup/restore ve upgrade belgelerini güncellemek.
Tasarım backlog'u Faz 10'a kadar açılmaz. Faz 10 başladığında sayfa sırası ve her sayfanın görsel/UX yönü kullanıcı tarafından adım adım belirlenecektir. Tasarım backlog'u Faz 10'a kadar açılmaz. Faz 10 başladığında sayfa sırası ve her sayfanın görsel/UX yönü kullanıcı tarafından adım adım belirlenecektir.
+2 -1
View File
@@ -124,7 +124,8 @@ Status: Accepted for redesign baseline.
Karar: Karar:
- İlk self-hosted release'te PWA/offline sync hedeflenmez. - İlk self-hosted release'te PWA/offline sync hedeflenmez.
- `next-pwa` kaldırılacak veya devre dışı bırakılacak. - `next-pwa`, Dexie, offline indicator ve üretilmiş service worker runtime'dan kaldırıldı.
- Web manifest yalnızca install metadata/branding çıktısı olarak server-side dinamik üretilir; offline çalışma vaadi değildir.
Gerekçe: Gerekçe:
@@ -0,0 +1,281 @@
---
title: Faz 8 — Supabase Import ve Production Release Runbook
description: Export bundle sözleşmesi, doğrulama, cutover, backup, rollback, Docker ve upgrade operasyonları.
status: completed
last_updated: 2026-07-17
---
# Faz 8 — Supabase import ve production release runbook
Bu belge Neta self-hosted v3'ün operasyonel kaynağıdır. `supabase/` ve `docs/database/` yalnızca eski PostgreSQL şemasını ve import kaynağını açıklayan tarihsel arşivdir; yeni instance kurulumu için kullanılmaz.
## 1. Tamamlanan runtime sınırı
- Auth yalnızca Better Auth kullanır.
- İş verisi yalnızca SQLite/Drizzle üzerinde çalışır.
- Dosyalar yalnızca `DATA_DIR/uploads` altında tutulur.
- Supabase SDK ve runtime env değişkenleri yoktur.
- PWA service worker, Dexie ve offline cache yoktur.
- Export/import aracı Supabase'e bağlanmaz; hazırlanmış offline bundle okur.
`pnpm phase8:release-boundary` bu sınırı kaynak kodda, `--build-output` argümanı ise build artifact'lerinde doğrular.
### Dependency denetimi
| Grup | Korunan doğrudan paketler | Gerekçe |
| --- | --- | --- |
| Runtime | `next`, `react`, `react-dom` | Web runtime ve SSR |
| Auth/veri | `better-auth`, `better-sqlite3`, `drizzle-orm`, `zod` | Auth, SQLite erişimi, schema ve input doğrulama |
| UI | `poyraz-ui`, `lucide-react`, `recharts`, `framer-motion`, `clsx`, `tailwind-merge`, `tailwindcss-animate` | Aktif component importları; Framer Motion auth shell'de reduced-motion ile, Recharts üç aktif ekranda kullanılır |
| Build/UI peer | `@tailwindcss/postcss`, `mermaid`, `react-hook-form` | Tailwind v4 build plugin'i; Poyraz molecule entrypoint'inin temiz npm/container build'inde doğrudan çözdüğü peer'ler |
| Tarih | `date-fns` | Aktif tarih filtreleme/formatlama |
| AI | `ai`, `@ai-sdk/react`, `@ai-sdk/google`, `@ai-sdk/openai`, `@ai-sdk/groq` | Chat stream'i ve kullanıcı tarafından seçilebilen aktif provider adapter'ları |
Kullanımı bulunmayan `dnd-kit`, Hook Form resolver ve UUID paketleri; Supabase SDK'ları, PWA ve Dexie paketleriyle birlikte kaldırıldı. `react-hook-form`, uygulama doğrudan form API'sini çağırmasa da Poyraz molecule bundle'ının statik import ettiği runtime peer olduğu için korundu. Temizlik sonrasında pnpm kurulum ağacı 231 paket küçüldü.
## 2. Export bundle v1
Import kökünde `export.json` ve varsa `storage/` ağacı bulunur:
```text
neta-export/
export.json
storage/
avatars/
project-assets/
```
Minimum envelope:
```json
{
"format": "neta-supabase-export",
"version": 1,
"exported_at": "2026-07-17T10:00:00.000Z",
"source": {
"owner_user_id": "source-owner-uuid"
},
"tables": {
"profiles": [],
"clients": [],
"client_activities": [],
"projects": [],
"project_planning_sections": [],
"project_revisions": [],
"tasks": [],
"calendar_events": [],
"finance_transactions": [],
"daily_logs": [],
"journals": [],
"chat_sessions": [],
"chat_messages": [],
"proposals": [],
"contracts": [],
"invoices": [],
"subscriptions": [],
"app_settings": [],
"document_embeddings": []
},
"storage": {
"objects": []
}
}
```
Eksik tablo anahtarları boş liste kabul edilir. Satırlar eski Supabase tablosundaki kolon adlarını kullanır. `user_id` taşıyan bütün satırlar `source.owner_user_id` ile aynı olmak zorundadır.
Storage kaydı:
```json
{
"bucket": "project-assets",
"object_path": "owner/project-cover.png",
"local_path": "storage/project-assets/project-cover.png",
"original_name": "project-cover.png",
"mime_type": "image/png",
"bytes": 12345,
"sha256": "64-karakter-lowercase-hex",
"project_id": "project-uuid",
"portal_visible": true,
"references": [
{
"type": "project_cover",
"project_id": "project-uuid"
}
]
}
```
`local_path` export root dışına çıkamaz. Desteklenen görseller PNG, JPEG, WebP ve GIF'tir; 5 MiB sınırı, byte count, SHA-256 ve magic-byte doğrulanır.
Export hazırlarken:
1. Supabase tablolarını JSON array olarak dışarı alın.
2. Yalnızca taşınacak owner'ın satırlarını bundle'a koyun.
3. `avatars` ve `project-assets` objelerini indirip relative `local_path` verin.
4. Her dosyanın byte count ve SHA-256 değerini storage manifest'e yazın.
5. Export klasörünü erişimi sınırlı, şifreli bir alanda tutun.
Auth kullanıcı export'u, access/refresh token, password hash ve secret key bundle'a eklenmemelidir. Araç böyle bir alanı kullanmaz.
## 3. Normalization ve güvenlik kararları
- Kaynak UUID/text ID'leri korunur.
- Kaynak owner kimliği hedef Better Auth owner kimliğine map edilir.
- `tasks.status=completed`, `done` olur.
- Ondalıklı para değerleri floating point kullanmadan integer minor unit'e çevrilir.
- Fatura vergi yüzdesi integer basis point'e çevrilir.
- Aynı tarihteki `daily_logs` ve `journals`, `journal_entries` içinde tek kanonik kayda birleşir.
- Birleşen journal referansları görev ve chat context'lerinde kanonik ID'ye çevrilir.
- Bilinmeyen enum, geçersiz tarih/para, duplicate ID ve eksik foreign key import'u durdurur.
- Eski AI API key'i import edilmez.
- Auth password/session verisi import edilmez.
- Eski client auth bağları temizlenir; müşteriler yeniden davet edilir.
- Tarihsel client revision actor'u geçerli principal bulunmadığında owner'a map edilir ve warning raporlanır.
- `document_embeddings` runtime'a taşınmaz; warning ile arşiv kapsamı dışında bırakılır.
- Project cover ve planning metadata içindeki taşınan storage referansları `/api/files/:id` URL'sine çevrilir.
## 4. Dry-run ve import
Hedefte migration'ları uygulayın ve ilk owner'ı `/register` üzerinden oluşturun. Owner ID'sini `user.id`/`app_profiles.auth_user_id` üzerinden belirleyin.
```bash
pnpm db:import:supabase -- \
--from /secure/path/neta-export \
--owner-user-id TARGET_OWNER_ID \
--dry-run \
--report /secure/path/import-dry-run-report.json
```
Dry-run DB veya upload alanını değiştirmez. Raporda kaynak sayıları, hedefe hazırlanmış sayılar, mevcut hedef sayıları ve warning'ler bulunur.
Apply:
```bash
pnpm db:import:supabase -- \
--from /secure/path/neta-export \
--owner-user-id TARGET_OWNER_ID \
--report /secure/path/import-report.json
```
Araç boş domain hedefini varsayar. Kontrollü tekrar çalıştırma/merge gerekiyorsa:
```bash
pnpm db:import:supabase -- \
--from /secure/path/neta-export \
--owner-user-id TARGET_OWNER_ID \
--allow-existing
```
Tekrar çalıştırma ID bazlı upsert'tir. Var olan aynı storage path yalnızca checksum aynıysa kabul edilir. Dosyalar DB transaction'ından önce stage edilir; DB hatasında yeni dosyalar geri alınır.
## 5. Production cutover
Gerçek production verisine erişim gerektiren bu adımlar otomatik checklist olarak işaretlenmez:
1. Mevcut Supabase sisteminin tam backup/export'unu alın.
2. Yeni Neta instance'ında owner'ı oluşturun.
3. Yeni instance'ın pre-import backup'ını alın.
4. Export bundle'ı dry-run ile doğrulayın.
5. Eski sistemi maintenance/read-only moda alın.
6. Son tablo ve storage export'unu üretin.
7. Final dry-run raporunu önceki sayımlarla karşılaştırın.
8. Import'u uygulayın.
9. Rapor, foreign key check, tablo sayıları ve storage checksum'larını doğrulayın.
10. Login, müşteri, proje, görev, finans, dosya ve portal davet akışlarını smoke test edin.
11. DNS/reverse proxy trafiğini yeni instance'a alın.
12. Client re-invite planını uygulayın.
13. Eski Supabase projesini en az 7 günlük rollback penceresi boyunca read-only tutun; daha uzun ürün/uyumluluk retention'ı gerekiyorsa bu süreyi artırın ve hemen silmeyin.
## 6. Rollback
Cutover öncesi:
```bash
pnpm db:backup -- --retention-count 14
```
Uygulamayı durdurduktan sonra doğrulama amaçlı ayrı hedefe restore:
```bash
pnpm db:restore -- \
--from /app/data/backups/neta-TIMESTAMP \
--target /tmp/neta-rollback-rehearsal \
--force
```
Production rollback:
1. Yeni instance'ı maintenance'a alın ve durdurun.
2. Cutover öncesi backup'ı restore edin veya DNS'i read-only eski sisteme döndürün.
3. Restore sonrası `/api/health/ready` ve kritik akışları kontrol edin.
4. Yeni sistemde cutover sonrası yazı oluştuysa veri kaybı penceresini açıkça kaydedin; iki sistemi otomatik merge etmeyin.
`phase8:import-smoke`, pre-import backup'ı gerçek SQLite dosyasına restore ederek bu rollback yolunu fixture üzerinde doğrular.
## 7. Backup politikası
Örnek günlük cron:
```text
0 2 * * * cd /app && BACKUP_RETENTION_COUNT=14 node scripts/backup.mjs
```
- En az 14 günlük local retention önerilir.
- Backup'ı aynı diskle sınırlamayın; şifreli off-host kopya alın.
- Restore'u düzenli olarak geçici data directory üzerinde prova edin.
- Uygulama online iken backup alınabilir; restore sırasında process durmalıdır.
- Manifest dışı, değiştirilmiş veya symlink içeren backup reddedilir.
## 8. Docker, Coolify ve Dokploy
Ortak production sözleşmesi:
- Repository `Dockerfile` kullanılır.
- Internal port `3000`.
- Tek replica.
- `/app/data` persistent volume.
- `APP_URL` ve `NEXT_PUBLIC_SITE_URL` aynı HTTPS origin.
- Güçlü `BETTER_AUTH_SECRET`.
- Healthcheck `/api/health/ready`.
- Reverse proxy websocket/streaming response'ları kesmemeli ve request body limitini en az 8 MiB tutmalıdır.
Coolify/Dokploy'da Dockerfile build seçin; Nixpacks/ephemeral filesystem kullanmayın. Persistent volume deploy/rebuild sırasında silinmemelidir.
## 9. Upgrade ve rollback
1. Release tag/image'i sabitleyin.
2. Backup ve restore provasını tamamlayın.
3. Yeni image'i build edin.
4. Tek instance'ı durdurup yeni image'i başlatın.
5. Startup migration'ın başarılı olduğunu ve readiness'in `200` döndüğünü doğrulayın.
6. Kritik smoke testleri çalıştırın.
Migration sonrası geri dönüşte eski image ile birlikte upgrade öncesi DB backup'ı restore edilmelidir. Drizzle migration dosyalarını elle silmek veya SQLite şemasını elle downgrade etmek desteklenmez.
## 10. Release doğrulama komutları
```bash
pnpm phase1:smoke
pnpm phase4:ui-boundary
pnpm phase5:backend-boundary
pnpm phase6:portal-boundary
pnpm phase7:backend-boundary
pnpm phase8:import-smoke
pnpm phase8:release-boundary
pnpm typecheck
pnpm build
node scripts/phase8-release-boundary.mjs --build-output
```
Docker daemon bulunan hostta ayrıca:
```bash
docker compose config
docker compose build
docker compose up -d
curl --fail http://127.0.0.1:3000/api/health/ready
docker compose down
```
Production cutover checklist'i dış sisteme erişim, maintenance kararı ve DNS yetkisi gerektirir; fixture provası bu gerçek operasyonun yerine geçmez.
-72
View File
@@ -1,72 +0,0 @@
import { embed } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createClient } from '@/lib/supabase/server';
export async function generateEmbedding(text: string, provider: string, apiKey: string) {
let embeddingModel;
if (provider === 'google' && apiKey) {
const google = createGoogleGenerativeAI({ apiKey });
embeddingModel = google.textEmbeddingModel('text-embedding-004');
} else if (apiKey) {
const openai = createOpenAI({ apiKey });
embeddingModel = openai.embedding('text-embedding-3-small');
} else {
throw new Error('Geçerli bir API Anahtarı bulunamadı.');
}
const { embedding } = await embed({
model: embeddingModel,
value: text,
});
return embedding;
}
export async function saveDocumentEmbedding(
userId: string,
content: string,
metadata: Record<string, any>,
provider: string,
apiKey: string
) {
const embedding = await generateEmbedding(content, provider, apiKey);
const supabase = await createClient();
const { error } = await supabase.from('document_embeddings').insert({
user_id: userId,
content,
metadata,
embedding,
});
if (error) {
console.error('Embedding kayıt hatası:', error);
throw new Error('Embedding kaydedilemedi.');
}
}
export async function searchSimilarDocuments(
userId: string,
query: string,
provider: string,
apiKey: string,
matchCount: number = 5
) {
const queryEmbedding = await generateEmbedding(query, provider, apiKey);
const supabase = await createClient();
const { data, error } = await supabase.rpc('match_documents', {
query_embedding: queryEmbedding,
match_count: matchCount,
filter_user_id: userId,
});
if (error) {
console.error('Vektör arama hatası:', error);
return [];
}
return data;
}
-111
View File
@@ -1,111 +0,0 @@
import { createClient } from "@/lib/supabase/server";
type FirstAdminSetupState = {
available: boolean;
errorMessage?: string;
};
type FirstAdminSetupOptions = {
timeoutMs?: number;
};
const DEFAULT_SETUP_TIMEOUT_MS = 5_000;
function createTimeoutSignal(timeoutMs: number) {
if (typeof AbortSignal !== "undefined" && "timeout" in AbortSignal) {
return AbortSignal.timeout(timeoutMs);
}
const controller = new AbortController();
setTimeout(() => controller.abort(), timeoutMs).unref?.();
return controller.signal;
}
function isMissingSetupFunctionError(error: {
code?: string;
message?: string;
}) {
return (
error.code === "PGRST202" ||
error.message?.includes("is_first_admin_setup_available")
);
}
async function getSetupStateFromProfiles(
timeoutMs: number,
): Promise<FirstAdminSetupState | null> {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!supabaseUrl || !serviceRoleKey) {
return null;
}
const endpoint = new URL("/rest/v1/profiles", supabaseUrl);
endpoint.searchParams.set("select", "id");
endpoint.searchParams.set("limit", "1");
try {
const response = await fetch(endpoint, {
cache: "no-store",
signal: createTimeoutSignal(timeoutMs),
headers: {
apikey: serviceRoleKey,
authorization: `Bearer ${serviceRoleKey}`,
},
});
if (!response.ok) {
console.error("First admin setup fallback check failed", {
status: response.status,
body: await response.text(),
});
return null;
}
const rows = (await response.json()) as Array<{ id: string }>;
return { available: rows.length === 0 };
} catch (error) {
console.error("First admin setup fallback request failed", error);
return null;
}
}
export async function getFirstAdminSetupState(
options: FirstAdminSetupOptions = {},
): Promise<FirstAdminSetupState> {
const timeoutMs = options.timeoutMs ?? DEFAULT_SETUP_TIMEOUT_MS;
const supabase = await createClient();
const { data, error } = await supabase
.rpc("is_first_admin_setup_available")
.abortSignal(createTimeoutSignal(timeoutMs));
if (error) {
console.error("First admin setup check failed", {
code: error.code,
message: error.message,
details: error.details,
hint: error.hint,
});
const fallbackState = await getSetupStateFromProfiles(timeoutMs);
if (fallbackState) {
if (isMissingSetupFunctionError(error)) {
console.warn(
"First admin setup RPC is not available through PostgREST yet; using service-role profile fallback.",
);
}
return fallbackState;
}
return {
available: false,
errorMessage:
"İlk kurulum kontrolü yapılamadı. Veritabanı hazırlık servisi henüz tamamlanmamış olabilir; birkaç saniye sonra tekrar deneyin.",
};
}
return { available: Boolean(data) };
}
-65
View File
@@ -1,65 +0,0 @@
import { createServiceRoleClient } from "@/lib/supabase/admin";
type InternalAuthUserRole = "freelancer" | "client";
type CreateInternalAuthUserInput = {
email: string;
password: string;
role: InternalAuthUserRole;
reason: string;
};
export async function createInternalAuthUser({
email,
password,
role,
reason,
}: CreateInternalAuthUserInput) {
const admin = createServiceRoleClient();
const normalizedEmail = email.trim().toLowerCase();
if (!normalizedEmail || !password) {
throw new Error("E-posta ve şifre zorunludur.");
}
const { error: guardError } = await admin.rpc(
"request_internal_auth_creation",
{
target_email: normalizedEmail,
target_reason: reason,
},
);
if (guardError) {
throw new Error(
`Kullanıcı oluşturma hazırlığı tamamlanamadı: ${guardError.message}`,
);
}
const { data, error } = await admin.auth.admin.createUser({
email: normalizedEmail,
password,
email_confirm: true,
app_metadata: {
internal_created: true,
role,
},
user_metadata: {
role,
},
});
if (error) {
throw new Error(error.message);
}
if (!data.user?.id) {
throw new Error("Kullanıcı oluşturuldu fakat kullanıcı kimliği alınamadı.");
}
return {
admin,
user: data.user,
userId: data.user.id,
};
}
-52
View File
@@ -1,52 +0,0 @@
import Dexie, { type Table } from "dexie";
// Veritabanı Modelleri
export interface Journal {
id: string;
date: string;
mood: string;
energy: number;
content: string;
ai_tags?: string[];
ai_sentiment_score?: number;
ai_summary?: string;
created_at: string;
updated_at: string;
}
export interface Task {
id: string;
journal_id?: string;
title: string;
status: "todo" | "in_progress" | "completed";
ai_generated: boolean;
date: string;
created_at: string;
}
export interface ChatMessage {
id: string;
role: "user" | "assistant";
content: string;
created_at: string;
}
export class MindSpaceDB extends Dexie {
journals!: Table<Journal>;
tasks!: Table<Task>;
chat_messages!: Table<ChatMessage>;
constructor() {
super("MindSpaceDatabase");
// Schema tanımlamaları.
// IndexedDB'de sadece indekslenecek (üzerinde arama/sıralama yapılacak) alanları belirtiriz.
this.version(2).stores({
journals: "id, date, mood",
tasks: "id, status, date, journal_id",
chat_messages: "id, created_at",
});
}
}
export const db = new MindSpaceDB();
-17
View File
@@ -1,17 +0,0 @@
import { createClient } from "@supabase/supabase-js";
export function createServiceRoleClient() {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!supabaseUrl || !serviceRoleKey) {
throw new Error("Supabase service role yapılandırması eksik.");
}
return createClient(supabaseUrl, serviceRoleKey, {
auth: {
autoRefreshToken: false,
persistSession: false,
},
});
}
-8
View File
@@ -1,8 +0,0 @@
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
-62
View File
@@ -1,62 +0,0 @@
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function updateSession(request: NextRequest) {
const pathname = request.nextUrl.pathname
if (
pathname.startsWith('/login') ||
pathname.startsWith('/register') ||
pathname.startsWith('/auth') ||
pathname.startsWith('/forgot-password')
) {
return NextResponse.next({ request })
}
let supabaseResponse = NextResponse.next({
request,
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// IMPORTANT: Avoid writing any logic between createServerClient and
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
// issues with users being randomly logged out.
const {
data: { user },
} = await supabase.auth.getUser()
if (
!user &&
!pathname.startsWith('/login') &&
!pathname.startsWith('/register') &&
!pathname.startsWith('/auth')
) {
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone()
url.pathname = '/login'
return NextResponse.redirect(url)
}
return supabaseResponse
}
-29
View File
@@ -1,29 +0,0 @@
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => {
cookieStore.set(name, value, options)
})
} catch {
// The `set` method was called from a Server Component.
// This can be ignored if you have middleware refreshing
// user sessions.
}
},
},
}
)
}
+1 -8
View File
@@ -1,11 +1,4 @@
import type { NextConfig } from "next"; import type { NextConfig } from "next";
import withPWAInit from "@ducanh2912/next-pwa";
const withPWA = withPWAInit({
dest: "public",
disable: process.env.NODE_ENV === "development",
register: true,
});
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
output: "standalone", output: "standalone",
@@ -17,4 +10,4 @@ const nextConfig: NextConfig = {
turbopack: {}, turbopack: {},
}; };
export default withPWA(nextConfig); export default nextConfig;
+176 -2974
View File
File diff suppressed because it is too large Load Diff
+7 -13
View File
@@ -12,6 +12,7 @@
"db:migrate": "node scripts/migrate.mjs", "db:migrate": "node scripts/migrate.mjs",
"db:backup": "node scripts/backup.mjs", "db:backup": "node scripts/backup.mjs",
"db:restore": "node scripts/restore.mjs", "db:restore": "node scripts/restore.mjs",
"db:import:supabase": "node scripts/import-supabase.mjs",
"phase1:smoke": "node scripts/phase1-smoke.mjs", "phase1:smoke": "node scripts/phase1-smoke.mjs",
"phase1:auth-smoke": "node scripts/phase1-auth-smoke.mjs", "phase1:auth-smoke": "node scripts/phase1-auth-smoke.mjs",
"phase2:domain-smoke": "node scripts/phase2-domain-smoke.mjs", "phase2:domain-smoke": "node scripts/phase2-domain-smoke.mjs",
@@ -21,28 +22,23 @@
"phase5:backend-boundary": "node scripts/phase5-backend-boundary.mjs", "phase5:backend-boundary": "node scripts/phase5-backend-boundary.mjs",
"phase5:smoke": "node scripts/phase5-freelancer-smoke.mjs", "phase5:smoke": "node scripts/phase5-freelancer-smoke.mjs",
"phase6:portal-boundary": "node scripts/phase6-portal-boundary.mjs", "phase6:portal-boundary": "node scripts/phase6-portal-boundary.mjs",
"phase6:smoke": "node scripts/phase6-portal-smoke.mjs" "phase6:smoke": "node scripts/phase6-portal-smoke.mjs",
"phase7:backend-boundary": "node scripts/phase7-backend-boundary.mjs",
"phase7:smoke": "node scripts/phase7-smoke.mjs",
"phase8:import-smoke": "node scripts/phase8-import-smoke.mjs",
"phase8:release-boundary": "node scripts/phase8-release-boundary.mjs"
}, },
"dependencies": { "dependencies": {
"@ai-sdk/google": "^3.0.80", "@ai-sdk/google": "^3.0.80",
"@ai-sdk/groq": "^3.0.39", "@ai-sdk/groq": "^3.0.39",
"@ai-sdk/openai": "^3.0.68", "@ai-sdk/openai": "^3.0.68",
"@ai-sdk/react": "^3.0.199", "@ai-sdk/react": "^3.0.199",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@ducanh2912/next-pwa": "^10.2.9",
"@hookform/resolvers": "^5.4.0",
"@supabase/ssr": "^0.10.3",
"@supabase/supabase-js": "^2.105.3",
"@tailwindcss/postcss": "^4.3.0", "@tailwindcss/postcss": "^4.3.0",
"ai": "^6.0.197", "ai": "^6.0.197",
"better-auth": "^1.6.23", "better-auth": "^1.6.23",
"better-sqlite3": "^12.11.1", "better-sqlite3": "^12.11.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.4.0", "date-fns": "^4.4.0",
"dexie": "^4.4.3",
"dexie-react-hooks": "^4.4.0",
"drizzle-orm": "^0.45.2", "drizzle-orm": "^0.45.2",
"framer-motion": "^11.18.2", "framer-motion": "^11.18.2",
"lucide-react": "^1.17.0", "lucide-react": "^1.17.0",
@@ -51,11 +47,10 @@
"poyraz-ui": "^3.0.2", "poyraz-ui": "^3.0.2",
"react": "^19.2.7", "react": "^19.2.7",
"react-dom": "^19.2.7", "react-dom": "^19.2.7",
"react-hook-form": "^7.77.0", "react-hook-form": "^7.81.0",
"recharts": "^3.8.1", "recharts": "^3.8.1",
"tailwind-merge": "^3.6.0", "tailwind-merge": "^3.6.0",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"uuid": "^14.0.0",
"zod": "^4.4.3" "zod": "^4.4.3"
}, },
"devDependencies": { "devDependencies": {
@@ -63,7 +58,6 @@
"@types/node": "^22.19.19", "@types/node": "^22.19.19",
"@types/react": "^19.2.16", "@types/react": "^19.2.16",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/uuid": "^10.0.0",
"autoprefixer": "^10.5.0", "autoprefixer": "^10.5.0",
"drizzle-kit": "^0.31.10", "drizzle-kit": "^0.31.10",
"eslint": "^9.39.4", "eslint": "^9.39.4",
+4 -2465
View File
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
{
"short_name": "Neta",
"description": "Self-hosted freelancer operating dashboard",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone",
"orientation": "portrait",
"scope": "/",
"start_url": "/",
"icons": [
{
"src": "/logo/iconLogo.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/logo/iconLogo.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
-1
View File
@@ -44,7 +44,6 @@ for (const file of requiredSystemCompositions) {
} }
const allowedLocalUiFiles = new Set([ const allowedLocalUiFiles = new Set([
"offline-indicator.tsx",
"pending-link.tsx", "pending-link.tsx",
"pending-submit-button.tsx", "pending-submit-button.tsx",
]); ]);
+109
View File
@@ -0,0 +1,109 @@
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
const repoRoot = process.cwd();
const packageJson = readJson("package.json");
const installed = {
...packageJson.dependencies,
...packageJson.devDependencies,
...packageJson.optionalDependencies,
};
const removedPackages = [
"@supabase/ssr",
"@supabase/supabase-js",
"@ducanh2912/next-pwa",
"dexie",
"dexie-react-hooks",
"@dnd-kit/core",
"@dnd-kit/sortable",
"@dnd-kit/utilities",
"@hookform/resolvers",
"uuid",
"@types/uuid",
];
for (const dependency of removedPackages) {
assert.equal(installed[dependency], undefined, `Removed dependency is still declared: ${dependency}`);
}
const runtimeTargets = [
"app",
"components",
"config",
"lib",
"server",
"proxy.ts",
"next.config.ts",
".env.example",
];
const runtimePatterns = [
[/@supabase\//i, "Supabase package import"],
[/\b(?:NEXT_PUBLIC_SUPABASE_URL|NEXT_PUBLIC_SUPABASE_ANON_KEY|SUPABASE_SERVICE_ROLE_KEY)\b/, "Supabase runtime environment variable"],
[/\b(?:dexie|dexie-react-hooks)\b/i, "browser database dependency"],
[/\bnext-pwa\b/i, "PWA wrapper"],
[/\b(?:serviceWorker|service-worker|workbox|OfflineIndicator|offline-indicator)\b/i, "offline/PWA runtime"],
];
const violations = [];
for (const filePath of runtimeTargets.flatMap(walk)) {
const content = fs.readFileSync(filePath, "utf8");
for (const [pattern, label] of runtimePatterns) {
if (pattern.test(content)) {
violations.push(`${path.relative(repoRoot, filePath)}: ${label}`);
}
}
}
assert.deepEqual(violations, [], `Phase 8 runtime boundary violations:\n${violations.join("\n")}`);
const publicFiles = walk("public").map((filePath) => path.basename(filePath).toLowerCase());
assert.equal(
publicFiles.some((fileName) => /^(?:sw|service-worker|workbox-.+)\.(?:js|mjs)$/.test(fileName)),
false,
"Generated service worker output remains in public/",
);
if (process.argv.includes("--build-output")) {
const buildTargets = [".next/server/app", ".next/server/chunks", ".next/static"];
const buildViolations = [];
for (const filePath of buildTargets.flatMap(walk).filter(isTextBuildFile)) {
const content = fs.readFileSync(filePath, "utf8");
if (
/@supabase\/|NEXT_PUBLIC_SUPABASE_(?:URL|ANON_KEY)|SUPABASE_SERVICE_ROLE_KEY|supabase\.co/i.test(
content,
)
) {
buildViolations.push(path.relative(repoRoot, filePath));
}
}
assert.deepEqual(
buildViolations,
[],
`Supabase reference remains in production output:\n${buildViolations.join("\n")}`,
);
}
console.log(
`Phase 8 release boundary passed${process.argv.includes("--build-output") ? " (source and build output)" : " (source)"}.`,
);
function readJson(relativePath) {
return JSON.parse(fs.readFileSync(path.join(repoRoot, relativePath), "utf8"));
}
function walk(targetPath) {
const absolutePath = path.join(repoRoot, targetPath);
if (!fs.existsSync(absolutePath)) return [];
const stat = fs.lstatSync(absolutePath);
if (stat.isSymbolicLink()) return [];
if (stat.isFile()) return [absolutePath];
return fs.readdirSync(absolutePath, { withFileTypes: true }).flatMap((entry) => {
if (entry.isSymbolicLink()) return [];
return walk(path.relative(repoRoot, path.join(absolutePath, entry.name)));
});
}
function isTextBuildFile(filePath) {
return /\.(?:html|js|json|mjs|rsc|txt)$/.test(filePath);
}
+6 -60
View File
@@ -1,67 +1,13 @@
# Supabase Directory # Legacy Supabase archive
This directory stores SQL files for the project's Supabase/PostgreSQL database. Bu klasör Neta v2'nin eski PostgreSQL şeması, migration'ları ve seed kayıtları için salt tarihsel/import kaynağıdır.
## One-Shot Setup Self-hosted v3 runtime'ı bu SQL dosyalarını çalıştırmaz; Supabase Auth, Database, Storage veya environment değişkeni kullanmaz. Yeni değişiklikler `server/db/schema` ve `server/db/migrations` altında Drizzle/SQLite migration'ı olarak yapılmalıdır.
For a fresh Supabase project, use: Bu arşivi yalnızca eski bir Supabase instance'ının kolonlarını anlamak ve `neta-supabase-export` bundle'ı hazırlamak için kullanın. Güncel aktarım sözleşmesi ve cutover runbook'u:
```text ```text
supabase/setup.sql docs/self-hosted-redesign/phase-8-import-release.md
``` ```
You can paste the full file into Supabase SQL Editor and run it once, or run it from the repository root with `psql`: Arşivdeki SQL'i yeni Neta kurulumu için çalıştırmayın.
```bash
psql "postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres" -v ON_ERROR_STOP=1 -f supabase/setup.sql
```
The setup file is generated by concatenating `schema.sql` and migrations `0002` through `0011` in the canonical order. Demo seed data is intentionally not included.
## Current Baseline
- `schema.sql` is the first registered database SQL file.
- Its documentation is in `docs/database/0001-initial-schema.md`.
- Its order is tracked in `docs/database/query-order.md`.
- Execution history is tracked in `docs/database/query-log.md`.
## Future Changes
Future schema changes should be added under:
```text
supabase/migrations/
```
Optional local/demo data should be added under:
```text
supabase/seeds/
```
Do not overwrite already executed SQL without also creating a new ordered migration and documenting why.
## Current Ordered SQL
1. `schema.sql`
2. `migrations/0002_add_freelancer_os_core_tables.sql`
3. `migrations/0003_add_project_planning_assets.sql`
4. `migrations/0004_add_business_os_tables.sql`
5. `migrations/0005_add_advanced_crm_tables.sql`
6. `migrations/0006_add_pgvector_and_embeddings.sql`
7. `migrations/0007_add_client_portal_tables.sql`
8. `migrations/0008_add_project_progress_and_quota.sql`
9. `migrations/0009_lock_registration_after_first_admin.sql`
10. `migrations/0010_allow_internal_auth_user_creation.sql`
11. `migrations/0011_fix_service_role_claims_and_storage_policies.sql`
12. Optional local/demo data: `seeds/0001_demo_freelancer_os_data.sql`
## Apply Migrations
For a new project, prefer the one-shot setup file:
```bash
psql "postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres" -v ON_ERROR_STOP=1 -f supabase/setup.sql
```
The ordered migration files remain as the source history for future schema changes.