---
# System prepended metadata

title: 鏈新聞 DB Schema & 需求確認

---

# 鏈新聞 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