refactor: update environment configuration, enhance installation script, and add migration scripts for database setup

This commit is contained in:
Poyraz Avsever
2026-06-13 21:10:21 +03:00
parent a47e39455c
commit 17ff60faea
12 changed files with 400 additions and 74 deletions
+20 -11
View File
@@ -1,14 +1,23 @@
# ─── Supabase (Zorunlu) ─────────────────────────────────────── # Neta self-host environment
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
# Müşteri Portalı hesabı oluşturmak için gerekli (Freelancer panelinde kullanılır) # Public URL where users open Neta.
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key NEXT_PUBLIC_SITE_URL=http://localhost:3000
# ─── AI Sağlayıcılar (Opsiyonel — uygulama içi ayarlardan da tanımlanabilir) ─── # Host port mapped to the Neta container's internal port 3000.
# OPENAI_API_KEY=your_openai_api_key NETA_PORT=3000
# GROQ_API_KEY=your_groq_api_key
# GEMINI_API_KEY=your_gemini_api_key
# ─── Supabase Auth (Self-host'ta gerekli olabilir) ─────────── # Supabase API URL. For a hosted project this looks like:
# NEXT_PUBLIC_SITE_URL=https://neta.example.com # https://your-project.supabase.co
# For a bundled/self-hosted Supabase setup this is usually your public API URL.
NEXT_PUBLIC_SUPABASE_URL=
# Supabase anon/public API key.
NEXT_PUBLIC_SUPABASE_ANON_KEY=
# Supabase service role key. Required for creating client portal accounts.
# Keep this secret. It is only used server-side.
SUPABASE_SERVICE_ROLE_KEY=
# Optional: direct Postgres connection string used only by bash ./scripts/apply-migrations.sh.
# Do not expose this to browsers. It is not required by the web container.
# DATABASE_URL=postgresql://postgres:password@host:5432/postgres
+20 -7
View File
@@ -50,32 +50,45 @@ Neta is engineered using modern, high-performance web technologies:
## Installation and Deployment ## Installation and Deployment
Neta is designed to be easily self-hosted. Follow these steps to deploy the application on your own infrastructure. Neta is designed for self-hosting. The current Docker Compose file runs the Neta web application and connects it to a Supabase-compatible backend. A bundled Supabase Compose profile is planned for the full-stack self-host mode.
### Prerequisites ### Prerequisites
- Docker and Docker Compose - Docker and Docker Compose
- Node.js (for local development) - A Supabase project or self-hosted Supabase backend
- A Supabase instance (Cloud or Self-Hosted) - Supabase API URL, anon key, and service role key
- A direct Postgres `DATABASE_URL` if you want the installer to apply migrations automatically
### 1-Click Installation (Recommended) ### 1-Click Installation (Recommended)
You can install and start Neta immediately using our automated setup script. Simply run the following command in your terminal: You can install Neta using the interactive setup script:
```bash ```bash
curl -sL https://raw.githubusercontent.com/poyrazavsever/neta/main/install.sh | bash curl -sL https://raw.githubusercontent.com/poyrazavsever/neta/main/install.sh | bash
``` ```
The installer asks for the required Supabase values, writes a `.env` file, optionally applies database migrations, validates Docker Compose configuration, and starts the application.
### Manual Installation ### Manual Installation
If you prefer to set up Neta manually: If you prefer to set up Neta manually:
1. Clone the repository: `git clone https://github.com/poyrazavsever/neta.git` 1. Clone the repository: `git clone https://github.com/poyrazavsever/neta.git`
2. Navigate to the directory and copy the `.env.example` file to `.env.local`. 2. Navigate to the directory and copy the `.env.example` file to `.env`.
3. Build and start the Docker container: 3. Fill every required value in `.env`.
4. Apply database migrations:
```bash ```bash
docker-compose up -d --build DATABASE_URL='postgresql://postgres:password@host:5432/postgres' bash ./scripts/apply-migrations.sh
``` ```
5. Build and start the Docker container:
```bash
docker compose up -d --build
```
Docker Compose intentionally fails fast when required Supabase environment values are missing.
### First Administrator Account ### First Administrator Account
To ensure data security, Neta is locked to a single administrator. Upon launching the application for the first time, navigate to the `/register` route to create the initial admin account. Once this account is created, public registration is permanently disabled. To ensure data security, Neta is locked to a single administrator. Upon launching the application for the first time, navigate to the `/register` route to create the initial admin account. Once this account is created, public registration is permanently disabled.
+8 -10
View File
@@ -4,18 +4,16 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL} NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL:?Set NEXT_PUBLIC_SUPABASE_URL in .env}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY} NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY:?Set NEXT_PUBLIC_SUPABASE_ANON_KEY in .env}
NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-http://localhost:3000} NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-http://localhost:3000}
container_name: neta-web container_name: neta-web
restart: unless-stopped restart: unless-stopped
ports: ports:
- "3000:3000" - "${NETA_PORT:-3000}:3000"
environment: environment:
- NODE_ENV=production NODE_ENV: production
- NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL} NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL:?Set NEXT_PUBLIC_SUPABASE_URL in .env}
- NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY} NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY:?Set NEXT_PUBLIC_SUPABASE_ANON_KEY in .env}
- SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY} SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY:?Set SUPABASE_SERVICE_ROLE_KEY in .env}
- NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL:-http://localhost:3000} NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-http://localhost:3000}
env_file:
- .env.local
+22
View File
@@ -0,0 +1,22 @@
# 0004 - Business OS Tables
SQL file: `supabase/migrations/0004_add_business_os_tables.sql`
## Purpose
Adds business document and recurring cost tables used by the freelancer business layer.
## What It Creates
- `proposals`
- `contracts`
- `invoices`
- `subscriptions`
## RLS
Every table has `user_id` and row level security policies that allow users to select, insert, update, and delete only their own rows.
## Execution
Run after `0003_add_project_planning_assets.sql`.
+28
View File
@@ -0,0 +1,28 @@
# 0005 - Advanced CRM Tables
SQL file: `supabase/migrations/0005_add_advanced_crm_tables.sql`
## Purpose
Extends client management with pipeline and activity tracking fields.
## What It Changes
The `clients` table receives:
- `pipeline_stage`
- `next_follow_up_date`
- `last_contact_date`
- `client_value_score`
## What It Creates
- `client_activities`
## RLS
`client_activities` is user-scoped through `user_id` and has select, insert, update, and delete policies for the owning user.
## Execution
Run after `0004_add_business_os_tables.sql`.
@@ -0,0 +1,25 @@
# 0006 - pgvector And Embeddings
SQL file: `supabase/migrations/0006_add_pgvector_and_embeddings.sql`
## Purpose
Adds vector storage for future retrieval augmented generation features.
## What It Creates
- `vector` extension
- `document_embeddings`
- `match_documents()`
## RLS
Embeddings are scoped by `user_id`; users can manage only their own embedding rows.
## Notes
The migration expects the target Postgres/Supabase environment to support the `vector` extension.
## Execution
Run after `0005_add_advanced_crm_tables.sql`.
@@ -0,0 +1,25 @@
# 0007 - Client Portal Tables
SQL file: `supabase/migrations/0007_add_client_portal_tables.sql`
## Purpose
Adds client portal access and revision request support.
## What It Changes
- Adds `profiles.role`
- Adds `clients.client_auth_id`
- Adds `tasks.is_public_to_client`
## What It Creates
- `project_revisions`
## RLS
Freelancers manage revisions for their own projects. Clients can view their linked client record, related projects, public project tasks, project planning sections, and their own revision requests.
## Execution
Run after `0006_add_pgvector_and_embeddings.sql`.
@@ -0,0 +1,29 @@
# 0008 - Project Progress And Quota
SQL file: `supabase/migrations/0008_add_project_progress_and_quota.sql`
## Purpose
Adds project progress mode and revision quota support.
## What It Changes
The `projects` table receives:
- `progress_type`
- `revision_quota`
## What It Creates
- `update_project_progress_on_task_change()`
- `trigger_update_project_progress`
- `update_project_progress_on_type_change()`
- `trigger_update_project_progress_type`
## Notes
Automatic progress mode calculates progress from tasks with status `done`.
## Execution
Run after `0007_add_client_portal_tables.sql`.
+15
View File
@@ -7,6 +7,11 @@ This file is the canonical order of SQL files for database setup and migration.
| 0001 | `supabase/schema.sql` | `docs/database/0001-initial-schema.md` | Baseline registered | | 0001 | `supabase/schema.sql` | `docs/database/0001-initial-schema.md` | Baseline registered |
| 0002 | `supabase/migrations/0002_add_freelancer_os_core_tables.sql` | `docs/database/0002-freelancer-os-core-tables.md` | Pending execution | | 0002 | `supabase/migrations/0002_add_freelancer_os_core_tables.sql` | `docs/database/0002-freelancer-os-core-tables.md` | Pending execution |
| 0003 | `supabase/migrations/0003_add_project_planning_assets.sql` | `docs/database/0003-project-planning-assets.md` | Pending execution | | 0003 | `supabase/migrations/0003_add_project_planning_assets.sql` | `docs/database/0003-project-planning-assets.md` | Pending execution |
| 0004 | `supabase/migrations/0004_add_business_os_tables.sql` | `docs/database/0004-business-os-tables.md` | Pending execution |
| 0005 | `supabase/migrations/0005_add_advanced_crm_tables.sql` | `docs/database/0005-advanced-crm-tables.md` | Pending execution |
| 0006 | `supabase/migrations/0006_add_pgvector_and_embeddings.sql` | `docs/database/0006-pgvector-and-embeddings.md` | Pending execution |
| 0007 | `supabase/migrations/0007_add_client_portal_tables.sql` | `docs/database/0007-client-portal-tables.md` | Pending execution |
| 0008 | `supabase/migrations/0008_add_project_progress_and_quota.sql` | `docs/database/0008-project-progress-and-quota.md` | Pending execution |
| 0009 | `supabase/migrations/0009_lock_registration_after_first_admin.sql` | `docs/database/0009-lock-registration-after-first-admin.md` | Pending execution | | 0009 | `supabase/migrations/0009_lock_registration_after_first_admin.sql` | `docs/database/0009-lock-registration-after-first-admin.md` | Pending execution |
| seed-0001 | `supabase/seeds/0001_demo_freelancer_os_data.sql` | `docs/database/seed-0001-demo-freelancer-os-data.md` | Optional demo seed, pending execution | | seed-0001 | `supabase/seeds/0001_demo_freelancer_os_data.sql` | `docs/database/seed-0001-demo-freelancer-os-data.md` | Optional demo seed, pending execution |
@@ -23,3 +28,13 @@ This file is the canonical order of SQL files for database setup and migration.
Seed files are optional and should live under `supabase/seeds/`. Seed files are optional and should live under `supabase/seeds/`.
They must also be documented and registered in this file, but they should only be run in local/demo environments unless explicitly approved. They must also be documented and registered in this file, but they should only be run in local/demo environments unless explicitly approved.
## Applying The Ordered SQL
Use the migration helper from the repository root:
```bash
DATABASE_URL='postgresql://postgres:password@host:5432/postgres' bash ./scripts/apply-migrations.sh
```
The helper applies `0001` through `0009` in the order listed above. It uses local `psql` when available, otherwise it runs `psql` through Docker.
+138 -45
View File
@@ -1,57 +1,150 @@
#!/bin/bash #!/usr/bin/env bash
# Neta - Freelancer Operating System Installation Script # Neta - Freelancer Operating System installer
set -e set -euo pipefail
echo "🚀 Neta kurulumu başlıyor..." REPO_URL="${NETA_REPO_URL:-https://github.com/poyrazavsever/neta.git}"
TARGET_DIR="${NETA_TARGET_DIR:-neta-os}"
# 1. Check for Git info() {
if ! [ -x "$(command -v git)" ]; then printf "\n%s\n" "$1"
echo "Hata: Git yüklü değil. Lütfen önce Git'i kurun." >&2 }
fail() {
echo "Error: $1" >&2
exit 1 exit 1
fi }
# 2. Check for Docker require_command() {
if ! [ -x "$(command -v docker)" ]; then command -v "$1" >/dev/null 2>&1 || fail "$1 is required."
echo "Hata: Docker yüklü değil. Lütfen önce Docker'ı kurun." >&2 }
exit 1
fi
# 3. Target directory compose_cmd() {
TARGET_DIR="neta-os" if docker compose version >/dev/null 2>&1; then
echo "docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
echo "docker-compose"
else
fail "Docker Compose is required."
fi
}
if [ -d "$TARGET_DIR" ]; then prompt_required() {
echo "Hata: '$TARGET_DIR' dizini zaten var. Lütfen farklı bir dizinde deneyin veya mevcut dizini silin." >&2 local var_name="$1"
exit 1 local label="$2"
fi local current_value="${!var_name:-}"
local value
# 4. Clone repository if [ -n "$current_value" ]; then
echo "📦 GitHub'dan kodlar indiriliyor..." return
git clone https://github.com/poyrazavsever/neta.git "$TARGET_DIR" fi
cd "$TARGET_DIR"
# 5. Setup environment variables while true; do
echo "⚙️ Çevresel değişkenler ayarlanıyor..." read -r -p "$label: " value
if [ -f ".env.example" ]; then if [ -n "$value" ]; then
cp .env.example .env.local printf -v "$var_name" "%s" "$value"
else export "$var_name"
echo "Uyarı: .env.example dosyası bulunamadı." return
fi fi
echo "This value is required."
done
}
# 6. Start with Docker Compose prompt_optional() {
echo "🐳 Docker container'ları inşa ediliyor ve başlatılıyor..." local var_name="$1"
if docker compose version > /dev/null 2>&1; then local label="$2"
docker compose up -d --build local default_value="$3"
elif docker-compose version > /dev/null 2>&1; then local current_value="${!var_name:-}"
docker-compose up -d --build local value
else
echo "Hata: docker-compose komutu bulunamadı." >&2
exit 1
fi
echo "" if [ -n "$current_value" ]; then
echo "✅ Kurulum tamamlandı!" return
echo "Neta başarıyla ayağa kaldırıldı." fi
echo "Tarayıcınızdan http://localhost:3000 adresine giderek Neta'yı kullanmaya başlayabilirsiniz."
echo "İlk girişte oluşturacağınız hesap, sistemin tek yöneticisi (admin) olacaktır." read -r -p "$label [$default_value]: " value
printf -v "$var_name" "%s" "${value:-$default_value}"
export "$var_name"
}
prompt_secret_required() {
local var_name="$1"
local label="$2"
local current_value="${!var_name:-}"
local value
if [ -n "$current_value" ]; then
return
fi
while true; do
read -r -s -p "$label: " value
echo
if [ -n "$value" ]; then
printf -v "$var_name" "%s" "$value"
export "$var_name"
return
fi
echo "This value is required."
done
}
write_env_file() {
cat > .env <<EOF
NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL
NETA_PORT=$NETA_PORT
NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY=$SUPABASE_SERVICE_ROLE_KEY
EOF
chmod 600 .env || true
}
main() {
info "Neta self-host installer"
require_command git
require_command docker
docker info >/dev/null 2>&1 || fail "Docker is installed but the daemon is not reachable."
if [ -d "$TARGET_DIR" ]; then
fail "'$TARGET_DIR' already exists. Set NETA_TARGET_DIR or remove the directory."
fi
info "Cloning Neta into $TARGET_DIR"
git clone "$REPO_URL" "$TARGET_DIR"
cd "$TARGET_DIR"
prompt_optional NEXT_PUBLIC_SITE_URL "Public Neta URL" "http://localhost:3000"
prompt_optional NETA_PORT "Host port for Neta" "3000"
prompt_required NEXT_PUBLIC_SUPABASE_URL "Supabase API URL"
prompt_secret_required NEXT_PUBLIC_SUPABASE_ANON_KEY "Supabase anon key"
prompt_secret_required SUPABASE_SERVICE_ROLE_KEY "Supabase service role key"
write_env_file
info "Wrote .env"
read -r -p "Apply Neta database migrations now? Requires a direct Postgres DATABASE_URL. [y/N]: " apply_migrations
if [ "$apply_migrations" = "y" ] || [ "$apply_migrations" = "Y" ]; then
prompt_secret_required DATABASE_URL "Postgres DATABASE_URL"
DATABASE_URL="$DATABASE_URL" bash ./scripts/apply-migrations.sh
else
echo "Skipping migrations. Run them later with:"
echo " DATABASE_URL='postgresql://...' bash ./scripts/apply-migrations.sh"
fi
local compose
compose="$(compose_cmd)"
info "Validating Docker Compose configuration"
$compose config >/dev/null
info "Building and starting Neta"
$compose up -d --build
info "Neta is starting"
echo "Open: $NEXT_PUBLIC_SITE_URL"
echo "Create the first admin account at: $NEXT_PUBLIC_SITE_URL/register"
}
main "$@"
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
if [ -z "${DATABASE_URL:-}" ]; then
echo "DATABASE_URL is required." >&2
echo "Example:" >&2
echo " DATABASE_URL='postgresql://postgres:password@host:5432/postgres' bash ./scripts/apply-migrations.sh" >&2
exit 1
fi
SQL_FILES=(
"supabase/schema.sql"
"supabase/migrations/0002_add_freelancer_os_core_tables.sql"
"supabase/migrations/0003_add_project_planning_assets.sql"
"supabase/migrations/0004_add_business_os_tables.sql"
"supabase/migrations/0005_add_advanced_crm_tables.sql"
"supabase/migrations/0006_add_pgvector_and_embeddings.sql"
"supabase/migrations/0007_add_client_portal_tables.sql"
"supabase/migrations/0008_add_project_progress_and_quota.sql"
"supabase/migrations/0009_lock_registration_after_first_admin.sql"
)
run_sql_file() {
local file_path="$1"
local absolute_path="$ROOT_DIR/$file_path"
if [ ! -f "$absolute_path" ]; then
echo "Missing SQL file: $file_path" >&2
exit 1
fi
echo "Applying $file_path"
if command -v psql >/dev/null 2>&1; then
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f "$absolute_path"
elif command -v docker >/dev/null 2>&1; then
docker run --rm -i postgres:16-alpine \
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f - < "$absolute_path"
else
echo "Neither psql nor docker is available to run migrations." >&2
exit 1
fi
}
for sql_file in "${SQL_FILES[@]}"; do
run_sql_file "$sql_file"
done
echo "All Neta migrations were applied."
+18 -1
View File
@@ -29,4 +29,21 @@ Do not overwrite already executed SQL without also creating a new ordered migrat
1. `schema.sql` 1. `schema.sql`
2. `migrations/0002_add_freelancer_os_core_tables.sql` 2. `migrations/0002_add_freelancer_os_core_tables.sql`
3. Optional: `seeds/0001_demo_freelancer_os_data.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. Optional local/demo data: `seeds/0001_demo_freelancer_os_data.sql`
## Apply Migrations
From the repository root:
```bash
DATABASE_URL='postgresql://postgres:password@host:5432/postgres' bash ./scripts/apply-migrations.sh
```
The script applies all required schema files in canonical order. It requires either local `psql` or Docker. If `psql` is not installed, it runs `psql` through the `postgres:16-alpine` Docker image.