feat: enhance roadmap with detailed tasks and acceptance criteria; update database documentation and query management

This commit is contained in:
Poyraz Avsever
2026-06-01 11:43:37 +03:00
parent 083997e6bc
commit 53a225594a
15 changed files with 169 additions and 46 deletions
+7 -1
View File
@@ -410,10 +410,13 @@ Amac: Mevcut prototipi build edilebilir ve gelistirilebilir hale getirmek.
Isler: Isler:
- Build hatalarini gidermek. - Build hatalarini gidermek.
- `Cognis`, `MindSpace` ve yeni urun ismi kararini netlestirmek. - Urun adini netlestirmek: `Cognis`.
- Encoding bozukluklarini temizlemek. - Encoding bozukluklarini temizlemek.
- Mock veri kullanan ekranlari isaretlemek. - Mock veri kullanan ekranlari isaretlemek.
- `user_settings` yerine `app_settings` semasini netlestirmek. - `user_settings` yerine `app_settings` semasini netlestirmek.
- Supabase SQL dosyalarini sira, dokumantasyon ve calistirma kaydi olan bir sisteme oturtmak.
- Mevcut `supabase/schema.sql` dosyasini ilk database baseline olarak kaydetmek.
- Her yeni SQL ekinde ilgili dokumani ve query log kaydini zorunlu hale getirmek.
- MVP disi ekranlari sidebar'dan gecici olarak kaldirmak veya "coming later" durumuna almak. - MVP disi ekranlari sidebar'dan gecici olarak kaldirmak veya "coming later" durumuna almak.
Kabul kriteri: Kabul kriteri:
@@ -421,6 +424,9 @@ Kabul kriteri:
- `npm run build` basarili. - `npm run build` basarili.
- Ana layout, auth ve dashboard sorunsuz acilir. - Ana layout, auth ve dashboard sorunsuz acilir.
- MVP kapsamindaki moduller net gorunur. - MVP kapsamindaki moduller net gorunur.
- Database query sirasi `docs/database/query-order.md` icinde kayitlidir.
- Calistirilan SQL dosyalari `docs/database/query-log.md` icinde takip edilir.
- Ilk baseline olan `supabase/schema.sql` icin aciklayici dokuman vardir.
--- ---
+12 -9
View File
@@ -145,12 +145,15 @@ export default function AIChatPage() {
} else return; } else return;
} }
const resolvedSessionId = sessionId;
if (!resolvedSessionId) return;
setIsLoading(true); setIsLoading(true);
// 1. Optimistic Update: Add User Message locally // 1. Optimistic Update: Add User Message locally
const optimisticUserMsg: ChatMessage = { const optimisticUserMsg: ChatMessage = {
id: uuidv4(), id: uuidv4(),
session_id: sessionId, session_id: resolvedSessionId,
role: "user", role: "user",
content: userMessageContent, content: userMessageContent,
created_at: new Date().toISOString() created_at: new Date().toISOString()
@@ -160,7 +163,7 @@ export default function AIChatPage() {
// 2. Save User Message to Supabase // 2. Save User Message to Supabase
await supabase.from("chat_messages").insert({ await supabase.from("chat_messages").insert({
id: optimisticUserMsg.id, id: optimisticUserMsg.id,
session_id: sessionId, session_id: resolvedSessionId,
role: "user", role: "user",
content: userMessageContent content: userMessageContent
}); });
@@ -189,7 +192,7 @@ export default function AIChatPage() {
// 5. Optimistic Update: Add Assistant Message locally // 5. Optimistic Update: Add Assistant Message locally
const assistantMsg: ChatMessage = { const assistantMsg: ChatMessage = {
id: uuidv4(), id: uuidv4(),
session_id: sessionId, session_id: resolvedSessionId,
role: "assistant", role: "assistant",
content: data.reply || "Cevap üretilemedi.", content: data.reply || "Cevap üretilemedi.",
created_at: new Date().toISOString() created_at: new Date().toISOString()
@@ -199,24 +202,24 @@ export default function AIChatPage() {
// 6. Save Assistant Message to Supabase // 6. Save Assistant Message to Supabase
await supabase.from("chat_messages").insert({ await supabase.from("chat_messages").insert({
id: assistantMsg.id, id: assistantMsg.id,
session_id: sessionId, session_id: resolvedSessionId,
role: "assistant", role: "assistant",
content: assistantMsg.content content: assistantMsg.content
}); });
// 7. Update session title if it was default // 7. Update session title if it was default
const currentSession = sessions.find(s => s.id === sessionId); const currentSession = sessions.find(s => s.id === resolvedSessionId);
if (currentSession?.title === "Yeni Sohbet") { if (currentSession?.title === "Yeni Sohbet") {
const newTitle = userMessageContent.slice(0, 40); const newTitle = userMessageContent.slice(0, 40);
await supabase.from("chat_sessions").update({ title: newTitle }).eq("id", sessionId); await supabase.from("chat_sessions").update({ title: newTitle }).eq("id", resolvedSessionId);
setSessions(prev => prev.map(s => s.id === sessionId ? { ...s, title: newTitle } : s)); setSessions(prev => prev.map(s => s.id === resolvedSessionId ? { ...s, title: newTitle } : s));
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
const errorMsg: ChatMessage = { const errorMsg: ChatMessage = {
id: uuidv4(), id: uuidv4(),
session_id: sessionId, session_id: resolvedSessionId,
role: "assistant", role: "assistant",
content: "Hata oluştu. Lütfen Ayarlar sayfasından API anahtarınızı kontrol edin.", content: "Hata oluştu. Lütfen Ayarlar sayfasından API anahtarınızı kontrol edin.",
created_at: new Date().toISOString() created_at: new Date().toISOString()
@@ -224,7 +227,7 @@ export default function AIChatPage() {
setMessages(prev => [...prev, errorMsg]); setMessages(prev => [...prev, errorMsg]);
await supabase.from("chat_messages").insert({ await supabase.from("chat_messages").insert({
id: errorMsg.id, id: errorMsg.id,
session_id: sessionId, session_id: resolvedSessionId,
role: "assistant", role: "assistant",
content: errorMsg.content content: errorMsg.content
}); });
+1 -1
View File
@@ -2,7 +2,7 @@
import { useState } from "react"; import { useState } from "react";
import { import {
Plus, Search, User, Mail, Phone, Globe, Plus, Search, User, Users, Mail, Phone, Globe,
MoreHorizontal, MessageSquare, Briefcase, MoreHorizontal, MessageSquare, Briefcase,
TrendingUp, Star, Clock, X, ChevronRight, TrendingUp, Star, Clock, X, ChevronRight,
ArrowUpRight, DollarSign, Brain, Shield, ArrowUpRight, DollarSign, Brain, Shield,
+1 -1
View File
@@ -6,7 +6,7 @@ import {
CreditCard, ArrowUpRight, ArrowDownRight, MoreHorizontal, CreditCard, ArrowUpRight, ArrowDownRight, MoreHorizontal,
Calendar, FileText, Download, PieChart as PieChartIcon, Calendar, FileText, Download, PieChart as PieChartIcon,
Wallet, Brain, ArrowRight, X, Check, Activity, Wallet, Brain, ArrowRight, X, Check, Activity,
Briefcase, Landmark, Receipt, Percent, Target Briefcase, Landmark, Receipt, Percent, Target, Filter
} from "lucide-react"; } from "lucide-react";
import { import {
Area, AreaChart, Bar, BarChart, CartesianGrid, Area, AreaChart, Bar, BarChart, CartesianGrid,
+1 -1
View File
@@ -5,7 +5,7 @@ import {
Plus, Search, Calendar, Clock, Brain, MessageSquare, Plus, Search, Calendar, Clock, Brain, MessageSquare,
Smile, Frown, Meh, Star, MoreHorizontal, X, Smile, Frown, Meh, Star, MoreHorizontal, X,
Zap, Save, Trash2, Edit3, Image as ImageIcon, Link as LinkIcon, Zap, Save, Trash2, Edit3, Image as ImageIcon, Link as LinkIcon,
ChevronLeft, ChevronRight, Activity, Filter, AlignLeft, Hash ChevronLeft, ChevronRight, Activity, Filter, AlignLeft, Hash, ArrowRight
} from "lucide-react"; } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
+1 -1
View File
@@ -5,7 +5,7 @@ import {
Play, Pause, Square, Plus, Search, Clock, Play, Pause, Square, Plus, Search, Clock,
BarChart3, Calendar, MoreHorizontal, X, BarChart3, Calendar, MoreHorizontal, X,
CheckCircle2, AlertCircle, Brain, Zap, CheckCircle2, AlertCircle, Brain, Zap,
TrendingUp, Activity, Briefcase, User TrendingUp, Activity, Briefcase, User, ArrowRight
} from "lucide-react"; } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import { import {
+1 -2
View File
@@ -230,7 +230,7 @@ function SidebarPanel({
className="flex w-full items-center justify-between gap-2 rounded-md p-2 transition-all hover:bg-white/5 outline-none" className="flex w-full items-center justify-between gap-2 rounded-md p-2 transition-all hover:bg-white/5 outline-none"
> >
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
<Avatar user={user} size="sm" /> <Avatar user={user} />
<div className="min-w-0 text-left"> <div className="min-w-0 text-left">
<div className="truncate text-sm font-medium text-foreground leading-tight"> <div className="truncate text-sm font-medium text-foreground leading-tight">
{user.displayName} {user.displayName}
@@ -341,4 +341,3 @@ function AmbientBackdrop() {
</> </>
); );
} }
+10 -29
View File
@@ -1,25 +1,20 @@
import { import {
Activity,
BarChart3, BarChart3,
BookOpenText, BookOpenText,
Building2,
Calendar, Calendar,
CheckSquare2, CheckSquare2,
FileText,
FolderKanban, FolderKanban,
MessageCircleHeart, MessageCircleHeart,
Sparkles, Sparkles,
Target,
Users,
Wallet, Wallet,
Building2,
Tags,
} from "lucide-react"; } from "lucide-react";
export type SidebarNavItem = { export type SidebarNavItem = {
title: string; title: string;
href?: string; href?: string;
icon?: any; icon?: any;
items?: SidebarNavItem[]; // For nested (accordion) links later items?: SidebarNavItem[];
}; };
export type SidebarNavGroup = { export type SidebarNavGroup = {
@@ -29,7 +24,7 @@ export type SidebarNavGroup = {
export const sidebarData: SidebarNavGroup[] = [ export const sidebarData: SidebarNavGroup[] = [
{ {
title: "GENEL BAKIŞ", title: "GENEL BAKIS",
items: [ items: [
{ title: "Dashboard", href: "/", icon: Sparkles }, { title: "Dashboard", href: "/", icon: Sparkles },
{ title: "Takvim", href: "/calendar", icon: Calendar }, { title: "Takvim", href: "/calendar", icon: Calendar },
@@ -37,34 +32,20 @@ export const sidebarData: SidebarNavGroup[] = [
], ],
}, },
{ {
title: "YÖNETİM", title: "OPERASYON",
items: [ items: [
{ title: "Görevler", href: "/tasks", icon: CheckSquare2 }, { title: "Musteriler", href: "/clients", icon: Building2 },
{ title: "Projeler", href: "/projects", icon: FolderKanban }, { title: "Projeler", href: "/projects", icon: FolderKanban },
{ title: "Dökümanlar", href: "/documents", icon: FileText }, { title: "Gorevler", href: "/tasks", icon: CheckSquare2 },
{ title: "Finans", href: "/finance", icon: Wallet }, { title: "Finans", href: "/finance", icon: Wallet },
], ],
}, },
{ {
title: "KİŞİSEL", title: "KISISEL",
items: [ items: [{ title: "Gunluk", href: "/journal", icon: BookOpenText }],
{ title: "Günlük", href: "/journal", icon: BookOpenText },
{ title: "Alışkanlıklar", href: "/habits", icon: Activity },
{ title: "Hedefler", href: "/goals", icon: Target },
],
}, },
{ {
title: "FREELANCE", title: "AI ASISTAN",
items: [ items: [{ title: "Sohbet", href: "/chat", icon: MessageCircleHeart }],
{ title: "Müşteriler (CRM)", href: "/freelance/clients", icon: Building2 },
{ title: "Teklifler & Sözleşmeler", href: "/freelance/proposals", icon: Tags },
{ title: "Zaman Takibi", href: "/freelance/time-tracking", icon: Activity },
],
},
{
title: "AI ASİSTAN",
items: [
{ title: "Sohbet", href: "/chat", icon: MessageCircleHeart },
],
}, },
]; ];
+51
View File
@@ -0,0 +1,51 @@
# 0001 Initial Schema
SQL file: `supabase/schema.sql`
## Purpose
This is the first registered database query file for the project. It represents the schema that existed before the Freelancer OS MVP planning work started.
## What It Creates
- `journals`
- `tasks`
- `chat_sessions`
- `chat_messages`
- `profiles`
- Row Level Security policies for the tables above
- `handle_new_user()` trigger function for profile creation
- `on_auth_user_created` trigger
- `avatars` storage bucket and related storage policies
## Current Product Fit
This schema supports the earlier MindSpace/Cognis prototype:
- mood/energy journals
- basic tasks
- chat history
- user profile storage
- avatar uploads
It does not yet fully match the Freelancer OS MVP model.
## Known Gaps For MVP
The Freelancer OS MVP still needs new schema additions for:
- `clients`
- `projects`
- `calendar_events`
- `finance_transactions`
- `daily_logs`
- `app_settings`
The existing `journals` table can either be migrated into `daily_logs` or kept as a legacy table until the UI is moved to the new model.
## Execution Notes
This file should be treated as the first baseline. If it has already been run in a Supabase project, do not rerun it blindly because some `create table` and `create policy` statements are not idempotent.
Future changes should be added as ordered migration files rather than editing this baseline after execution.
+35
View File
@@ -0,0 +1,35 @@
# Database Change Process
This directory records every database change that should be run against Supabase/PostgreSQL.
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.
## Rules
1. Every SQL change must have a stable order number.
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
- `supabase/schema.sql`: Initial legacy schema. It creates the current auth/profile, journal, task, chat, and avatar storage structure.
- `docs/database/0001-initial-schema.md`: Explanation for the initial schema.
- `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
```
+10
View File
@@ -0,0 +1,10 @@
# Database Query Log
This file records SQL files that were executed against a database environment.
Do not mark a query as executed unless it was actually run.
| Date | Environment | Order | SQL file | Runner | Result | Notes |
| --- | --- | --- | --- | --- | --- | --- |
| Not recorded | Unknown existing environment | 0001 | `supabase/schema.sql` | Unknown | Assumed existing baseline | File existed before this query log was introduced. Confirm manually before rerunning. |
+16
View File
@@ -0,0 +1,16 @@
# Database Query Order
This file is the canonical order of SQL files for database setup and migration.
| Order | SQL file | Documentation | Status |
| --- | --- | --- | --- |
| 0001 | `supabase/schema.sql` | `docs/database/0001-initial-schema.md` | Baseline registered |
## How To Add The Next Query
1. Create a new SQL file under `supabase/migrations/`.
2. Use the next order number.
3. Add a documentation file under `docs/database/`.
4. Register both files in this table.
5. After running the SQL, add an entry to `query-log.md`.
+1 -1
View File
@@ -1,6 +1,6 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts"; import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+21
View File
@@ -0,0 +1,21 @@
# Supabase Directory
This directory stores SQL files for the project's Supabase/PostgreSQL database.
## 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/
```
Do not overwrite already executed SQL without also creating a new ordered migration and documenting why.
+1
View File
@@ -0,0 +1 @@