first commit
This commit is contained in:
689
README.md
Normal file
689
README.md
Normal file
@@ -0,0 +1,689 @@
|
||||
|
||||
# 🚀 WebSocket API Service - Real-Time Communication
|
||||
|
||||
> **Modern WebSocket API service with advanced real-time communication, client management, and broadcasting capabilities**
|
||||
|
||||
## 📑 Daftar Isi
|
||||
|
||||
- [✨ Fitur Utama](#-fitur-utama)
|
||||
- [🏗️ Arsitektur](#%EF%B8%8F-arsitektur)
|
||||
- [⚡ Quick Start](#-quick-start)
|
||||
- [🔐 Autentikasi](#-autentikasi)
|
||||
- [📊 API Endpoints](#-api-endpoints)
|
||||
- [🛠️ Development](#%EF%B8%8F-development)
|
||||
- [🚀 Deployment](#-deployment)
|
||||
- [📚 Dokumentasi](#-dokumentasi)
|
||||
|
||||
***
|
||||
|
||||
## ✨ Fitur Utama
|
||||
|
||||
### Real-Time Communication
|
||||
|
||||
- **🔄 WebSocket Server** - High-performance WebSocket server dengan auto-reconnect
|
||||
- **🏠 Room Management** - Multi-room support untuk isolated communication
|
||||
- **👥 Client Tracking** - Advanced client identification (IP-based, static ID, generated)
|
||||
- **📡 Real-time Broadcasting** - Server-initiated broadcasts ke semua atau specific clients
|
||||
- **💬 Direct Messaging** - Peer-to-peer messaging antar clients
|
||||
- **🔄 Database Notifications** - PostgreSQL LISTEN/NOTIFY integration
|
||||
|
||||
### Advanced Features
|
||||
|
||||
- **📊 Connection Monitoring** - Real-time statistics dan health monitoring
|
||||
- **🧹 Auto Cleanup** - Automatic cleanup untuk inactive connections
|
||||
- **🔒 Secure Authentication** - JWT-based authentication untuk WebSocket connections
|
||||
- **📈 Performance Metrics** - Built-in performance tracking dan analytics
|
||||
- **🎯 Message Queue** - High-throughput message processing dengan worker pools
|
||||
- **🔍 Activity Logging** - Comprehensive activity logging untuk debugging
|
||||
|
||||
### Developer Experience
|
||||
|
||||
- **🔥 Hot Reload** - Development dengan auto-restart
|
||||
- **🐳 Docker Ready** - Easy deployment dengan Docker
|
||||
- **⚡ Code Generator** - Buat handler dan model otomatis
|
||||
- **🧪 Testing Suite** - Unit dan integration tests
|
||||
- **📊 Health Monitoring** - Monitoring kesehatan aplikasi
|
||||
|
||||
***
|
||||
|
||||
## 🏗️ Arsitektur WebSocket
|
||||
|
||||
### WebSocket Architecture Layers
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ WebSocket Layer │ ← websocket.go, broadcast.go
|
||||
├─────────────────────────────────────┤
|
||||
│ Application Layer │ ← handlers/, middleware/
|
||||
├─────────────────────────────────────┤
|
||||
│ Domain Layer │ ← models/, services/
|
||||
├─────────────────────────────────────┤
|
||||
│ Infrastructure Layer │ ← database/, external APIs
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Core Components
|
||||
|
||||
```
|
||||
api-service/
|
||||
├── 📁 cmd/api/ # 🚪 WebSocket server entry point
|
||||
├── 📁 internal/ # 🏠 Core WebSocket logic
|
||||
│ ├── handlers/websocket/ # 🔄 WebSocket handlers & hub
|
||||
│ ├── middleware/ # 🛡️ Auth & validation middleware
|
||||
│ ├── models/ # 📊 Data structures & validation
|
||||
│ ├── routes/ # 🛣️ API routing
|
||||
│ ├── services/ # 💼 Business logic services
|
||||
│ └── database/ # 💾 Database connections
|
||||
├── 📁 examples/clientsocket/ # 🌐 Vue.js WebSocket client
|
||||
├── 📁 docs/ # 📚 Swagger documentation
|
||||
└── 📁 configs/ # ⚙️ Configuration files
|
||||
```
|
||||
|
||||
### WebSocket Hub Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Hub │ ← Central WebSocket manager
|
||||
├─────────────────────────────────────┤
|
||||
│ • Client Management │ ← Register/unregister clients
|
||||
│ • Message Broadcasting │ ← Broadcast to clients/rooms
|
||||
│ • Room Management │ ← Multi-room support
|
||||
│ • Connection Monitoring │ ← Track active connections
|
||||
│ • Database Notifications │ ← PostgreSQL LISTEN/NOTIFY
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
***
|
||||
|
||||
## ⚡ Quick Start
|
||||
|
||||
### 1️⃣ Setup Environment (2 menit)
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone <repository-url>
|
||||
cd api-service
|
||||
|
||||
# Setup environment
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 2️⃣ Pilih Method Setup
|
||||
|
||||
**🐳 Docker (Recommended)**
|
||||
|
||||
```bash
|
||||
make docker-run
|
||||
```
|
||||
|
||||
**🔧 Manual Setup**
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
go mod download
|
||||
|
||||
# Start server
|
||||
go run cmd/api/main.go
|
||||
```
|
||||
|
||||
### 3️⃣ Setup WebSocket Client
|
||||
|
||||
**Start Vue.js Client Example:**
|
||||
|
||||
```bash
|
||||
cd examples/clientsocket
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 4️⃣ Verify Installation
|
||||
|
||||
| Service | URL | Status |
|
||||
| :-- | :-- | :-- |
|
||||
| **WebSocket API** | ws://localhost:8080/api/v1/ws | ✅ |
|
||||
| **WebSocket Client** | http://localhost:3000 | 🌐 |
|
||||
| **API Documentation** | http://localhost:8080/swagger/index.html | 📖 |
|
||||
| **Health Check** | http://localhost:8080/api/sistem/health | 💚 |
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 🔐 Autentikasi
|
||||
|
||||
### Login \& Mendapatkan Token
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "admin",
|
||||
"password": "password"
|
||||
}'
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"expires_in": 3600,
|
||||
"user": {
|
||||
"id": "123",
|
||||
"username": "admin",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Menggunakan Token
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8080/api/v1/products \
|
||||
-H "Authorization: Bearer <your-token>"
|
||||
```
|
||||
|
||||
|
||||
### Demo Accounts
|
||||
|
||||
| Username | Password | Role | Akses |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| `admin` | `password` | Admin | Semua endpoint |
|
||||
| `user` | `password` | User | Read-only |
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 📊 API Endpoints
|
||||
|
||||
### 🔄 WebSocket Endpoints
|
||||
|
||||
#### Main WebSocket Connection
|
||||
|
||||
| Protocol | Endpoint | Deskripsi |
|
||||
| :-- | :-- | :-- |
|
||||
| `WS` | `ws://localhost:8080/api/v1/ws` | WebSocket connection utama |
|
||||
|
||||
**Connection Parameters:**
|
||||
|
||||
```javascript
|
||||
// Basic connection
|
||||
const ws = new WebSocket('ws://localhost:8080/api/v1/ws');
|
||||
```
|
||||
|
||||
#### WebSocket Management API
|
||||
|
||||
| Method | Endpoint | Deskripsi |
|
||||
| :-- | :-- | :-- |
|
||||
| `GET` | `/api/websocket/stats` | WebSocket connection statistics |
|
||||
| `GET` | `/api/websocket/clients` | List all connected clients |
|
||||
| `GET` | `/api/websocket/rooms` | List all active rooms |
|
||||
| `POST` | `/api/websocket/broadcast` | Server-initiated broadcast |
|
||||
| `POST` | `/api/websocket/broadcast/room/:room` | Broadcast to specific room |
|
||||
| `POST` | `/api/websocket/send/:clientId` | Send message to specific client |
|
||||
| `POST` | `/api/websocket/cleanup/inactive` | Cleanup inactive clients |
|
||||
|
||||
### 🌍 Public REST Endpoints
|
||||
|
||||
| Method | Endpoint | Deskripsi |
|
||||
| :-- | :-- | :-- |
|
||||
| `POST` | `/api/v1/auth/login` | Login pengguna |
|
||||
| `POST` | `/api/v1/auth/register` | Registrasi pengguna baru |
|
||||
| `GET` | `/api/sistem/health` | Status kesehatan API |
|
||||
| `GET` | `/api/sistem/info` | System information |
|
||||
|
||||
### 🔒 Protected REST Endpoints
|
||||
|
||||
#### User Management
|
||||
|
||||
| Method | Endpoint | Deskripsi |
|
||||
| :-- | :-- | :-- |
|
||||
| `GET` | `/api/v1/auth/me` | Profile pengguna |
|
||||
| `PUT` | `/api/v1/auth/me` | Update profile |
|
||||
|
||||
#### Retribusi Management
|
||||
|
||||
| Method | Endpoint | Deskripsi |
|
||||
| :-- | :-- | :-- |
|
||||
| `GET` | `/api/v1/retribusi` | List semua retribusi |
|
||||
| `GET` | `/api/v1/retribusi/dynamic` | Query dengan filter dinamis |
|
||||
| `GET` | `/api/v1/retribusi/search` | Search retribusi advanced |
|
||||
| `GET` | `/api/v1/retribusi/id/:id` | Detail retribusi by ID |
|
||||
| `POST` | `/api/v1/retribusi` | Buat retribusi baru |
|
||||
| `PUT` | `/api/v1/retribusi/id/:id` | Update retribusi |
|
||||
| `DELETE` | `/api/v1/retribusi/id/:id` | Hapus retribusi |
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Code Generation (30 detik)
|
||||
|
||||
**🎯 Generate CRUD Lengkap**
|
||||
|
||||
```bash
|
||||
# Generate handler untuk entity baru
|
||||
go run tools/general/generate-handler.go product get post put delete
|
||||
|
||||
# Generate dengan fitur advanced
|
||||
go run tools/general/generate-handler.go orders get post put delete dynamic search stats
|
||||
```
|
||||
|
||||
**🏥 Generate BPJS Handler**
|
||||
|
||||
```bash
|
||||
# Single service
|
||||
go run tools/bpjs/generate-bpjs-handler.go tools/bpjs/reference/peserta get
|
||||
|
||||
# Semua service dari config
|
||||
go run tools/bpjs/generate-handler.go tools/bpjs/services-config-bpjs.yaml
|
||||
```
|
||||
|
||||
**🩺 Generate SATUSEHAT Handler**
|
||||
|
||||
```bash
|
||||
go run tools/satusehat/generate-satusehat-handler.go tools/satusehat/services-config-satusehat.yaml patient
|
||||
```
|
||||
|
||||
|
||||
### Development Commands
|
||||
|
||||
```bash
|
||||
# 🔥 Development dengan hot reload
|
||||
make watch
|
||||
|
||||
# 🧪 Testing
|
||||
make test # Unit tests
|
||||
make itest # Integration tests
|
||||
make test-all # Semua tests
|
||||
|
||||
# 📖 Update dokumentasi
|
||||
make docs # Generate Swagger docs
|
||||
|
||||
# 🔍 Code quality
|
||||
make lint # Linting
|
||||
make format # Format code
|
||||
```
|
||||
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
**📁 .env File:**
|
||||
|
||||
```bash
|
||||
# Database
|
||||
BLUEPRINT_DB_HOST=localhost
|
||||
BLUEPRINT_DB_PORT=5432
|
||||
BLUEPRINT_DB_USERNAME=postgres
|
||||
BLUEPRINT_DB_PASSWORD=postgres
|
||||
BLUEPRINT_DB_DATABASE=api_service
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=your-super-secret-key-change-in-production
|
||||
|
||||
# External APIs
|
||||
BPJS_BASE_URL=https://api.bpjs-kesehatan.go.id
|
||||
SATUSEHAT_BASE_URL=https://api.satusehat.kemkes.go.id
|
||||
|
||||
# Application
|
||||
APP_ENV=development
|
||||
APP_PORT=8080
|
||||
LOG_LEVEL=debug
|
||||
```
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 🚀 Deployment
|
||||
|
||||
### 🐳 Docker Deployment
|
||||
|
||||
**Development:**
|
||||
|
||||
```bash
|
||||
# Start semua services
|
||||
make docker-run
|
||||
|
||||
# Stop services
|
||||
make docker-down
|
||||
|
||||
# Rebuild dan restart
|
||||
make docker-rebuild
|
||||
```
|
||||
|
||||
**Production:**
|
||||
|
||||
```bash
|
||||
# Build production image
|
||||
docker build -t api-service:prod .
|
||||
|
||||
# Run production container
|
||||
docker run -d \
|
||||
--name api-service \
|
||||
-p 8080:8080 \
|
||||
--env-file .env.prod \
|
||||
api-service:prod
|
||||
```
|
||||
|
||||
|
||||
### 🔧 Manual Deployment
|
||||
|
||||
```bash
|
||||
# Build aplikasi
|
||||
make build
|
||||
|
||||
# Run migrations
|
||||
./scripts/migrate.sh up
|
||||
|
||||
# Start server
|
||||
./bin/api-service
|
||||
```
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 📚 Dokumentasi
|
||||
|
||||
### 📖 Interactive API Documentation
|
||||
|
||||
Kunjungi **Swagger UI** di: http://localhost:8080/swagger/index.html
|
||||
|
||||
**Cara menggunakan:**
|
||||
|
||||
1. 🔑 Login melalui `/auth/login` endpoint
|
||||
2. 📋 Copy token dari response
|
||||
3. 🔓 Klik tombol "Authorize" di Swagger
|
||||
4. 📝 Masukkan: `Bearer <your-token>`
|
||||
5. ✅ Test semua endpoint yang tersedia
|
||||
|
||||
### 🔄 WebSocket Client Examples
|
||||
|
||||
#### JavaScript WebSocket Client
|
||||
|
||||
**Basic Connection:**
|
||||
|
||||
```javascript
|
||||
// Create WebSocket connection
|
||||
const ws = new WebSocket('ws://localhost:8080/api/v1/ws');
|
||||
|
||||
// Connection opened
|
||||
ws.onopen = function(event) {
|
||||
console.log('Connected to WebSocket server');
|
||||
};
|
||||
|
||||
// Listen for messages
|
||||
ws.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('Message received:', data);
|
||||
};
|
||||
|
||||
// Send a message
|
||||
function sendMessage(message) {
|
||||
ws.send(JSON.stringify({
|
||||
type: 'broadcast',
|
||||
message: message
|
||||
}));
|
||||
}
|
||||
|
||||
// Handle connection close
|
||||
ws.onclose = function(event) {
|
||||
console.log('Disconnected from WebSocket server');
|
||||
};
|
||||
```
|
||||
|
||||
#### Vue.js Component Example
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="websocket-chat">
|
||||
<div class="messages" ref="messages">
|
||||
<div v-for="message in messages" :key="message.id" class="message">
|
||||
<strong>{{ message.client_id }}:</strong> {{ message.content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-area">
|
||||
<input
|
||||
v-model="newMessage"
|
||||
@keyup.enter="sendMessage"
|
||||
placeholder="Type a message..."
|
||||
>
|
||||
<button @click="sendMessage">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'WebSocketChat',
|
||||
data() {
|
||||
return {
|
||||
ws: null,
|
||||
messages: [],
|
||||
newMessage: ''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.connectWebSocket();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
connectWebSocket() {
|
||||
this.ws = new WebSocket('ws://localhost:8080/api/v1/ws');
|
||||
|
||||
this.ws.onopen = () => {
|
||||
console.log('WebSocket connected');
|
||||
};
|
||||
|
||||
this.ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
this.handleMessage(data);
|
||||
};
|
||||
|
||||
this.ws.onclose = () => {
|
||||
console.log('WebSocket disconnected');
|
||||
// Auto-reconnect after 5 seconds
|
||||
setTimeout(() => this.connectWebSocket(), 5000);
|
||||
};
|
||||
},
|
||||
|
||||
sendMessage() {
|
||||
if (this.newMessage.trim() && this.ws) {
|
||||
this.ws.send(JSON.stringify({
|
||||
type: 'broadcast',
|
||||
message: this.newMessage
|
||||
}));
|
||||
|
||||
this.newMessage = '';
|
||||
}
|
||||
},
|
||||
|
||||
handleMessage(data) {
|
||||
this.messages.push({
|
||||
id: Date.now(),
|
||||
client_id: data.client_id || 'server',
|
||||
content: data.message
|
||||
});
|
||||
|
||||
// Auto-scroll to bottom
|
||||
this.$nextTick(() => {
|
||||
this.$refs.messages.scrollTop = this.$refs.messages.scrollHeight;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
### 🧪 Testing Examples
|
||||
|
||||
**WebSocket Testing with wscat:**
|
||||
|
||||
```bash
|
||||
# Install wscat globally
|
||||
npm install -g wscat
|
||||
|
||||
# Connect to WebSocket server
|
||||
wscat -c ws://localhost:8080/api/v1/ws
|
||||
|
||||
# Send a message
|
||||
{"type": "broadcast", "message": "Hello from wscat!"}
|
||||
```
|
||||
|
||||
**cURL for REST endpoints:**
|
||||
|
||||
```bash
|
||||
# Login
|
||||
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"password"}' | jq -r '.access_token')
|
||||
|
||||
# Get WebSocket statistics
|
||||
curl http://localhost:8080/api/websocket/stats
|
||||
|
||||
# Broadcast message to all clients
|
||||
curl -X POST http://localhost:8080/api/websocket/broadcast \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type": "broadcast", "message": "Server broadcast message"}'
|
||||
|
||||
# Get system information
|
||||
curl http://localhost:8080/api/sistem/info
|
||||
|
||||
# Health check
|
||||
curl http://localhost:8080/api/sistem/health
|
||||
```
|
||||
|
||||
**Response Examples:**
|
||||
|
||||
```json
|
||||
{
|
||||
"connected_clients": 5,
|
||||
"databases": ["default"],
|
||||
"database_health": "connected",
|
||||
"timestamp": 1694325600
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 🚨 Troubleshooting
|
||||
|
||||
### Masalah Umum
|
||||
|
||||
**❌ Database Connection Error**
|
||||
|
||||
```bash
|
||||
# Cek status PostgreSQL
|
||||
make db-status
|
||||
|
||||
# Reset database
|
||||
make db-reset
|
||||
|
||||
# Check logs
|
||||
make logs-db
|
||||
```
|
||||
|
||||
**❌ Generate Handler Gagal**
|
||||
|
||||
- ✅ Pastikan berada di root project
|
||||
- ✅ Cek permission write di folder `internal/`
|
||||
- ✅ Verifikasi file `internal/routes/v1/routes.go` exists
|
||||
|
||||
**❌ Token Invalid/Expired**
|
||||
|
||||
- 🔄 Login ulang untuk mendapatkan token baru
|
||||
- ⏰ Token expire dalam 1 jam (configurable)
|
||||
- 📝 Format harus: `Bearer <token>`
|
||||
|
||||
**❌ Import Error saat Generate**
|
||||
|
||||
- 🧹 Jalankan: `go mod tidy`
|
||||
- 🔄 Restart development server
|
||||
- 📝 Cek format import di generated files
|
||||
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```bash
|
||||
# Enable debug logging
|
||||
export LOG_LEVEL=debug
|
||||
|
||||
# Run dengan verbose output
|
||||
make run-debug
|
||||
|
||||
# Monitor performance
|
||||
make monitor
|
||||
```
|
||||
|
||||
|
||||
***
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
### 📋 WebSocket Development Roadmap
|
||||
|
||||
- [x] ✅ **Setup environment selesai**
|
||||
- [x] ✅ **Implementasi WebSocket server**
|
||||
- [x] ✅ **Setup Vue.js client example**
|
||||
- [x] ✅ **Test WebSocket functionality**
|
||||
- [ ] 🔄 **Implementasi room management**
|
||||
- [ ] 🔄 **Tambahkan authentication ke WebSocket**
|
||||
- [ ] 🔄 **Implementasi database notifications**
|
||||
- [ ] 🔄 **Tambahkan unit tests untuk WebSocket**
|
||||
- [ ] 🔄 **Setup monitoring dan observability**
|
||||
- [ ] 🔄 **Deploy ke production**
|
||||
|
||||
### 🚀 Advanced WebSocket Features
|
||||
|
||||
- **🔄 Database Integration** - PostgreSQL LISTEN/NOTIFY
|
||||
- **📊 Real-time Analytics** - Connection metrics dan monitoring
|
||||
- **🔒 Enhanced Security** - Rate limiting, CORS, authentication
|
||||
- **📈 Performance Optimization** - Connection pooling, message queuing
|
||||
- **🏠 Multi-room Support** - Advanced room management
|
||||
- **📱 Mobile SDK Integration** - React Native, Flutter support
|
||||
- **🌐 Multi-protocol Support** - MQTT, Server-Sent Events
|
||||
- **📡 Load Balancing** - Horizontal scaling untuk WebSocket
|
||||
|
||||
### 🛠️ Immediate Next Steps
|
||||
|
||||
1. **Test WebSocket Connection**
|
||||
```bash
|
||||
# Start the server
|
||||
go run cmd/api/main.go
|
||||
|
||||
# Test with wscat
|
||||
wscat -c ws://localhost:8080/api/v1/ws
|
||||
```
|
||||
|
||||
2. **Try Vue.js Client Example**
|
||||
```bash
|
||||
cd examples/clientsocket
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
3. **Explore WebSocket Features**
|
||||
- Join/leave rooms
|
||||
- Send broadcast messages
|
||||
- Direct messaging between clients
|
||||
- Monitor connection statistics
|
||||
|
||||
***
|
||||
|
||||
**⚡ Total setup time: 5 menit | 🔄 WebSocket ready: Langsung test | 🌐 Client example: Vue.js included**
|
||||
|
||||
> **💡 Pro Tip:** Gunakan `make help` untuk melihat semua command yang tersedia
|
||||
|
||||
***
|
||||
|
||||
Reference in New Issue
Block a user