## GDSC課程評價網站小組
### 期末專案發表

----
## 我們做了什麼(ㄧ)
#### 政大課程評價網
主要的功能包含
1. 瀏覽課程評價
2. 上傳課程評價
----
<!-- ## 我們做了什麼(二)
與一般課程評價網站不同的是多了以下幾個功能:
1. 留言板
2. 貼文版
3. 收藏課程
4. 課程尋找過濾器(提供親切的圖形介面供使用者過濾出自己想找的課程)
---- -->
## 為什麼想開發課程評價網站
1. 降低同學發修課評價的成本,不需要再到論壇上發文,而是可直接填表上傳
2. 集合所有政大課程到一個網站,找課程資料不需要再到處google
----
### 專案成品
https://course-nccu.com

----
### 掃我填評價

---
#### 目錄
1. #### 專案規劃
2. #### 資料庫規劃
2-a. 課程
2-b. 使用者帳號
2-c. 課程評價
3. #### 前後端開發
3-a. MVC開發架構
3-b. 前端頁面開發
3-c. 後端api
3-d. 網站上線
4. #### 未來規劃
---
## 專案規劃
----
## 規劃
我們一開始有很多想法
樹莓派、自走車、
咖啡豆辨識機、
車輛違規辨識、
政大二手書交易網
----
### 最後我們決定走自己最擅長的領域-前後端App

----
### 我們開始找網頁技術能夠解決的問題
我們在政大的課程查詢網站上找到了這份excel檔,

我們覺得要做出政大的課程評價網只需要這個就夠了
(true)
----
所以我們簡單規劃了一下這個專案的資料有哪幾種
1. 課程 <- 由政大提供
2. 使用者 <- 自己做登入登出系統
3. 使用者對課程進行的評價 <- 自己做評價上傳系統
確認是做的出來的之後
就開始做課程評價系統了
---
# 規劃資料庫
---
## 規劃資料庫(1)-課程

----
### 處理課程資料
我們觀察這份政大課程查詢下載的excel檔

我們發現科目代碼得編碼是有規則的
從前3碼可以看出這堂課是哪一大分類的
中間3碼則表是子分類
----
科目代碼編碼規則整理
| 課程類別 | 前3碼 |
| ---- | ----- |
| 整開 | 000 |
| 中文通識 | 031 |
| 英文通識 | 032 |
| 書院 | 045 |
| 資訊 | 046 |
| 人文 | 041 |
| 社會 | 042 |
| 自然 | 043 |
| 跨領域 | 044 / 090 / 993 |
| 體育 | 002 |
| 備註: | 子類別看中間3碼 |
----
### 資料庫中一堂課的識別代碼製造方式:
一堂課的識別代碼(Primary Key)=
學年(3碼)+ 學期(1碼) + 科目代碼(9碼)
共13碼
----
### 以 110 上學期的微積分為例
他的識別碼是
1101000713001
拆解如下:
| 學年(3碼) | 學期(1碼) | 科目代碼(9碼)
| ---- | ----- | ----- |
| 110 | 1 | 000713001 |
----
### 處理課程資料
我們將excel檔轉成csv檔,
並按照科目代碼幫課程進行分類後,
直接import到我們的資料庫,
然後對每堂課加上type跟subtype
還有一些必要的attribute,
就這樣把課程資料搞定了
----
## 課程資料結構
``` javascript [2|3|4|5|6-7|8-9|10-11|12-13|14-19|20|21-24|25-26|27-28]
const courseSchema = mongoose.Schema({
id: { type: String ,unique:true //primary key()
semester: String //學期(共四碼:)e.g. "1101"代表110學年上學期 前三碼代表學年 第四碼代表上或下學期
code: String //由政大編碼的九碼課程id (取自課程查詢下載的excel檔)
point: Number, //學分 (取自課程查詢下載的excel檔)
courseNameZH_TW: String //課程名稱(中文) (取自課程查詢下載的excel檔)
courseName: String //課程名稱 (取自課程查詢下載的excel檔)
instructorZH_TW: String //教師名稱 (取自課程查詢下載的excel檔)
instructor: String //教師名稱 (取自課程查詢下載的excel檔)
departmentZH_TW: String //開課單位 (取自課程查詢下載的excel檔)
department: String //開課單位 (取自課程查詢下載的excel檔)
sessionZH_TW: String //上課時段 (取自課程查詢下載的excel檔)
session: String ////上課時段 (取自課程查詢下載的excel檔)
classroom: String //上課教室 (取自課程查詢下載的excel檔)
typeOfCredit: String // (取自課程查詢下載的excel檔)
lectureLanguage: String //教學使用語言 (取自課程查詢下載的excel檔)
isCoreGeneral: String //是否為核心通識 (取自課程查詢下載的excel檔)
information: String //詳細資訊 (取自課程查詢下載的excel檔)
note: String //課程註解 (取自課程查詢下載的excel檔)
comments: [String], default: [] //此課程的評價陣列
avg_rate:Number, //此課程的平均評價
avg_sweet:Number, //此課程的平均甜度
avg_loading:Number, //此課程的平均涼度
avg_gain:Number, //此課程的平均收穫
num_of_feedback:Number, //此課程的評價數
num_of_like:Number, //此課程的評價數
type: String //此課程的種類:有以下幾種["DEPARTMENT","GENERAL","INTEGRATED","PE","ND"]
subType: String //此課程的子種類 列舉如下
// type為"DEPARTMENT" 的有以下幾種subtype:["CHINESE","COMPUTER_SCIENCE"...]
// type為"GENERAL" 有以下幾種subtype:["SOCIAL","HUMANITY","ENGLISH"...]
// type為"INTEGRATED" 有以下幾種subtype:["CALCULUS","CIVIL_LAW"...]
// type為"PE"(體育) 目前沒有subtype subtype值為""
// type為"ND"(國防) 目前沒有subtype subtype值為""
short_code: String //此課程的短id code的前三碼
})
```
---
## 規劃資料庫(2)-政大學生帳號

----
## 處理使用者登入/登出
為了確認使用者是否是真的政大的學生,
我們的使用者登入登出系統使用了google auth
第三方登入驗證
----
## 登入架構流程圖

----
## 登入架構
使用者在跟google登入驗證成功後,再將拿到的token傳到我們的server,
然後我們server再拿此token跟google確認,
確認成功後,google就會回傳這個使用者的資料供我們寫入我們資料庫(使用upsert)
----
## 登入demo

----
## 驗證使用者是否為政大學生 done
使用google第三方登入驗證系統得好處就是
我們可以驗證使用者是否使用@g.nccu.edu.tw登入我們的系統
因為我們希望只有政大的學生能上傳評價
----
## 使用者資料結構
``` javascript [3-6]
const userSchema = mongoose.Schema({
id: { type: String ,unique:true}, //primary key
token: { type: String ,unique:true}, //google api 回傳的此使用者的代碼(驗證用)
name: { type: String, required: true }, // (取自google api)
email: { type: String, required: true }, // (取自google api)
picture: { type: String }, // 人物頭像圖(取自google api)
nickname: { type: String },// 暱稱
loginChannel: { type: String }, //使用者的登入管道
isValid: { type: String }, //是否通過信箱驗證
isBanned: { type: String }, //是否被ban
likes:[String], //使用者收藏的課程id陣列
thumbups:[String], //使用者按讚的評價(feedback)id陣列
},{timestamps: true});
```
---
## 規劃資料庫(3)-課程評價
因為課程跟使用者都有了,所以課程評價也可以做了

----
## 評價資料關係圖

----
## 評價資料結構圖
|評價id| 課程 | 學生 | 總分 | 甜度 | 涼度 | 評語 |
|--------| -------- | -------- | -------- | -------- | -------- | -------- |
|1| 1101000713001 | 108703051 | 4 | 3 | 4 | 老師人很好! |
|2| 1101000314061 | 108703060 | 5 | 2 | 5 | 很涼~ |
----
## 評價資料結構
``` javascript [2|3-6|7-8|9|11]
const courseFeedBackSchema = mongoose.Schema({
id:String, //(PK)
rate: Number, //評價
sweet: Number, //甜度
loading: Number, //涼度
gain: String, //收獲
introduction: String, //懶人包
description: String, //評價內容
user: String, //使用者id
user_nickname: String, //使用者暱稱
course: String, //課程id (FK)
course_semester: String, //e.g. "1101"
course_code: String, //由政大編碼的九碼課程id
num_of_thumbsup: Number, //按讚數
})
```
----
## 評價資料關係

---
## 資料庫ok了,開始處理前端跟後端
<!-- 在那之前,得先確認開發架構跟工具

-->
---
# 前端、後端架構

----
# 前端、後端架構

----
### 前端、後端架構圖

----
### 另一種理解:MVC架構

----
### 專案架構圖

---
<!-- ## 工具

---- -->
### 前端
#### 負責跟使用者互動的App、User Interface
<!--  -->

----
### 前端使用工具(1)
#### React.js

----
#### 為什麼我們前端要用React.js

----
### 前端使用工具(2)
#### material UI

----
### 為什麼我們前端要用Material UI
github 星星數第三的React library
Next.js ( ⭐ 79K)
Ant Design ( ⭐ 77K)
Material-UI(⭐ 74K) 開發快/好看/客製化
Tailewind CSS(⭐ 52K) 開發慢/好看/客製化
Bootstrap React(⭐ 20K) 開發快/不好看/制式化
---
<!-- ### 前端使用工具
#### Material UI
---- -->
### 後端

----
### 後端架構圖

----
### server
#### node.js server

----
#### node.js server結構

----
### 資料庫

----
### mongoDB

----
### mongoDB資料結構
## 評價資料結構
``` javascript [1|19|20-31]
const course =
{
course:"1101000211011",
semester:"1101",
code:"000211011",
point:3,
courseNameZH_TW:"政治學",
courseName:"Political science",
instructorZH_TW:"蔡中民",
instructor:"TSAI CHUNG-MIN",
departmentZH_TW:"政治系",
department:"Department of Political Science",
sessionZH_TW:"一D56",
session:"mon13-16",
classroom:"綜合270751",
typeOfCredit:"必/Required",
lectureLanguage:"中文/Mandarin",
isCoreGeneral:"否/No",
information:"@異動資訊Information of alteration:N/A",
note:"@備註Note:政治系優先。本課程於第二階段初選登記開放選課。",
comments:["小明:good","派大星:"老師人很好"],
feedbacks:[
{
id:1,
user:"11",
rate:4
},
{
id:2,
user:"12",
rate:4
}
],
avg_rate:3.3333333333333335,
avg_sweet:2.5,
avg_loading:2.1666666666666665,
avg_gain:4.166666666666667,
num_of_feedback:3
}
```
----
## 總結:全部工具的程式語言都是javascript

~~謎之音:javascript真香~~
----
### 專案架構圖

----
### 專案架構圖

----
### 完成品
[DEMO](https://hackmd.io/@_YdT2NPxQtGdnDBoiC3yQg/HkxZ7DehF)
<!--
### api
``` javascript [1|5|8-10]
export const fetchPost = (id) => API.get(`/posts/${id}`);
export const fetchPosts = (page) => API.get(`/posts?page=${page}`);
export const fetchPostsByCreator = (name) => API.get(`/posts/creator?name=${name}`);
export const fetchPostsBySearch = (searchQuery) => API.get(`/posts/search?searchQuery=${searchQuery.search || 'none'}&tags=${searchQuery.tags}`);
export const createPost = (newPost) => API.post('/posts', newPost);
export const likePost = (id) => API.patch(`/posts/${id}/likePost`);
export const comment = (value, id) => API.post(`/posts/${id}/commentPost`, { value });
export const updatePost = (id, updatedPost) => API.patch(`/posts/${id}`, updatedPost);
export const deletePost = (id) => API.delete(`/posts/${id}`);
export const fetchCourse = (course) => API.post(`/course`,course);
export const fetchCourseWithCheck = (course) => API.post(`/course/check`,course);
export const fetchCourseDetail = (course) => API.post(`/course/detail`,course);
export const fetchCourseResource = (course) => API.post(`/resource/get`,course);
export const fetchCourses = (page) => API.get(`/courses?page=${page}`);
export const fetchCoursesBySearch = (department) => API.get(`/courses/department?department=${department}`);
export const fetchCoursesByDepartment = (department) => API.post(`/course/department`, { department });
export const fetchCoursesByType = (data) => API.post(`/course/type`, data);
export const fetchCoursesByUserLike = (data) => API.post(`/course/userlike`, data);
export const createCourse = (newBook) => API.post('/books', newBook);
export const fetchFeedBack = (feedBack) => API.post('/feedback/get', feedBack);
export const createFeedBack = (newFeedBack) => API.post('/feedback', newFeedBack);
export const updateFeedBack = (feedBack) => API.post('/feedback/update', feedBack);
export const deleteFeedBack = (feedBack) => API.post('/feedback/delete', feedBack);
export const createResource = (newResource) => API.post('/resource', newResource);
export const createCourseComment = (value, id) => API.post(`/course/${id}/commentPost`, { value });
export const updateLike = (userData) => API.post('/user/like', userData);
export const updateNickname = (userData) => API.post('/user/nickname', userData);
export const signIn = (formData) => API.post('/user/signin', formData);
export const signUp = (formData) => API.post('/user/signup', formData);
export const googleSignIn = (formData) => API.post('/user/googlesignin', formData);
```
-->
---
### 課程評價網站初版完成了
deploy到heroku上
~~因為免費的最香~~

----
### 買網域

----
### 使用cloud flare增加安全

使用者 -> https://course-nccu.com -> 真實網域
----
### 休息一下
https://course-nccu.com
---
### 開發願景(接下來要做的事)

~~願景:vison~~
----
### 蒐集評價

<!-- 
-->
----
<!-- ### 版本控制
因為我們希望這個專案能有其他夥伴加入
| 理想 |vs| 實際 |
| -------- | -------- | -------- |
| 有commit訊息、不同功能不同branch | | 只有一條很長的master
---- -->
<!--
### 提升UI/UX
讓使用者更好操作本網站
---- -->
### 做dark mode功能
為了使用者(自己)的眼睛,必須要做。
----
### 整合DCARD上的修課心得

----
### SEO

----
### SEO

----
<!-- ### 跟政大選課系統re整合
開評價Api出來給他們call
--- -->
### 做考古題跟筆記上傳功能
<!-- 交大有做這個 -->

----
### 做二手書交易

---
### 最終目標: 流量/評價 永動機

---
### 特別感謝
選課系統組長的超強視覺宣傳圖

---
### 特別感謝
法律系 何傑恩同學的近2000筆Dcard選課紀錄
---
### 特別感謝
GDSC core team 的幫忙宣傳
GDSC的資源跟開發氣氛
---
## 謝謝大家撥空觀賞
https://course-nccu.com
{"metaMigratedAt":"2023-06-16T17:11:05.452Z","metaMigratedFrom":"YAML","title":"規劃資料庫","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"slideOptions\":null,\"spotlight\":{\"enabled\":true}}","contributors":"[{\"id\":\"fd8753d8-d3f1-42d1-9d9c-3068882df242\",\"add\":24455,\"del\":11771}]"}