# FSE Chat
The Chat Application is a real-time messaging platform that allows users to engage in text-based conversations. It is built using Node.js, Express, Socket.io, and Passport.js. The application provides a simple and intuitive interface for users to register, log in, and participate in chat conversations.
## Table of Contents
- [Features](#Features)
- [Technical Stack](#Technical-Stack)
- [File Structure](#File-Structure)
- [Reference](#Reference)
- [Frontend](#Frontend)
- [Backend](#Backend)
- [Database](#Database)
## Features
- Real-time Messaging: Users can send and receive messages in real-time, providing a seamless chatting experience.
- User Authentication: The application includes user authentication functionality, allowing users to securely log in and log out.
- User Registration: New users can create an account by registering with a unique username and password.
- Persistent Data Storage: Messages are stored in a database, ensuring that the chat history is preserved even after users leave and return to the application.
## Technical Stack
The application is built using the following technologies and libraries:
- Express.js: A popular web application framework for Node.js.
- Socket.io: A library for enabling real-time bidirectional communication between the server and clients.
- Pug.js: A template engine used for rendering dynamic HTML views.
- Passport.js: A user authentication middleware for Node.js.
- Prisma: An ORM (Object-Relational Mapping) tool for simplifying database interactions.
## File Structure
```
- server
- route.js
- index.js
- utils.js
- chatSocket.js
- views
- layout.pug
- index.pug
- login.pug
- register.pug
- public
- script.js
- style.css
- prisma
- schema.prisma
- index.js
- package.json
```
## Frontend
The frontend of the FSE Chat Room project is built using Pug.js and follows the BEM (Block-Element-Modifier) methodology for styling.
### Pug.js Templates
The project utilizes Pug.js as the templating engine to generate HTML. The main templates used in the frontend are as follows:
```pug
extends layout.pug
block content
header.header-container
h1.page-heading FSE Chat Room
form.logout-form(action='/logout', method='post')
input.button.button--orange(type='submit', value='Logout')
ul#messages.msg-list
form#form.msg-form(action="")
textarea#input.msg-form__input
div.msg-form__btn-container
button.button.button--orange Post
script.
const currentUser = !{JSON.stringify(username)};
script(src="/socket.io/socket.io.js")
script(src="/script.js")
```
### BEM (Block-Element-Modifier) CSS
The frontend styling follows the BEM methodology, providing a structured and modular approach to CSS. Here's an example of the CSS classes used:
```css
.logout-form {
margin: 0;
}
.msg-form {
position: fixed;
margin: 0;
bottom: 0; left: 0; right: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 8rem;
box-sizing: border-box;
background-color: #fff;
}
.msg-form__input {
flex-grow: 1;
padding: 0.25rem;
margin: 0.25rem;
resize: none;
border: 1px solid #333;
}
```
## Backend
The backend of the FSE Chat Room project is built using Express.js and Socket.IO for real-time communication. It also utilizes Passport.js for authentication and Prisma as the ORM (Object-Relational Mapping) tool for database operations.
### Server Setup
The server is set up using the following code in the ChatAppServer class:
```javascript
class ChatAppServer {
constructor() {
this.init()
this.useMiddleWares()
this.addRoutes()
this.listenServer()
}
// ... code continues
}
```
The ChatAppServer class handles the initialization of the server, middleware configuration, route setup, and server listening.
### Routes
The backend routes are organized into separate router classes, including IndexRouter, AuthRouter, and ChatRouter. Here's an example of how the routes are defined:
```javascript
class BaseRouter {
constructor() {
this.router = express.Router();
}
getRouter() {
return this.router;
}
}
class IndexRouter extends BaseRouter {
constructor() {
super();
this.router.get('/', isAuthenticated, this.getHome.bind(this));
}
// ... code continues
}
class AuthRouter extends BaseRouter {
constructor() {
super();
// ... route definitions
}
// ... route handler functions
}
class ChatRouter extends BaseRouter {
constructor() {
super();
// ... route definitions
}
// ... route handler functions
}
module.exports = {
IndexRouter,
AuthRouter,
ChatRouter
};
```
The routes are organized into separate classes to keep the code modular and maintainable. Each router class extends the BaseRouter class, which provides the underlying express.Router() instance.
### WebSocket Communication
WebSocket communication is handled by the ChatSocket class, which utilizes the Socket.IO library. Here's an example of how it's implemented:
```javascript
class ChatSocket {
constructor(io, sessionMiddleware) {
this.io = io;
this.sessionMiddleware = sessionMiddleware;
}
initialize() {
// ... middleware
this.io.on('connection', (socket) => {
socket.on('chat message', this.handleChatMessage.bind(this, socket));
});
}
// ... event handler functions
}
module.exports = ChatSocket;
```
The ChatSocket class initializes Socket.IO and handles WebSocket events, such as the 'connection' event and the 'chat message' event.
## Database
The FSE Chat Room project utilizes a SQLite database for storing user information and chat messages. The database schema is defined using Prisma, an ORM (Object-Relational Mapping) tool. Here's an example of the schema:
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
username String @unique
password String
messages Message[]
}
model Message {
id Int @id @default(autoincrement())
content String
user User @relation(fields: [username], references: [username])
username String
createdAt DateTime @default(now())
}
```
The User model represents a user in the system and has the following fields:
* `id`: An auto-incrementing integer that serves as the primary key.
* `username`: A unique string that represents the user's username.
* `password`: A string that stores the hashed password of the user.
* `messages`: A one-to-many relationship with the Message model, representing the messages posted by the user.
The Message model represents a chat message and has the following fields:
* `id`: An auto-incrementing integer that serves as the primary key.
* `content`: A string that stores the content of the message.
* `user`: A many-to-one relationship with the User model, representing the user who posted the message.
* `username`: A string that references the username field of the User model.
* `createdAt`: A datetime field that stores the timestamp when the message was created.
The Prisma schema enables easy interaction with the database using the Prisma Client. The Prisma Client generates a JavaScript client that provides a type-safe API for querying and manipulating data in the database.
## Reference
- [Socket.IO chat-example](https://socket.io/get-started/chat)
- [Passport tutorial](https://www.passportjs.org/tutorials/password/)
- [Prisma Quickstart](https://www.prisma.io/docs/getting-started/quickstart)
- [Express App using classes](https://youtu.be/kbPXLlnYuBg)
- [BEM,CSS 設計模式](https://chupai.github.io/posts/2104/bem/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99)