呂哲仲
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Final project USER STORY :::info 藍色:前端 ::: :::success 綠色:後端 ::: :::danger 紅色:全端 ::: == 使用者 PL == :::info - [ ] P0 身為一個使用者,我希望我可以以 e-mail 註冊會員、並登入、登出、修改帳號及密碼 * 個人頁面、登入使用 google、FB 等 API 串 - [ ] P1 身為一個使用者,我希望我可以在不同的裝置上正常使用網站功能。 - [ ] P1 身為一個使用者,我希望我可以在網站首頁看到使用指引。 ::: :::success - [ ] P1 身為一個使用者,我希望我可以在將使用期間遇到的問題向管理員回報。 - [ ] P3 身為一個使用者,我希望我可以匯出我在房間的活動紀錄。 * 聊天紀錄、完整 LOG ::: :::danger - [ ] P0 身為一個使用者,我希望我可以在登入後瀏覽、創立、編輯和刪除房間。 - [ ] P0 身為一個使用者,我希望我可以以不同的身分(參與者、觀眾、房主)加入房間。 - [ ] P1 身為一個使用者,我希望我可以在房間列表搜尋符合條件(系統、團名)的房間。 - [ ] P2 身為一個使用者,我希望我可以觀看其他使用者的個人資訊、並得知他的上線狀態。 ::: == 觀眾 viewer == (觀眾身分組本身可能就是 P1 或 P2?) :::info - [ ] P1 身為一個觀眾,我希望我可以觀看房間中的所有訊息。 - [ ] P1 身為一個觀眾,我希望我可以使用觀眾與房主專用的聊天頻道。 ::: == 參與者 PC == :::info - [ ] P1 身為一個參與者,我希望我可以在房間中使用擲骰功能。 - [ ] P1 身為一個參與者,我希望我可以在進入房間時接收房主傳送的資訊。 - [ ] P2 身為一個參與者,我希望我可以拖曳筆記的位置或將其至頂。 ::: :::danger - [ ] P0 身為一個參與者,我希望我可以設定自己的角色訊息(頭像、基礎數值)。 - [ ] P0 身為一個參與者,我希望我可以發送訊息,並選擇發送的頻道。 - [ ] P0 身為一個參與者,我希望我可以即時收到他人的訊息。 - [ ] P0 身為一個參與者,我希望我可以編輯、刪除自己的訊息。 - [ ] P1 身為一個參與者,我希望我可以在進入房間時自動載入先前的訊息。 - [ ] P1 身為一個參與者,我希望我可以創立並管理自己的筆記。 ::: == 房主 GM == :::info - [ ] P0 身為一個房主,我希望我可以查看並管理參與者的角色資訊。 - [ ] P0 身為一個房主,我希望我可以管理參與者的角色資訊。 - [ ] P0 身為一個房主,我希望我可以使用指令擲骰。 - [ ] P2 身為一個房主,我希望我可以在房間中播放 BGM。 - [ ] P2 身為一個房主,我希望我可以將特定內容投影到參與者的介面上。 ::: :::success - [ ] P0 身為一個房主,我希望我可以發送訊息,並選擇發送的頻道。 - [ ] P0 身為一個房主,我希望我可以即時收到他人的訊息。 - [ ] P0 身為一個房主,我希望我可以編輯、刪除房間的所有訊息、並管理發言權限。 - [ ] P1 身為一個房主,我希望我可以在設立房間時使用密碼為房間上鎖、並管理玩家跟觀眾的人數。 - [ ] P2 身為一個房主,我希望我可以透過帳號邀請使用者加入房間。 ::: :::danger - [ ] P0 身為一個房主,我希望我可以設立房間,並設置房間的基本狀態。 - [ ] P1 身為一個房主,我希望我可以傳送私人訊息給參與者、觀眾、並設定觀眾是否能看到。 - [ ] P1 身為一個房主,我希望我可以創立並管理自己的筆記。 - [ ] P1 身為一個房主,我希望我可以在房間中設置公告和行事曆。 ::: == 管理者 ADMIN == :::info - [ ] P0 身為一個管理者,我希望我可以看到所有的使用者資料。 ::: :::danger - [ ] P0 身為一個管理者,我希望我可以在後台管理所有的房間。 - [ ] P1 身為一個管理者,我希望我可以在首頁發布文章。 - [ ] P1 身為一個管理者,我希望我可以接收使用者的問題回報,並給予回應。 ::: # 網站頁面架構 1. 首頁(房間推薦、公告、問題回報) 2. 個人頁面(個人資料確認、修改) 3. 房間列表(搜尋房間、加入) 4. 房間頁面(聊天室、各種擴充功能) 5. 後台(管理房間、使用者) # 開發工具 1. 後端:Express + MySQL 2. 前端:React + Tailwind or Materialize + Sass 3. 部屬:Heroku(後端) + githubPage(前端) # 後端架構 :::success ## 資料庫結構 ### 使用者 - id - username - nickname - password (hashed) - email - relatedAccount (用FB/Google等帳號登入者) - onlineState (登入/離線/忙碌等) - info (讓使用者自訂的個人資訊,應該會用JSON存物件字串,避免把細節一項一項寫成 model) - picture (允許使用者用圖片網址/外部圖床API上傳來放大頭貼) ### 房間 - id - title - ~~message (聊天紀錄) ↑這裡應該會設計成每一條 message 本身有 content、from、to、isPublic 四個屬性 用 to 屬性決定是否是私訊、用 isPublic 決定是否讓觀眾看到~~ 改為 chat 為單獨的 table,用資料庫關聯處理 - notes (使用者加入的筆記) - ~~owner~~ 用資料庫關聯處理:userId - ~~participants~~ ← 不需要存進資料庫的內容,從 ws 判斷連線狀況更好 - ~~audiences~~ ← 同上 - system (使用何種遊戲規則) ### 對話紀錄 - id - content - userId ← 與使用者關聯,取用使用者的 id - roomId ← 與房間關聯,取用房間的 id ::: :::info ## 對前端 API 接口 ### 使用者帳號相關 #### 註冊 【POST】 /user/register body:{ username, password, email } 回傳值: - 成功 → {ok:1, token:token user:user} token 由 jwt 輸入 { username, email } 生成 user 是登入的使用者的詳細資訊 - 失敗 → {ok:0, error:error} 錯誤訊息 error 由後端寫定 *** #### 登入 【POST】 /user/login body:{ username, password } 回傳值: - 成功 → {ok:1, token:token, user:user} token 由 jwt 輸入 { username, email } 生成 user 是登入的使用者的詳細資訊 - 失敗 → {ok:0, error:error} 錯誤訊息 error 由後端寫定 ======================================== 回傳的 token 的格式是 bearer token,會長得像這樣: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mbyI6eyJ1c2VybmFtZSI6Imhhc2gtdGVzdGVyIiwiZW1haWwiOiIxMjNAZ21haWwuY29tIn0sImlhdCI6MTYzMzUxMTI0NSwiZXhwIjoxNjMzNTExMjc1fQ.91XN4QgXa9AU6hLJJx4ykAzLga5q_6YI5FDfTqnDzcA 直接將這個字串在發 request 的時候放在 header 的 Authorization 就可以了。 token 的有效時間是四個小時,資訊紀錄在 token 本身,時間超過之後就會視同沒有 token。 *** #### 檢查登入狀態 【GET】 Header: {Authorization: (bearer token)} /user/checkToken - 成功 → {ok:1, token:token, user:user} token 是更新過的 user 是登入的使用者的詳細資訊 - 失敗 → {ok:0,error:"token invalid or expired"} *** #### 修改使用者資訊 【POST】 /user/update?\_method=PUT Header: {Authorization: (bearer token)} body: { [email, info, nickname, picture] } 回傳值: - 成功 → 修改後的使用者之物件,物件包含該使用者創建的所有房間之物件的矩陣 ======================================== 所有的 body 內容都是 optional,放空白的也無所謂 不需要在網址指定 id,直接從使用者的 token 中取得 id,也就是只能夠修改目前登入的使用者的資訊 這個其實是【PUT】,但是 HTML 預設沒有 PUT 這個請求方法,所以是用 POST 發一個加上了特定 query 的請求,後端會把它解析成用 PUT 處理 *** #### 查詢所有使用者資訊 【GET】 /user Query: {username: string, nickname: string, offset:number, limit:number} 回傳值: - 成功 → 包含所有使用者之物件的矩陣 username 與 nickname 可以用 substring 的方式篩選使用者帳號/暱稱 offset 是略過指定數量,limit 是限制回傳數量 *** #### 查詢使用者數量 【GET】 /user/count 回傳值: - {userCount: n} 回傳目前資料庫中的使用者資訊總數 *** #### 查詢特定使用者資訊 【GET】 /user/:id :id 為任意正整數 回傳值: - 成功 → id 等於網址 :id 的使用者之物件,物件包含該使用者創建的所有房間之物件的矩陣 - 失敗 → {ok:0, error:'no such user'} *** ### 房間相關 #### 使用者檢視房間列表 【GET】 /room Query: {title: string, system: string, offset:number, limit:number} 回傳值: - 包含所有房間之物件的矩陣,如果 querystring 中有 title 或者 system 則篩選出符合 substring 的相應房間 - 失敗 → {ok:0, error:'no such room'} title 與 system 可以用 substring 的方式篩選房間名稱/系統相符的房間 offset 是略過指定數量,limit 是限制回傳數量 另外後端預設按 id 降冪排序,越晚創建的房間在回傳矩陣中越前面 *** #### 查詢房間數量 【GET】 /room/count 回傳值: - {roomCount: n} 回傳目前資料庫中的房間資訊總數 *** #### 使用者創建新房間 【POST】 /room/new Header: {Authorization: (bearer token)} body: { title, system } 回傳值: - 所建立房間之物件 *** #### 使用者變更房間設定 #### 使用者進入房間 【GET】 /room/:id :id 為任意正整數 回傳值: - 成功 → id 等於網址 :id 的房間之物件 - 失敗 → {ok:0, error:'no such room'} *** #### 使用者刪除房間 【POST】 /room/:id?\_method=DELETE Header: {Authorization: (bearer token)} :id 為任意正整數 刪除 id 等於 :id 的房間 回傳值: - 成功 → {ok:1} - 失敗 → {ok:0, error: error} #### 在有使用者的期間房間設定被變更 #### 發送訊息 見下方 socket.io 相關 #### 接收訊息 見下方 socket.io 相關 #### 接收私人訊息 ::: :::danger ## Socket.io 客戶端的使用方法: 安裝插件 npm i socket.io-client import { io } from 'socket.io-client' const socket = io('https://fay-trpg-api.herokuapp.com') ### 監聽事件 在 component 內: ``` useEffect(()=>{ socket.on("event1", function(message){ // do something here when receive event1 }) socket.on("event2", function(message){ // do something here when receive event2 }) return () => { socket.offAny() // clear all listener } }) ``` 用 useEffect 建立事件監聽器,在 re-render 時刪除前面建立的監聽器然後設置新的 監聽器的第一個參數是 String,監聽的目標是「從伺服器發過來的訊息」 當後端發送了一個事件名稱為 "hello" 的訊息時,如果前端有設置 socket.on("hello", function(message){}) 的監聽器, 那後面的 function 就會被執行、message 是後端發送的事件中帶著的資訊(一個物件) 傳送的資訊會是 JSON,但是 socket.io 自己寫好了 parser,所以不用特別去用 JSON.stringfy 等函式處理 ### 發送事件 `socket.emit(eventName, message)` 跟前端接收事件的方式一樣,後端也是設置對特定 eventName 的監聽器來做出回應 輸入的 message 是一個物件,裡面帶著要傳送的資訊 ## websocket API ### 已登入的使用者發送聊天室訊息 `socket.on("sendChat", {userId, roomId, content, to})` userId: 發送者的使用者 id roomId: 當前所在的房間 id content: 聊天訊息的內容 to: 發送的目標對象的 id,為 null 時為公開訊息 回傳值: - 成功 → `("chatSent", chat)` chat 為被存入資料庫的 chat 物件,包含發送該 chat 的使用者之帶有 id、username、nickname、onlineState 資訊的物件 - 失敗 → `("errorSentFromServer", err)` err 為相應的錯誤資訊 備註: 為了減少資料庫的讀寫,客戶端的聊天紀錄讀寫我預想中是這樣: 進入房間時讀取房間資料、裡面就會帶有該房間的聊天紀錄,這會是這次連線中唯一一次從資料庫讀取聊天訊息。 之後每當有人發送訊息,後端就會廣播 chatSent 事件,使用者後續畫面更新所需要的新訊息是從這裡接收。 ### 進入房間 `socket.on("joinRoom", {roomId})` roomId: 要進入的房間 id 回傳值:無 沒有回傳值的原因是客戶端的 socket instance 並沒有 room 屬性, 只有在伺服器端才能從連接中的 socket instance 取得這個客戶目前在哪些房間中。 伺服器端在廣播訊息時可以針對特定房間進行廣播。 :::

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully