- Backend: Spring Boot 3 + WebFlux, JWT auth, Oracle ADB wallet, 8 controllers/services/repositories (Auth~Tag), DTOs, exception handling - Frontend: Next.js 15, TypeScript, Tailwind CSS, AuthContext, 7 pages (dashboard, knowledge, chat, study, todos, habits, login) - DB: V1 migration with 12 tables including VECTOR(1024) + HNSW index - Ops: PM2 ecosystem config, deploy.sh, start-backend.sh - CLAUDE.md: DB credentials replaced with env var references Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
157 lines
5.6 KiB
MySQL
157 lines
5.6 KiB
MySQL
-- ============================================
|
|
-- SUNDOL Database Schema - Oracle 23ai
|
|
-- ============================================
|
|
|
|
-- USERS
|
|
CREATE TABLE users (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
email VARCHAR2(320) NOT NULL UNIQUE,
|
|
display_name VARCHAR2(255),
|
|
avatar_url VARCHAR2(1000),
|
|
google_sub VARCHAR2(255) UNIQUE,
|
|
refresh_token VARCHAR2(1000),
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
-- KNOWLEDGE_ITEMS
|
|
CREATE TABLE knowledge_items (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
user_id RAW(16) NOT NULL REFERENCES users(id),
|
|
type VARCHAR2(20) NOT NULL,
|
|
title VARCHAR2(500),
|
|
source_url VARCHAR2(2000),
|
|
raw_text CLOB,
|
|
status VARCHAR2(20) DEFAULT 'PENDING' NOT NULL,
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_ki_user_id ON knowledge_items(user_id);
|
|
CREATE INDEX idx_ki_status ON knowledge_items(status);
|
|
|
|
-- KNOWLEDGE_CHUNKS
|
|
CREATE TABLE knowledge_chunks (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
knowledge_item_id RAW(16) NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
|
|
chunk_index NUMBER(10) NOT NULL,
|
|
content CLOB NOT NULL,
|
|
embedding VECTOR(1024, FLOAT32),
|
|
token_count NUMBER(10),
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_kc_item_id ON knowledge_chunks(knowledge_item_id);
|
|
|
|
-- VECTOR index for semantic search
|
|
CREATE VECTOR INDEX idx_kc_embedding ON knowledge_chunks(embedding)
|
|
ORGANIZATION NEIGHBOR PARTITIONS
|
|
DISTANCE COSINE
|
|
WITH TARGET ACCURACY 95;
|
|
|
|
-- TAGS
|
|
CREATE TABLE tags (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
user_id RAW(16) NOT NULL REFERENCES users(id),
|
|
name VARCHAR2(100) NOT NULL,
|
|
color VARCHAR2(7) DEFAULT '#3b82f6',
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_tags_user_name ON tags(user_id, name);
|
|
|
|
-- KNOWLEDGE_ITEM_TAGS (many-to-many)
|
|
CREATE TABLE knowledge_item_tags (
|
|
knowledge_item_id RAW(16) NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
|
|
tag_id RAW(16) NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (knowledge_item_id, tag_id)
|
|
);
|
|
|
|
-- CHAT_SESSIONS
|
|
CREATE TABLE chat_sessions (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
user_id RAW(16) NOT NULL REFERENCES users(id),
|
|
title VARCHAR2(500) DEFAULT 'New Chat',
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_cs_user_id ON chat_sessions(user_id);
|
|
|
|
-- CHAT_MESSAGES
|
|
CREATE TABLE chat_messages (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
session_id RAW(16) NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE,
|
|
role VARCHAR2(20) NOT NULL,
|
|
content CLOB NOT NULL,
|
|
source_chunks CLOB,
|
|
tokens_used NUMBER(10),
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_cm_session_id ON chat_messages(session_id);
|
|
|
|
-- TODOS
|
|
CREATE TABLE todos (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
user_id RAW(16) NOT NULL REFERENCES users(id),
|
|
parent_id RAW(16) REFERENCES todos(id) ON DELETE CASCADE,
|
|
title VARCHAR2(500) NOT NULL,
|
|
description CLOB,
|
|
status VARCHAR2(20) DEFAULT 'PENDING' NOT NULL,
|
|
priority VARCHAR2(10) DEFAULT 'MEDIUM' NOT NULL,
|
|
due_date DATE,
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_todos_user_id ON todos(user_id);
|
|
CREATE INDEX idx_todos_parent_id ON todos(parent_id);
|
|
|
|
-- HABITS
|
|
CREATE TABLE habits (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
user_id RAW(16) NOT NULL REFERENCES users(id),
|
|
name VARCHAR2(200) NOT NULL,
|
|
description VARCHAR2(1000),
|
|
habit_type VARCHAR2(10) DEFAULT 'BUILD' NOT NULL,
|
|
target_days VARCHAR2(50) DEFAULT 'DAILY',
|
|
color VARCHAR2(7) DEFAULT '#22c55e',
|
|
streak_current NUMBER(10) DEFAULT 0,
|
|
streak_best NUMBER(10) DEFAULT 0,
|
|
is_active NUMBER(1) DEFAULT 1,
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_habits_user_id ON habits(user_id);
|
|
|
|
-- HABIT_LOGS
|
|
CREATE TABLE habit_logs (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
habit_id RAW(16) NOT NULL REFERENCES habits(id) ON DELETE CASCADE,
|
|
log_date DATE NOT NULL,
|
|
checked_in NUMBER(1) DEFAULT 1,
|
|
note VARCHAR2(500),
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_hl_habit_date ON habit_logs(habit_id, log_date);
|
|
|
|
-- STUDY_CARDS
|
|
CREATE TABLE study_cards (
|
|
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
|
|
user_id RAW(16) NOT NULL REFERENCES users(id),
|
|
knowledge_item_id RAW(16) REFERENCES knowledge_items(id) ON DELETE SET NULL,
|
|
front CLOB NOT NULL,
|
|
back CLOB NOT NULL,
|
|
ease_factor NUMBER(4,2) DEFAULT 2.50,
|
|
interval_days NUMBER(10) DEFAULT 0,
|
|
repetitions NUMBER(10) DEFAULT 0,
|
|
next_review_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_sc_user_review ON study_cards(user_id, next_review_at);
|