ไบคๆไฟกๅท็ฎก็ๅนณๅฐๅ็ซฏๆๅก
openmask/
โโโ cmd/server/main.go # ๅ
ฅๅฃๆไปถ
โโโ go.mod # Goๆจกๅ้
็ฝฎ
โโโ internal/
โ โโโ config/ # ้
็ฝฎๆจกๅ
โ โ โโโ config.go # ้
็ฝฎๅ ่ฝฝ
โ โ โโโ config_test.go # ้
็ฝฎๆต่ฏ
โ โโโ models/ # ๆฐๆฎๅบๆจกๅ
โ โ โโโ models.go # 17ไธชๆฐๆฎ่กจๆจกๅ
โ โโโ repository/ # ๆฐๆฎ่ฎฟ้ฎๅฑ
โ โ โโโ repository.go # ๆฐๆฎๅบๆไฝ
โ โโโ services/ # ไธๅก้ป่พๅฑ
โ โ โโโ user_service.go # ็จๆท/้ดๆๆๅก
โ โ โโโ signal_service.go # ไฟกๅทไธญๅฟๆๅก
โ โ โโโ trade_service.go # ไบคๆๅๆฅๆๅก
โ โ โโโ stats_service.go # ็ป่ฎกๅๆๆๅก
โ โ โโโ content_service.go # ๅ
ๅฎนๆถๆฏๆๅก
โ โ โโโ *_test.go # ๆๅกๅฑๆต่ฏ
โ โโโ handlers/ # APIๅค็ๅจ
โ โ โโโ handlers.go # ๆๆHTTPๆฅๅฃ
โ โโโ middleware/ # ไธญ้ดไปถ
โ โโโ middleware.go # ่ฎค่ฏ/ๆฅๅฟ/้ๆต็ญ
โโโ pkg/
โโโ utils/ # ๅทฅๅ
ทๅฝๆฐ
โ โโโ crypto.go # ๅ ๅฏ/่ฑๆ
โ โโโ response.go # ๅๅบๅฐ่ฃ
โ โโโ *_test.go # ๅทฅๅ
ทๆต่ฏ
โโโ errors/ # ้่ฏฏๅค็
โโโ errors.go # ้่ฏฏๅฎไน
โโโ errors_test.go # ้่ฏฏๆต่ฏ
graph TB
subgraph Client ["ๅฎขๆท็ซฏ"]
A[iOS App]
B[Android App]
C[Web App]
D[ไบคๆๆบๅจไบบ]
end
subgraph Gateway ["API ็ฝๅ
ณ / Load Balancer"]
E[ginx / Envoy]
end
subgraph Auth ["็จๆท้ดๆๆจกๅ"]
F[็จๆทๆณจๅ/็ปๅฝ]
G[SDK Session]
H[ไบคๆ่ดฆๆท็ปๅฎ]
end
subgraph Signal ["ไฟกๅทไธญๅฟๆจกๅ"]
I[ไฟกๅทๅฝๅ
ฅ]
J[ไฟกๅทๅๅ]
K[ACK็กฎ่ฎค]
end
subgraph Trade ["ไบคๆๅๆฅๆฅๆถๆจกๅ"]
L[ๅผๅ/ๅนณๅไธๆฅ]
M[ๆไปๅฟซ็
ง<br/>10็งๅข้]
N[่ตไบงๅฟซ็
ง]
O[ๅน็ญๆงไฟ่ฏ]
end
subgraph Stats ["็ป่ฎกๅๆๆจกๅ"]
P[็ไบ็ป่ฎก<br/>ๆฅ/็ดฏ่ฎก]
Q[ๅ
จๅฑๆ่กๆฆ]
R[็ญ็ฅ็ป่ฎก]
end
subgraph Content ["ๅ
ๅฎนๆถๆฏๆจกๅ"]
S[ๅ
ฌๅ็ฎก็]
T[็ญ็ฅๅๅฒ]
U[AIๅฏน่ฏๅๅฒ]
end
subgraph Database ["ๆฐๆฎๅญๅจ"]
V[(MySQL)]
W[(Redis)]
end
subgraph External ["ๅค้จๆๅก"]
X[ไบคๆๆ API<br/>Binance/OKX]
end
A --> E
B --> E
C --> E
D --> E
E --> F
E --> G
E --> H
E --> I
E --> L
E --> P
E --> S
F --> V
G --> V
H --> V
I --> V
L --> V
M --> V
N --> V
P --> V
Q --> V
S --> V
T --> V
U --> V
V <--> W
H --> X
sequenceDiagram
participant Client as ๅฎขๆท็ซฏ
participant Server as ๆๅก็ซฏ
participant DB as MySQL
participant Redis as Redis
Note over Client,Server: ่ฎค่ฏๆต็จ
Client->>Server: POST /auth/register
Server->>DB: ๅๅปบ็จๆท
Server->>Client: {user_id, username}
Client->>Server: POST /auth/login
Server->>DB: ้ช่ฏ็จๆท
Server->>DB: ๅๅปบSession
Server->>Client: {token, expires_at}
Note over Client,Server: ไบคๆๅๆฅไธๆฅ
Client->>Server: POST /trade/open (request_id)
Server->>DB: ๆฃๆฅrequest_idๆฏๅฆๅทฒๅญๅจ
alt ๅน็ญๆฃๆฅ
Server->>DB: ๆๅ
ฅ่ฎขๅ่ฎฐๅฝ
Server->>Client: {order_id}
else ๅทฒๅญๅจ
Server->>Client: ่ฟๅๅทฒๆ่ฎฐๅฝ
end
loop ๆฏ10็งๅข้ๅๆญฅ
Client->>Server: POST /trade/sync
Server->>DB: ๆดๆฐๆไปๅฟซ็
ง
Server->>DB: ๆดๆฐ่ตไบงๅฟซ็
ง
Server->>Client: {message}
end
erDiagram
User ||--o{ UserExchangeAccount : has
User ||--o{ UserSDKSession : has
User ||--o{ Signal : creates
User ||--o{ SignalDispatchLog : receives
User ||--o{ TradeOrder : places
User ||--o{ UserPositionSnapshot : holds
User ||--o{ UserAssetSnapshot : owns
User ||--o{ UserPnlDaily : generates
User ||--o{ UserPnlTotal : accumulates
User ||--o{ GlobalRankSnapshot : appears_in
User ||--o{ AIChatHistory : chats
Signal ||--o{ SignalDispatchLog : dispatched_to
Signal ||--o{ SignalFollowRelation : followed_by
TradeOrder ||--o{ TradeFill : contains
- ็จๆทๆณจๅ/็ปๅฝ
- SDKไผ่ฏ็ฎก็
- ไบคๆ่ดฆๆท็ปๅฎ๏ผAPI Keyๅ ๅฏๅญๅจ๏ผ
- ๆๅทฅไฟกๅทๅฝๅ ฅ
- AIไฟกๅทๅฝๅ ฅ๏ผ้ข็๏ผ
- ไฟกๅทๅๅไธACK็กฎ่ฎค
- ๅผๅ/ๅนณๅไธๆฅ
- ๆไปๅฟซ็ งไธๆฅ๏ผๆฏ10็งๅข้๏ผ
- ่ตไบงๅฟซ็ งไธๆฅ
- ๅน็ญๆงไฟ่ฏ
- ็จๆท็ไบ็ป่ฎก๏ผๆฅ/็ดฏ่ฎก๏ผ
- ๅ จๅฑๆ่กๆฆ๏ผๆ็ไบ/ๆถ็็๏ผ
- ๆๅๆดๆฐ
- ๅ ฌๅ็ฎก็
- ็ญ็ฅไฟกๅทๅๅฒ
- AIๅฏน่ฏๅๅฒ
- ไปช่กจ็ๆฐๆฎ
- ่ฎขๅ/ๆไป/่ตไบงๅๅฒ
- ๆ่กๆฆๆฅ่ฏข
- UserใUserExchangeAccountใUserSDKSession
- SignalใSignalDispatchLogใSignalFollowRelation
- TradeOrderใTradeFillใUserPositionSnapshotใUserAssetSnapshot
- UserPnlDailyใUserPnlTotalใGlobalRankSnapshot
- AnnouncementใStrategySignalHistoryใAIChatHistory
- ๅบ็กURL:
http://localhost:8080/api/v1 - ๅ่ฎฎ: HTTP JSON
- ่ฎค่ฏๆนๅผ: Bearer Token (Session Token)
// ๆๅๅๅบ
{
"code": 0,
"message": "success",
"data": {}
}
// ๅ้กตๅๅบ
{
"code": 0,
"message": "success",
"data": [],
"total": 100,
"page": 1,
"page_size": 20
}
// ้่ฏฏๅๅบ
{
"code": 1001,
"message": "้่ฏฏไฟกๆฏ"
}| ้่ฏฏ็ | ่ฏดๆ |
|---|---|
| 0 | ๆๅ |
| 1001 | ๅๆฐ้่ฏฏ |
| 1002 | ๆชๆๆ |
| 1003 | ็ฆๆญข่ฎฟ้ฎ |
| 1004 | ่ตๆบไธๅญๅจ |
| 1005 | ่ตๆบๅฒ็ช |
| 1006 | ็จๆทไธๅญๅจ |
| 1007 | ็จๆทๅทฒ่ขซ็ฆ็จ |
| 1008 | ็จๆทๅๆๅฏ็ ้่ฏฏ |
| 1009 | Tokenๆ ๆ |
| 1010 | Tokenๅทฒ่ฟๆ |
| 5000 | ๆๅกๅจๅ ้จ้่ฏฏ |
Content-Type: application/json
Authorization: Bearer <session_token>
X-Device-ID: <่ฎพๅคID>
POST /auth/register
Request:
{
"username": "string", // ๅฟ
ๅกซ๏ผ็จๆทๅ
"password": "string", // ๅฟ
ๅกซ๏ผๅฏ็
"email": "string", // ้ๅกซ๏ผ้ฎ็ฎฑ
"nickname": "string" // ้ๅกซ๏ผๆต็งฐ
}Response:
{
"code": 0,
"message": "success",
"data": {
"user_id": 1,
"username": "testuser"
}
}POST /auth/login
Request:
{
"username": "string", // ๅฟ
ๅกซ
"password": "string" // ๅฟ
ๅกซ
}Response:
{
"code": 0,
"message": "success",
"data": {
"user_id": 1,
"username": "testuser",
"token": "uuid-token",
"expires_at": "2024-12-31T23:59:59Z"
}
}POST /auth/sdk/login
Request:
{
"token": "string" // ๅฟ
ๅกซ๏ผsession token
}Response:
{
"code": 0,
"message": "success",
"data": {
"user_id": 1,
"expires_at": "2024-12-31T23:59:59Z"
}
}GET /user/info
Headers: Authorization: Bearer <token>
Response:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"username": "testuser",
"nickname": "ๆต็งฐ",
"email": "[email protected]",
"avatar": "avatar_url",
"total_pnl": 1000.50,
"total_pnl_rate": 0.25,
"rank": 10,
"created_at": "2024-01-01T00:00:00Z"
}
}POST /user/exchange/account
Headers: Authorization: Bearer <token>
Request:
{
"exchange": "binance", // ๅฟ
ๅกซ๏ผไบคๆๆๅ็งฐ
"api_key": "string", // ๅฟ
ๅกซ๏ผAPI Key
"api_secret": "string", // ๅฟ
ๅกซ๏ผAPI Secret
"account_type": "ๅ็บฆ", // ๅฟ
ๅกซ๏ผ็ฐ่ดง/ๅ็บฆ
"margin_type": "ๅ
จไป", // ้ๅกซ๏ผๅ
จไป/้ไป
"position_type": "ๅๅๆไป" // ้ๅกซ๏ผๅๅ/ๅๅ
}Response:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"exchange": "binance",
"api_key_masked": "abcd****1234",
"account_type": 2,
"status": 1
}
}GET /user/exchange/accounts
Headers: Authorization: Bearer <token>
Response:
{
"code": 0,
"message": "success",
"data": [
{
"id": 1,
"exchange": "binance",
"api_key_masked": "abcd****1234",
"account_type": 2,
"margin_type": 1,
"position_type": 1,
"status": 1,
"bind_time": "2024-01-01T00:00:00Z"
}
]
}POST /signals
Headers: Authorization: Bearer <token>
Request:
{
"strategy_id": "str_001",
"strategy_name": "่ถๅฟ็ญ็ฅ",
"symbol": "BTCUSDT",
"side": "BUY", // BUY/SELL
"position_side": "LONG", // LONG/SHORT
"order_type": "MARKET", // MARKET/LIMIT
"quantity": 0.01,
"price": 0, // ๅธไปทๅๅกซ0
"stop_price": 0, // ๆญขๆไปท
"remark": "็ญ็ฅๅคๆณจ"
}Response:
{
"code": 0,
"message": "success",
"data": {
"id": "sig_xxx",
"strategy_id": "str_001",
"symbol": "BTCUSDT",
"side": "BUY",
"status": 1,
"created_at": "2024-01-01T00:00:00Z"
}
}GET /signals
Query Parameters:
page: ้กต็ ๏ผ้ป่ฎค1page_size: ๆฏ้กตๆฐ้๏ผ้ป่ฎค20
Response:
{
"code": 0,
"message": "success",
"data": [],
"total": 100,
"page": 1,
"page_size": 20
}GET /signals/pending
Query Parameters:
limit: ๆฐ้้ๅถ๏ผ้ป่ฎค20
GET /signals/:id
POST /signals/:id/ack
Headers: Authorization: Bearer <token>
Response:
{
"code": 0,
"message": "success",
"data": {
"message": "ไฟกๅทๅทฒ็กฎ่ฎค"
}
}POST /trade/open
Headers: Authorization: Bearer <token>
Request:
{
"request_id": "unique_req_id", // ๅฟ
ๅกซ๏ผๅน็ญID
"order_id": "order_123",
"symbol": "BTCUSDT",
"side": "BUY",
"position_side": "LONG",
"order_type": "MARKET",
"quantity": 0.01,
"price": 50000.00,
"filled_quantity": 0.01,
"filled_price": 50000.00,
"commission": 0.00001,
"remark": "ๅผไปๅคๆณจ"
}POST /trade/close
Headers: Authorization: Bearer <token>
Request:
{
"request_id": "unique_req_id", // ๅฟ
ๅกซ๏ผๅน็ญID
"order_id": "order_456",
"symbol": "BTCUSDT",
"side": "SELL",
"position_side": "LONG",
"order_type": "MARKET",
"quantity": 0.01,
"price": 51000.00,
"filled_quantity": 0.01,
"filled_price": 51000.00,
"commission": 0.00001,
"realized_pnl": 10.00,
"remark": "ๅนณไปๅคๆณจ"
}POST /trade/fail
Headers: Authorization: Bearer <token>
Request:
{
"request_id": "unique_req_id",
"order_id": "order_789",
"symbol": "BTCUSDT",
"error_code": "INSUFFICIENT_BALANCE",
"error_msg": "ไฝ้ขไธ่ถณ"
}POST /trade/position/snapshot
Headers: Authorization: Bearer <token>
Request:
{
"request_id": "unique_req_id",
"symbol": "BTCUSDT",
"position_side": "LONG",
"quantity": 0.01,
"entry_price": 50000.00,
"mark_price": 51000.00,
"unrealized_pnl": 10.00,
"leverage": 10
}POST /trade/asset/snapshot
Headers: Authorization: Bearer <token>
Request:
{
"request_id": "unique_req_id",
"total_assets": 10000.00,
"total_pnl": 100.00,
"available_balance": 5000.00,
"frozen_balance": 4900.00,
"margin_balance": 100.00
}POST /trade/sync
Headers: Authorization: Bearer <token>
Request:
{
"positions": [
{
"request_id": "pos_001",
"symbol": "BTCUSDT",
"position_side": "LONG",
"quantity": 0.01,
"entry_price": 50000.00,
"mark_price": 51000.00,
"unrealized_pnl": 10.00,
"leverage": 10
}
],
"assets": {
"request_id": "asset_001",
"total_assets": 10000.00,
"total_pnl": 100.00,
"available_balance": 5000.00,
"frozen_balance": 4900.00,
"margin_balance": 100.00
}
}GET /trade/positions
Headers: Authorization: Bearer <token>
GET /trade/orders
Headers: Authorization: Bearer <token>
Query Parameters:
page: ้กต็ page_size: ๆฏ้กตๆฐ้
GET /trade/asset/latest
Headers: Authorization: Bearer <token>
GET /trade/asset/history
Headers: Authorization: Bearer <token>
Query Parameters:
page: ้กต็ page_size: ๆฏ้กตๆฐ้
GET /trade/fills
Headers: Authorization: Bearer <token>
Query Parameters:
page: ้กต็ page_size: ๆฏ้กตๆฐ้
GET /stats/pnl
Headers: Authorization: Bearer <token>
GET /stats/rank
Query Parameters:
type: ๆๅบ็ฑปๅ (pnl/rate)limit: ๆฐ้้ๅถ๏ผ้ป่ฎค20
GET /stats/rank/me
Headers: Authorization: Bearer <token>
POST /stats/rank/update
GET /announcements/active
GET /announcements
Query Parameters:
page: ้กต็ page_size: ๆฏ้กตๆฐ้
GET /announcements/:id
POST /announcements
POST /announcements/:id/publish
GET /strategy/history
Query Parameters:
strategy_id: ็ญ็ฅIDpage: ้กต็ page_size: ๆฏ้กตๆฐ้
GET /chat/history
Headers: Authorization: Bearer <token>
Query Parameters:
page: ้กต็ page_size: ๆฏ้กตๆฐ้
POST /chat/message
Headers: Authorization: Bearer <token>
Request:
{
"session_id": "session_001",
"content": "็จๆทๆถๆฏๅ
ๅฎน"
}GET /dashboard
Headers: Authorization: Bearer <token>
Response:
{
"code": 0,
"message": "success",
"data": {
"user": {},
"asset": {},
"positions": [],
"pnl": {},
"rank": {},
"timestamp": "2024-01-01T00:00:00Z"
}
}GET /health
็กฎไฟๆๅก็ซฏๅทฒ้ ็ฝฎไปฅไธ็ฏๅขๅ้ๆ้ ็ฝฎๆไปถ๏ผ
# ๆฐๆฎๅบ้
็ฝฎ
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=password
DB_NAME=openmask
# Redis้
็ฝฎ๏ผๅฏ้๏ผ
REDIS_HOST=localhost
REDIS_PORT=6379
# ๆๅก็ซฏๅฃ
SERVER_PORT=8080โโโโโโโโโโโโโโโ POST /api/v1/auth/register โโโโโโโโโโโโโโโ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบ โ โ
โ ๅฎขๆท็ซฏ โ โ ๆๅก็ซฏ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โโโโโโโโโโโโโโโ {user_id, username} โโโโโโโโโโโโโโโ
โ POST /api/v1/auth/login
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบ
โ โโโโโโโโโโโโโโโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ๆๅก็ซฏ โ
โ {token, expires_at} โโโโโโโโโโโโโโโ
โ
โผ
ๅ็ปญ่ฏทๆฑๆบๅธฆ Token
Authorization: Bearer <token>
ๅฎขๆท็ซฏ๏ผไบคๆๆบๅจไบบ๏ผ ๆๅก็ซฏ
โ โ
โโโโโ POST /trade/open โโโโโโโโโโโโโบโ
โ (request_id: "uuid") โ
โโโโโโโ {order_id, ...} โโโโโโโโโโโโโ
โ โ
โ (ไบคๆ่ฟ่กไธญ) โ
โ โ
โโโโโ POST /trade/sync โโโโโโโโโโโโโบโ
โ (positions + assets) โ
โโโโโโโ {message} โโโโโโโโโโโโโโโโโโโ
โ โ
โ (ๆฏ10็งๅข้ๅๆญฅ) โ
โ โ
โโโโโ POST /trade/close โโโโโโโโโโโโบโ
โ (request_id: "uuid") โ
โโโโโโโ {order_id, realized_pnl} โโโโ
โ โ
ๆๆไบคๆๅๆฅๆฅๅฃๆฏๆๅน็ญๆง๏ผ้่ฟ request_id ้ฒๆญข้ๅคๆไบค๏ผ
// ๅฎขๆท็ซฏ็ๆๅฏไธID
requestID := uuid.New().String()
// ่ฏทๆฑไฝๅ
ๅซ request_id
{
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"order_id": "order_123",
...
}
// ๆๅก็ซฏไผๆ นๆฎ request_id ๅคๆญๆฏๅฆๅทฒๅค็
// ็ธๅ request_id ็่ฏทๆฑไผ่ฟๅๅทฒๅญๅจ็็ปๆ๏ผไธไผ้ๅคๅค็- ๅฎขๆท็ซฏๆไบค API Key ๆถไฝฟ็จๆๆ
- ๆๅก็ซฏไฝฟ็จ AES-256-CFB ๅ ๅฏๅญๅจ
- ๅฑ็คบๆถ่ฟๅ่ฑๆๅ็ Key๏ผๅฆ
abcd****1234๏ผ
// Go ็คบไพ
resp, err := http.Post(url, "application/json", body)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
if result["code"].(float64) != 0 {
// ๅค็้่ฏฏ
log.Printf("Error: %v", result["message"])
}// Swift ็คบไพ
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default)
.responseJSON { response in
if let json = response.result.value as? [String: Any] {
if json["code"] as! Int != 0 {
print("Error: \(json["message"]!)")
}
}
}// Kotlin ็คบไพ
RetrofitClient.api.login(request)
.enqueue(object : Callback<LoginResponse> {
override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
if (response.body()?.code != 0) {
println("Error: ${response.body()?.message}")
}
}
})- ่ฐ็จ
/auth/registerๆณจๅ - ่ฐ็จ
/auth/login็ปๅฝ่ทๅ Token - ่ฐ็จ
/user/exchange/account็ปๅฎไบคๆๆ่ดฆๆท
- ๅฏๅจๆถ่ฐ็จ
/auth/sdk/login้ช่ฏ Token - ๅผไป่ฐ็จ
/trade/open - ๅฎๆถ๏ผๆฏ10็ง๏ผ่ฐ็จ
/trade/syncๅๆญฅๆไปๅ่ตไบง - ๅนณไป่ฐ็จ
/trade/close - ๅคฑ่ดฅ่ฐ็จ
/trade/fail
- ็ปๅฝ่ทๅ Token
- ่ฐ็จ
/dashboard่ทๅๆฆ่ง - ่ฐ็จ
/trade/positionsๆฅ็ๆไป - ่ฐ็จ
/stats/rankๆฅ็ๆ่กๆฆ
# ็ผ่ฏ
go build -o openmask-server ./cmd/server
# ่ฟ่กๆๆๆต่ฏ
go test -v -count=1 ./...
# ่ฟ่ก็นๅฎๅ
็ๆต่ฏ
go test -v -count=1 ./internal/tests/...
go test -v -count=1 ./pkg/...้กน็ฎๅ ๅซ 46 ไธชๅๅ ๆต่ฏ๏ผ่ฆ็ไปฅไธๆจกๅ๏ผ
| ๆจกๅ | ๆต่ฏๆไปถ | ๆต่ฏๆฐ้ |
|---|---|---|
| ไฟกๅทไธญๅฟ | internal/tests/signal_service_test.go |
14 |
| ็ป่ฎกๅๆ | internal/tests/stats_service_test.go |
9 |
| ้ ็ฝฎๅ ่ฝฝ | internal/config/config_test.go |
2 |
| ่ฏทๆฑ้ช่ฏ | internal/services/*_test.go |
6 |
| ้่ฏฏๅค็ | pkg/errors/errors_test.go |
3 |
| ๅ ๅฏๅทฅๅ ท | pkg/utils/crypto_test.go |
5 |
| ๅๅบๅฐ่ฃ | pkg/utils/response_test.go |
7 |
่ฏฆ็ป็ๅๅ ๆต่ฏ่ฏดๆ่ฏทๅ้ ๏ผๅๅ ๆต่ฏๆๆกฃ
่ฏฅๆๆกฃๅ ๅซๆฏไธชๆต่ฏ็๏ผ
- ๆต่ฏ็ฎ็
- ๆต่ฏๆนๆณ
- ้ช่ฏ็น
- ไปฃ็ ็คบไพ
ๆๆๆต่ฏๅทฒ้่ฟใๅฏๅจๆๅกๅ้่ฆ้ ็ฝฎMySQLๆฐๆฎๅบ่ฟๆฅใ