13 KiB
title, description, status, last_updated
| title | description | status | last_updated |
|---|---|---|---|
| Phase 0 Data Mapping | Supabase kaynak modelinden SQLite/Next.js hedef modeline onaylı mapping ve production audit sorguları. | active | 2026-07-16 |
Phase 0 Data Mapping
Bu dosya Faz 0 için onaylı source-to-target veri mapping'idir. Production verisine bağlanmadan status dağılımı ve gerçek satır sayısı tamamlanamaz; bu nedenle her production-only madde audit sorgularıyla birlikte bırakılmıştır. Alan düzeyi nihai Drizzle schema Faz 2'de üretilecek, ancak tablo kaderi ve normalization kuralları bu belgeyle kilitlenmiştir.
Kanonik veri standartları
- ID: Mevcut UUID değerleri korunacak.
- Para:
numeric(12,2)kaynak değerleri hedefte integer minor unit olarak saklanacak. - Tarih: Kullanıcı iş tarihi
YYYY-MM-DD, timestamp alanları UTC epoch veya ISO storage standardı ile tekleştirilecek. - Sahiplik: Supabase RLS yerine
owner_user_id/session role filtreli repository sorguları kullanılacak. - Client portal: client auth user ile
clients.client_auth_idilişkisi hedefte invitation/account relation olarak modellenir. - File path: Supabase bucket path değerleri hedefte
filesmetadata tablosu ve/app/data/uploadsaltındaki relative path ile tutulur. - AI secrets:
app_settings.api_keydüz metin olarak taşınmaz; yeni sistemde env veya encrypted-at-rest secret store kararı uygulanır.
Source-to-target mapping
| Supabase kaynak | Mevcut amaç | Hedef model | Karar |
|---|---|---|---|
auth.users |
Supabase auth principal, freelancer/client user | Better Auth user/session/account tabloları | Password/session taşınmayacak; reset veya yeniden davet |
profiles |
Ad, avatar, role | app_profiles |
`role: freelancer |
clients |
CRM client ve portal auth link | clients |
auth_user_id nullable; invitation kabulünde transaction ile kurulur |
client_activities |
Client timeline | client_activities |
Sahiplik owner_user_id ile |
projects |
Proje kayıtları, progress, quota, cover image | projects |
budget_amount minor unit; cover image file metadata |
project_planning_sections |
Project planning content | project_planning_sections |
category ve sort_order kanonik |
project_revisions |
Portal revision requests | project_revisions |
Quota ve project/client eşleşmesi service transaction içinde |
tasks |
Task/kanban | tasks |
Status kanoniği `todo |
calendar_events |
Takvim | calendar_events |
Visible range indexleri |
finance_transactions |
Gelir/gider | finance_transactions |
Amount integer minor unit |
proposals |
Teklifler | proposals veya açık archive eşleniği |
Veri korunur; UI/CRUD release-blocker değildir |
contracts |
Sözleşmeler | contracts veya açık archive eşleniği |
Veri korunur; UI/CRUD release-blocker değildir |
invoices |
Faturalar | invoices veya açık archive eşleniği |
Amount/tax minor unit; UI/CRUD release-blocker değildir |
subscriptions |
Recurring expenses | subscriptions veya açık archive eşleniği |
Billing cycle enum korunur; UI/CRUD release-blocker değildir |
daily_logs |
Aktif journal ekranı | journal_entries |
journals ile birleştirilecek |
journals |
Legacy AI journal | journal_entries archive/import source |
Aynı güne denk gelen kayıtlar merge rule ile |
chat_sessions |
AI chat session | chat_sessions |
Browser DB erişimi kaldırılır |
chat_messages |
AI chat messages | chat_messages |
Message role enum validate edilir |
document_embeddings |
pgvector RAG | Archive table veya import dışı | İlk release'te operational vector search yok |
app_settings |
Timezone/currency/AI settings | user_preferences + server-side AI secret config |
api_key taşınmaz; yalnızca migration warning/count |
storage.objects bucket avatars |
Avatar dosyaları | files + /uploads/avatars |
Public read yerine authorized handler veya static controlled path |
storage.objects bucket project-assets |
Project cover/assets | files + /uploads/project-assets |
MIME/magic byte/size checks |
neta_internal.internal_auth_creations |
Service-role guarded auth creation handshake | Kaldırılır | Better Auth invite/setup flow ile gerek kalmaz |
Hedefte kaynaktan türemeyen yeni tablolar:
| Hedef model | Amaç | Faz 0 kararı |
|---|---|---|
instance_settings |
Instance adı, support ve genel davranış | Singleton instance config |
instance_branding |
Logo, renk, mode ve radius ayarları | Poyraz UI semantic token girdisi |
user_preferences |
Tema tercihi, timezone, currency ve UI tercihleri | Kullanıcı bazlı; secret içermez |
files |
Yerel dosya metadata ve güvenli relative path | İçerik /app/data/uploads altında |
portal_invitations |
Süreli ve hash'lenmiş client invite token | Better Auth client self-activation |
auth_audit_events |
Setup/login/logout güvenlik olayları | Mevcut SQLite model korunur |
Enum/status baseline
Kaynak schema ve koddan görülen status/type değerleri:
profiles.role:freelancer,clientclients.status:active,paused,archivedclients.pipeline_stage:lead,contacted,proposal_sent,won,lostprojects.type:client_project,side_projectprojects.status:planning,active,paused,completed,cancelledprojects.progress_type:manual,autotasks.status: aktif kodtodo,in_progress,done; legacylib/db.tsve portal UI'dacompletedtoleransı vartasks.priority:low,medium,high,urgentcalendar_events.type:meeting,focus,deadline,personal,financefinance_transactions.type:income,expensefinance_transactions.payment_status:planned,pending,paid,cancelledproposals.status:draft,sent,accepted,rejectedcontracts.status:draft,active,completed,cancelledinvoices.status:draft,sent,paid,overdue,cancelledsubscriptions.billing_cycle:monthly,yearly,weeklysubscriptions.status:active,cancelledclient_activities.type:note,call,meeting,emailproject_planning_sections.category:overview,problem,goal,audience,scope,design_system,color_palette,typography,assets,notesproject_revisions.status:pending,in_progress,completed,rejected
RLS policy matrix
Hedefte RLS yok; bu policy'ler service/repository authorization testlerine çevrilecek:
| Resource | Freelancer policy | Client policy | Hedef test |
|---|---|---|---|
profiles |
Own profile CRUD | Own profile read | Role-based route access and profile owner filter |
clients |
Own client CRUD | Own linked client read | Cross-owner UUID reject |
projects |
Own project CRUD | Linked client projects read | Client cannot read unrelated project |
tasks |
Own task CRUD | Public tasks of linked projects read | Client cannot see private task |
project_planning_sections |
Own section CRUD | Sections of linked projects read | Category/sort order query |
project_revisions |
Manage project revisions | Insert/view own revisions | Quota and project/client relation |
calendar_events |
Own event CRUD | None | Client role reject |
finance_transactions |
Own transaction CRUD | None | Client role reject |
daily_logs/journals |
Own journal CRUD | None | Client role reject |
chat_sessions/messages |
Own chat CRUD | None | Session owner filter |
document_embeddings |
Own embedding CRUD | None | First release archive/no runtime search |
app_settings |
Own settings CRUD | None | Secret never returned to client |
storage.objects/avatars |
Public select, owner write | None | Authorized upload and safe public avatar URL |
storage.objects/project-assets |
Owner/service-role path access | Portal read via project relation | File route validates owner/project relation |
Production audit sorguları
Bu sorgular Supabase SQL Editor veya read-only connection ile çalıştırılmalı. Secret değerleri loglanmamalı.
2026-07-16 durumu: workspace'te yalnızca .env.example bulunduğu için bu sorgular production üzerinde çalıştırılmamıştır. Kaynak schema envanteri 19 ürün/public tablo, 1 internal tablo ve 2 storage bucket olarak doğrulanmıştır; gerçek satır/dosya sayıları açık kalmıştır.
select 'profiles' as table_name, count(*) from public.profiles
union all select 'clients', count(*) from public.clients
union all select 'projects', count(*) from public.projects
union all select 'tasks', count(*) from public.tasks
union all select 'calendar_events', count(*) from public.calendar_events
union all select 'finance_transactions', count(*) from public.finance_transactions
union all select 'daily_logs', count(*) from public.daily_logs
union all select 'journals', count(*) from public.journals
union all select 'project_planning_sections', count(*) from public.project_planning_sections
union all select 'project_revisions', count(*) from public.project_revisions
union all select 'chat_sessions', count(*) from public.chat_sessions
union all select 'chat_messages', count(*) from public.chat_messages
union all select 'document_embeddings', count(*) from public.document_embeddings
union all select 'app_settings', count(*) from public.app_settings;
select role, count(*) from public.profiles group by role order by role;
select status, count(*) from public.clients group by status order by status;
select pipeline_stage, count(*) from public.clients group by pipeline_stage order by pipeline_stage;
select status, type, progress_type, count(*) from public.projects group by status, type, progress_type order by status, type, progress_type;
select status, priority, count(*) from public.tasks group by status, priority order by status, priority;
select type, count(*) from public.calendar_events group by type order by type;
select type, currency, payment_status, count(*) from public.finance_transactions group by type, currency, payment_status order by type, currency, payment_status;
select status, count(*) from public.proposals group by status order by status;
select status, count(*) from public.contracts group by status order by status;
select status, count(*) from public.invoices group by status order by status;
select billing_cycle, status, count(*) from public.subscriptions group by billing_cycle, status order by billing_cycle, status;
select category, count(*) from public.project_planning_sections group by category order by category;
select status, count(*) from public.project_revisions group by status order by status;
select count(*) filter (where api_key is not null and btrim(api_key) <> '') as settings_with_api_key from public.app_settings;
Storage audit:
select bucket_id, count(*) as file_count, coalesce(sum(metadata->>'size')::bigint, 0) as total_size
from storage.objects
where bucket_id in ('avatars', 'project-assets')
group by bucket_id
order by bucket_id;
select p.id, p.avatar_url
from public.profiles p
where p.avatar_url is not null and p.avatar_url <> '';
select p.id, p.cover_image_path
from public.projects p
where p.cover_image_path is not null and p.cover_image_path <> '';
Constraint/index/policy audit:
select conrelid::regclass as table_name, conname, contype, pg_get_constraintdef(oid) as definition
from pg_constraint
where connamespace in ('public'::regnamespace)
order by table_name::text, conname;
select schemaname, tablename, indexname, indexdef
from pg_indexes
where schemaname in ('public', 'neta_internal')
order by schemaname, tablename, indexname;
select schemaname, tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname in ('public', 'storage')
order by schemaname, tablename, policyname;
Merge kuralları
journals + daily_logs:
- Hedef tablo adı:
journal_entries. - Aynı user + aynı date/log_date günü için önce
daily_logskanonik kabul edilir. journals.contentdoluysajournal_entries.noteiçine conflict suffix veya related legacy note olarak eklenir.journals.ai_*alanları ilk release'te ayrıjournal_ai_metadataJSON alanına veya archive tablosuna taşınır; runtime AI analiz için şart değildir.
Task status:
completeddeğerleri import sırasındadoneolarak normalize edilir.- Tanınmayan status varsa import fail eder; silent fallback yok.
Planning section:
- Kaynak
categorykorunur. - UI'da görülen
typereferansı import alanı değildir. - Kaynak
sort_orderkorunur. order_indexhiçbir hedef query'de kullanılmaz.
Money:
amount numeric(12,2)vebudget_amount numeric(12,2)hedefteamount_minor integerveyabudget_amount_minor integer.- Currency her row'da ISO-like text olarak korunur; kullanıcı default currency migration sırasında sadece fallback.