# 鏈新聞 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 的需求嗎?
→我研究一下
- 後台文章上架功能中,分類選擇與標籤選擇的差異是?
→
- 後台文章上架功能中,可見度的私密選項定義是什麼?特定作者可看到?特定
→ 後續僅有公開跟非公開,非公開為只有URL才可以瀏覽
- 補充一下:
後台使用者(即作者)發文章時,可以設定審核/免審核文章權限,審核開啟時,發文者需進行審核後在可上架。
## 分類(category) & 標籤(tag)
依造已知需求設計
- 分類只會有 1 層
- 分類下的子分類皆為 tag
ex:

```
新手必讀(category)
├── 新手指南(tag)
└── 加密貨幣詐騙(tag)
```
所以點選 nav bar 下 `新手必讀` 下的 `新手指南`,實際上就只是 filter by tag