# 鏈新聞 DB Schema & 需求確認 ## DB Schema ```Go= package main import "time" type User struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` DeletedAt time.Time `gorm:"null"` Username string `gorm:"type:varchar(255);not null"` // 暱稱 Password string `gorm:"type:varchar(255);not null"` // 密碼 Email string `gorm:"type:varchar(255);not null"` // 信箱, 需要是unique Url string `gorm:"type:varchar(255);null"` // 用戶個人連結 Avatar string `gorm:"type:varchar(255);null"` // 頭像路徑, 空的話為預設 Status uint8 `gorm:"type:TINYINT;UNSIGNED"` // 用戶身分, 黑名單/編輯資格 } type UserFollowing struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` UserId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 訂閱者 PostId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 正在追蹤的post id IsFollow bool `gorm:"type:TINYINT;not null;UNSIGNED"` // 是否追蹤, 取消追蹤 } type UserSubscribe struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` UserId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 訂閱者 SubscribeId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 正在訂閱的user id IsSubscribe bool `gorm:"type:TINYINT;not null;UNSIGNED"` // 是否訂閱, 取消訂閱 } type AuthorSubscribeCount struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` AuthorUid uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 被訂閱的作者user id Count uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 訂閱數 } type UserLike struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` UserId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 按讚者 PostId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 按讚的post id IsLike bool `gorm:"type:TINYINT;not null;UNSIGNED"` // 是否按讚, 或取消按讚 } type Post struct { ID uint64 `gorm:"primary_key;auto_increment:true"` Editor uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 文章編輯者 Title string `gorm:"type:varchar(255);not null"` // 標題 Author uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 作者 Context string `gorm:"type:mediumtext"` // 內文, html格式 Like uint64 `gorm:"type:int(11);default:0;UNSIGNED"` // 按讚數 Comment uint64 `gorm:"type:int(11);default:0;UNSIGNED"` // 留言數 View uint64 `gorm:"type:int(11);default:0;UNSIGNED"` // 觀看人數 Status uint8 `gorm:"type:TINYINT;not null;UNSIGNED"` // 狀態, publish, remove, history PostParent uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 如果是歷史紀錄, 指向最開始建立的 post id SEOAbstract string `gorm:"type:mediumtext"` // SEO 摘要 SEOKeyword string `gorm:"type:varchar(255);null"` // SEO 關鍵字 SEOCode string `gorm:"type:varchar(255);null"` // SEO 代碼 Banner uint64 `gorm:"type:int(11);null;UNSIGNED"` // 文章封面圖 Media Id CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` PublishAt time.Time `gorm:"null"` // 發布時間 } type PostTag struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` PostId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 文章Post id TagId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 關聯tag id } type Tag struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` Name string `gorm:"type:varchar(255);not null"` } type Category struct { ID uint64 `gorm:"primary_key;auto_increment:true"` Name string `gorm:"type:varchar(255);not null"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` Order uint8 `gorm:"type:TINYINT;not null;UNSIGNED"` // 分類從左至右順序 } type TagCategory struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` TagId uint64 `gorm:"type:int(11);not null;UNSIGNED"` CategoryId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // tag被歸類的分類 Order uint8 `gorm:"type:TINYINT;not null;UNSIGNED"` // 下拉選單順序 } type PostComment struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` CommentId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // comment的id PostId uint64 `gorm:"type:int(11);not null;UNSIGNED"` // 被留言的post id } type Comment struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` CommentBy uint64 `gorm:"type:int(11);null;UNSIGNED"` // 留下評論的user Context string `gorm:"type:varchar(50);not null"` // 留言內容, 字數限制50, 不可為空 IsBlock bool `gorm:"type:TINYINT;not null;UNSIGNED"` // 是否為垃圾訊息 Like uint64 `gorm:"type:int(11);default:0;UNSIGNED"` // 按讚數 Dislike uint64 `gorm:"type:int(11);default:0;UNSIGNED"` // 倒讚數 } type CommentReport struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` CommentId uint64 `gorm:"type:int(11);null;UNSIGNED"` // 被檢舉留言 ReportBy uint64 `gorm:"type:int(11);null;UNSIGNED"` // 檢舉人 Message string `gorm:"type:varchar(255);not null"` // 檢舉內容 ReviewBy uint64 `gorm:"type:int(11);null;UNSIGNED"` // 審核者 ReviewedAt time.Time `gorm:"null"` // 審核時間 Result uint8 `gorm:"type:TINYINT;not null;UNSIGNED"` // 審核結果, 有效, 無效, 待審 } type Announcement struct { ID uint64 `gorm:"primary_key;auto_increment:true"` Banner string `gorm:"type:varchar(255);null"` // 公告圖片url Url string `gorm:"type:varchar(255);null"` // 點擊跳轉超連結 Status bool `gorm:"type:TINYINT;not null;UNSIGNED"` // 上下架 Type uint8 `gorm:"type:TINYINT;not null;UNSIGNED"` // popup或是首頁 Opens uint64 `gorm:"type:int(11);null;UNSIGNED"` // popup彈出次數 CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` } type Info struct { ID uint64 `gorm:"primary_key;auto_increment:true"` CreatedAt time.Time `gorm:"null"` UpdatedAt time.Time `gorm:"null"` Contact string `gorm:"type:varchar(255);null"` // 聯絡我們, 連結 JoinUs string `gorm:"type:varchar(255);null"` // 加入我們, 連結 AboutUs string `gorm:"type:varchar(255);null"` // 簡介 FaceBook string `gorm:"type:varchar(255);null"` // 連結 Instagram string `gorm:"type:varchar(255);null"` // 連結 Telegram string `gorm:"type:varchar(255);null"` // 連結 Youtube string `gorm:"type:varchar(255);null"` // 連結 Twitter string `gorm:"type:varchar(255);null"` // 連結 Copyright string `gorm:"type:varchar(255);null"` // copyright } ``` ## 確認需求: - 檢舉的留言,畫面需要撈出,然後顯示 block 的區塊嗎?還是撈出時直接過濾掉不回傳 - popup 的公告,從 wordpress 看有看到 oppens 次數(推測是彈窗顯示次數),這個有需要紀錄嗎? →需要紀錄點擊次數 - 用戶跟文章是否可以刪除 →留言不能刪除、文章不能刪除,只有"移至回收桶"功能 - 用戶是否可以用Token打Api到我們server(activation key)   →不能,但要有openapi(Bestla APP&ACE Global有接鏈新聞) - 單則評論的限制字數為多少? →50字元 - 需要紀錄匿名留言者的名稱嗎(commentator)?   →登入才能留言 - NavBar 只會有兩層嗎? - 目前看起來 NavBar 標題都為 tag name,會有需要自訂標題嗎? - 目前看起來 NavBar 點擊後,都是使用該 tag name 去做 filter,會有多 tag filter 的需求嗎? →我研究一下 - 後台文章上架功能中,分類選擇與標籤選擇的差異是? →![](https://i.imgur.com/MaOU2bO.png) - 後台文章上架功能中,可見度的私密選項定義是什麼?特定作者可看到?特定 → 後續僅有公開跟非公開,非公開為只有URL才可以瀏覽 - 補充一下: 後台使用者(即作者)發文章時,可以設定審核/免審核文章權限,審核開啟時,發文者需進行審核後在可上架。 ## 分類(category) & 標籤(tag) 依造已知需求設計 - 分類只會有 1 層 - 分類下的子分類皆為 tag ex: ![](https://i.imgur.com/MaOU2bO.png) ``` 新手必讀(category) ├── 新手指南(tag) └── 加密貨幣詐騙(tag) ``` 所以點選 nav bar 下 `新手必讀` 下的 `新手指南`,實際上就只是 filter by tag