feat: enhance roadmap with detailed tasks and acceptance criteria; update database documentation and query management
This commit is contained in:
+7
-1
@@ -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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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 },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
@@ -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
|
||||||
|
```
|
||||||
|
|
||||||
@@ -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. |
|
||||||
|
|
||||||
@@ -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`.
|
||||||
|
|
||||||
Vendored
+1
-1
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
Reference in New Issue
Block a user