{{{#!sql -- Delete tables if they exist DROP TABLE IF EXISTS NEED_APPROVAL CASCADE; DROP TABLE IF EXISTS READING_LIST_ITEMS CASCADE; DROP TABLE IF EXISTS HAS_GENRE CASCADE; DROP TABLE IF EXISTS COLLABORATION CASCADE; DROP TABLE IF EXISTS COMMENT CASCADE; DROP TABLE IF EXISTS LIKES CASCADE; DROP TABLE IF EXISTS AI_SUGGESTION CASCADE; DROP TABLE IF EXISTS NOTIFICATION CASCADE; DROP TABLE IF EXISTS READING_LIST CASCADE; DROP TABLE IF EXISTS CHAPTER CASCADE; DROP TABLE IF EXISTS STORY CASCADE; DROP TABLE IF EXISTS WRITER CASCADE; DROP TABLE IF EXISTS REGULAR_USER CASCADE; DROP TABLE IF EXISTS ADMINS CASCADE; DROP TABLE IF EXISTS GENRE CASCADE; DROP TABLE IF EXISTS USERS CASCADE; -- Tables CREATE TABLE USERS( user_id SERIAL PRIMARY KEY, username VARCHAR(255) NOT NULL UNIQUE, email VARCHAR(255) NOT NULL UNIQUE, user_name VARCHAR(100) NOT NULL, surname VARCHAR(100) NOT NULL, password VARCHAR(255) NOT NULL, user_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, user_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$') ); CREATE TABLE ADMINS( user_id INTEGER PRIMARY KEY, assigned_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE REGULAR_USER( user_id INTEGER PRIMARY KEY, joined_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE WRITER( user_id INTEGER PRIMARY KEY, bio TEXT, FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE STORY( story_id SERIAL PRIMARY KEY, title VARCHAR(200) NOT NULL DEFAULT '', mature_content BOOLEAN NOT NULL, short_description VARCHAR(500) NOT NULL, image VARCHAR(2048), story_content TEXT NOT NULL, status VARCHAR(50) NOT NULL DEFAULT 'draft', user_id INTEGER NOT NULL, story_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, story_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT status_values CHECK (status IN ('draft', 'published', 'archived')), FOREIGN KEY (user_id) REFERENCES WRITER(user_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE CHAPTER( chapter_id SERIAL PRIMARY KEY, chapter_number INTEGER NOT NULL, chapter_name VARCHAR(100) NOT NULL, title VARCHAR(200) NOT NULL, chapter_content TEXT NOT NULL, word_count INTEGER CHECK (word_count >= 0), rating DECIMAL(3,2) CHECK (rating >= 0 AND rating <= 5), published_at TIMESTAMPTZ NOT NULL, view_count INTEGER DEFAULT 0 CHECK (view_count >= 0), story_id INTEGER NOT NULL, chapter_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, chapter_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT unique_chapter_number UNIQUE(story_id, chapter_number), FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE GENRE( genre_id SERIAL PRIMARY KEY, genre_name VARCHAR(100) NOT NULL UNIQUE ); CREATE TABLE READING_LIST( list_id SERIAL PRIMARY KEY, list_name VARCHAR(100) NOT NULL, list_content TEXT, is_public BOOLEAN NOT NULL, user_id INTEGER NOT NULL, list_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, list_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE NOTIFICATION( notification_id SERIAL PRIMARY KEY, notification_content TEXT NOT NULL, content_type VARCHAR(50) NOT NULL, is_read BOOLEAN DEFAULT FALSE, link VARCHAR(500), user_id INTEGER NOT NULL, story_id INTEGER, notification_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE SET NULL ON UPDATE CASCADE ); CREATE TABLE AI_SUGGESTION( suggestion_id SERIAL PRIMARY KEY, original_text TEXT NOT NULL, suggested_text TEXT NOT NULL, suggestion_type VARCHAR(50) NOT NULL, accepted BOOLEAN NOT NULL DEFAULT FALSE, suggestion_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, applied_at TIMESTAMPTZ, story_id INTEGER NOT NULL, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE LIKES( user_id INTEGER, story_id INTEGER, liked_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT like_pk PRIMARY KEY(user_id, story_id), FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE COMMENT( comment_id SERIAL PRIMARY KEY, comment_content TEXT NOT NULL, user_id INTEGER NOT NULL, story_id INTEGER NOT NULL, comment_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, comment_updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE COLLABORATION( user_id INTEGER, story_id INTEGER, role VARCHAR(50) NOT NULL, permission_level INTEGER, collab_created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT collaboration_pk PRIMARY KEY(user_id, story_id), FOREIGN KEY (user_id) REFERENCES USERS(user_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE HAS_GENRE( story_id INTEGER, genre_id INTEGER, CONSTRAINT has_genre_pk PRIMARY KEY(story_id, genre_id), FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (genre_id) REFERENCES GENRE(genre_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE READING_LIST_ITEMS( list_id INTEGER, story_id INTEGER, added_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT reading_list_items_pk PRIMARY KEY(list_id, story_id), FOREIGN KEY (list_id) REFERENCES READING_LIST(list_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE NEED_APPROVAL( suggestion_id INTEGER, story_id INTEGER, chapter_id INTEGER, CONSTRAINT need_approval_pk PRIMARY KEY(suggestion_id, story_id, chapter_id), FOREIGN KEY (suggestion_id) REFERENCES AI_SUGGESTION(suggestion_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (story_id) REFERENCES STORY(story_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (chapter_id) REFERENCES CHAPTER(chapter_id) ON DELETE CASCADE ON UPDATE CASCADE ); }}}