# halolight-bff **Repository Path**: halolight/halolight-bff ## Basic Information - **Project Name**: halolight-bff - **Description**: ๐Ÿ”— BFF ็ฝ‘ๅ…ณ Backend for Frontend - tRPC 11, TypeScript, React Query ้›†ๆˆ, ็ฑปๅž‹ๅฎ‰ๅ…จ Type-Safe API โ†’ halolight-bff.h7ml.cn - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: https://halolight.docs.h7ml.cn/guide/bff - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-24 - **Last Updated**: 2025-12-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: halolight, bff, trpc, TypeScript, api-gateway, type-safe, react-query ## README # HaloLight BFF ็ฝ‘ๅ…ณ > ๅŸบไบŽ tRPC ๆž„ๅปบ็š„ๅ‰็ซฏๅŽ็ซฏ็ฝ‘ๅ…ณ (BFF) ๅฑ‚๏ผŒไธบ HaloLight ๅ‰็ซฏๅบ”็”จๆไพ›็ปŸไธ€็š„็ฑปๅž‹ๅฎ‰ๅ…จ APIใ€‚ [![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue.svg)](https://www.typescriptlang.org/) [![tRPC](https://img.shields.io/badge/tRPC-11.0+-blueviolet.svg)](https://trpc.io/) [![License](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE) ## ๆฆ‚่ฟฐ HaloLight BFF ๆ˜ฏๅŸบไบŽ tRPC ็š„ๅ‰็ซฏๅŽ็ซฏๆœๅŠก๏ผŒไฝœไธบๅ‰็ซฏๅบ”็”จๅ’ŒๅŽ็ซฏๆœๅŠกไน‹้—ด็š„ API ็ฝ‘ๅ…ณใ€‚ๅฎƒๆไพ›๏ผš - **็ฑปๅž‹ๅฎ‰ๅ…จ API**๏ผšไปŽๆœๅŠกๅ™จๅˆฐๅฎขๆˆท็ซฏ็š„ๅฎŒๆ•ด TypeScript ็ฑปๅž‹ๆŽจๅฏผ - **็ปŸไธ€ๆŽฅๅฃ**๏ผšๅ•ไธ€ API ๅฑ‚่šๅˆๅคšไธชๅŽ็ซฏๆœๅŠก - **่บซไปฝ่ฎค่ฏ**๏ผšๅŸบไบŽ JWT ็š„่ฎค่ฏๅ’ŒๆŽˆๆƒ - **12 ไธชไธšๅŠกๆจกๅ—**๏ผš100+ ็ซฏ็‚น่ฆ†็›–ๆ‰€ๆœ‰ๅธธ่งไธšๅŠกๅœบๆ™ฏ - **ๆœๅŠกๆณจๅ†Œ**๏ผšๆ”ฏๆŒๅคšไธชๅŽ็ซฏๆœๅŠก๏ผˆPythonใ€Bunใ€Javaใ€NestJSใ€Nodeใ€Go๏ผ‰ ## ๆžถๆž„ ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๅ‰็ซฏๅบ”็”จ็จ‹ๅบ โ”‚ โ”‚ (Next.js, Vue, Angular, React, Nuxt ็ญ‰) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ tRPC ๅฎขๆˆท็ซฏ๏ผˆ็ฑปๅž‹ๅฎ‰ๅ…จ๏ผ‰ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ HaloLight BFF ็ฝ‘ๅ…ณ (tRPC) โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ ่ฎค่ฏ โ”‚ โ”‚ ็”จๆˆท โ”‚ โ”‚ไปช่กจ็›˜ โ”‚ โ”‚ ่ง’่‰ฒ โ”‚ โ”‚ ๅ›ข้˜Ÿ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ๆ–‡ไปถๅคน โ”‚ โ”‚ ๆ–‡ไปถ โ”‚ โ”‚ ๆ–‡ๆกฃ โ”‚ โ”‚ ๆ—ฅๅކ โ”‚ โ”‚ ๆถˆๆฏ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ HTTP ๅฎขๆˆท็ซฏ๏ผˆๅธฆ้‡่ฏ•ๅ’Œ่ถ…ๆ—ถ๏ผ‰ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ–ผ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Python โ”‚ โ”‚ Bun โ”‚ โ”‚ NestJS โ”‚ โ”‚ API โ”‚ โ”‚ API โ”‚ โ”‚ API โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ## ๅŠŸ่ƒฝ็‰นๆ€ง ### ไธšๅŠกๆจกๅ—๏ผˆ12 ไธช่ทฏ็”ฑ๏ผŒ100+ ็ซฏ็‚น๏ผ‰ | ๆจกๅ— | ็ซฏ็‚นๆ•ฐ | ๆ่ฟฐ | |------|--------|------| | **auth** | 8 | ็™ปๅฝ•ใ€ๆณจๅ†Œใ€ไปค็‰Œๅˆทๆ–ฐใ€็™ปๅ‡บใ€ๅฏ†็ ็ฎก็† | | **users** | 8 | ็”จๆˆทๅขžๅˆ ๆ”นๆŸฅใ€่ง’่‰ฒ/็Šถๆ€็ฎก็†ใ€ๅˆ†้กต | | **dashboard** | 9 | ็ปŸ่ฎกๆ•ฐๆฎใ€่ถ‹ๅŠฟใ€ๆดปๅŠจใ€ไปปๅŠกใ€็ณป็ปŸๆฆ‚่งˆ | | **permissions** | 7 | ๆƒ้™ๅขžๅˆ ๆ”นๆŸฅใ€ๆ ‘็ป“ๆž„ใ€ๆจกๅ—ๅˆ—่กจ | | **roles** | 8 | ่ง’่‰ฒๅขžๅˆ ๆ”นๆŸฅใ€ๆƒ้™ๅˆ†้… | | **teams** | 9 | ๅ›ข้˜Ÿๅขžๅˆ ๆ”นๆŸฅใ€ๆˆๅ‘˜็ฎก็†ใ€่ง’่‰ฒๆ›ดๆ–ฐ | | **folders** | 8 | ๆ–‡ไปถๅคนๅขžๅˆ ๆ”นๆŸฅใ€ๆ ‘็ป“ๆž„ใ€็งปๅŠจใ€้ขๅŒ…ๅฑ‘ | | **files** | 9 | ๆ–‡ไปถๅขžๅˆ ๆ”นๆŸฅใ€ไธŠไผ ใ€ไธ‹่ฝฝใ€็งปๅŠจใ€ๅคๅˆถใ€ๆ‰น้‡ๅˆ ้™ค | | **documents** | 10 | ๆ–‡ๆกฃๅขžๅˆ ๆ”นๆŸฅใ€็‰ˆๆœฌๅކๅฒใ€ๅˆ†ไบซใ€ๆขๅค | | **calendar** | 10 | ไบ‹ไปถๅขžๅˆ ๆ”นๆŸฅใ€ๅ‚ไธŽ่€…ใ€RSVP | | **notifications** | 7 | ๅˆ—่กจใ€ๆœช่ฏปๆ•ฐใ€ๆ ‡่ฎฐๅทฒ่ฏปใ€ๅˆ ้™ค | | **messages** | 9 | ๅฏน่ฏใ€ๆถˆๆฏใ€ๅ‘้€ใ€ๅทฒ่ฏป็Šถๆ€ | ### ๅŸบ็ก€่ฎพๆ–ฝ - **HTTP ๅฎขๆˆท็ซฏ**๏ผš็ปŸไธ€ๅฎขๆˆท็ซฏ๏ผŒๆ”ฏๆŒ้‡่ฏ•ใ€่ถ…ๆ—ถๅ’Œ Zod ๅ“ๅบ”้ชŒ่ฏ - **ๆœๅŠกๆณจๅ†Œ่กจ**๏ผšๅคšๅŽ็ซฏๆ”ฏๆŒ๏ผŒๅŸบไบŽไผ˜ๅ…ˆ็บง็š„่ทฏ็”ฑ - **Context ๅขžๅผบ**๏ผšTraceId ่ฟฝ่ธชใ€ๆœๅŠกๅฎขๆˆท็ซฏๆณจๅ…ฅ - **้€š็”จ Schemas**๏ผšๅฏๅค็”จ็š„ Zod schemas๏ผˆๅˆ†้กตใ€ๆŽ’ๅบใ€ๅ“ๅบ”๏ผ‰ ### ๅฎ‰ๅ…จๆ€ง - ๅŸบไบŽ JWT ็š„่ฎค่ฏๅ’Œ่ง’่‰ฒ่ฎฟ้—ฎๆŽงๅˆถ (RBAC) - ๅŸบไบŽๆƒ้™็š„ๆŽˆๆƒ (`*`ใ€`module:*`ใ€`module:action`) - Helmet.js ๅฎ‰ๅ…จๅคด - CORS ้…็ฝฎ - Zod ่ฏทๆฑ‚้ชŒ่ฏ ## ๅ‰็ฝฎ่ฆๆฑ‚ - **Node.js**: >= 20.0.0 - **pnpm**: >= 8.0.0 - **TypeScript**: >= 5.9.0 ## ๅฎ‰่ฃ… ```bash # ๅ…‹้š†ไป“ๅบ“ git clone https://github.com/halolight/halolight-bff.git cd halolight-bff # ๅฎ‰่ฃ…ไพ่ต– pnpm install # ๅคๅˆถ็Žฏๅขƒๅ˜้‡ cp .env.example .env # ๅฏๅŠจๅผ€ๅ‘ๆœๅŠกๅ™จ pnpm dev ``` ## ้…็ฝฎ ### ็Žฏๅขƒๅ˜้‡ ```bash # ๆœๅŠกๅ™จ้…็ฝฎ PORT=3002 HOST=0.0.0.0 NODE_ENV=development # CORS ้…็ฝฎ CORS_ORIGIN=* # JWT ้…็ฝฎ JWT_SECRET=your-super-secret-jwt-key-change-this-in-production JWT_EXPIRES_IN=7d # ๆ—ฅๅฟ— LOG_LEVEL=info # ๅŽ็ซฏๆœๅŠก๏ผˆๅฏ้€‰ - ็”จไบŽ API ่šๅˆ๏ผ‰ HALOLIGHT_API_PYTHON_URL=http://localhost:8000 HALOLIGHT_API_BUN_URL=http://localhost:3000 HALOLIGHT_API_JAVA_URL=http://localhost:8080 HALOLIGHT_API_NESTJS_URL=http://localhost:3001 HALOLIGHT_API_NODE_URL=http://localhost:3003 HALOLIGHT_API_GO_URL=http://localhost:8081 ``` ## ไฝฟ็”จ ### ๅผ€ๅ‘ๆจกๅผ ```bash pnpm dev # ๅฏๅŠจ็ƒญ้‡่ฝฝๅผ€ๅ‘ๆœๅŠกๅ™จ ``` ๆœๅŠกๅ™จๅฐ†ๅœจ `http://localhost:3002` ๅฏ็”จ ### ็”Ÿไบงๆจกๅผ ```bash pnpm build # ๆž„ๅปบ TypeScript pnpm start # ๅฏๅŠจ็”ŸไบงๆœๅŠกๅ™จ ``` ### ๅ…ถไป–ๅ‘ฝไปค ```bash pnpm lint # ไปฃ็ ๆฃ€ๆŸฅ pnpm format # ไปฃ็ ๆ ผๅผๅŒ– pnpm type-check # ็ฑปๅž‹ๆฃ€ๆŸฅ ``` ## API ็คบไพ‹ ### ่ฎค่ฏ ```typescript // ็™ปๅฝ• const result = await trpc.auth.login.mutate({ email: 'user@example.com', password: 'password123', }); // ่ฟ”ๅ›ž: { code: 200, message: '็™ปๅฝ•ๆˆๅŠŸ', data: { user, token, expiresIn } } // ่Žทๅ–ๅฝ“ๅ‰็”จๆˆท const user = await trpc.auth.getCurrentUser.query(); // ๅˆทๆ–ฐไปค็‰Œ const newToken = await trpc.auth.refreshToken.mutate(); ``` ### ็”จๆˆท็ฎก็† ```typescript // ๅˆ†้กตๆŸฅ่ฏข็”จๆˆทๅˆ—่กจ const users = await trpc.users.list.query({ page: 1, limit: 10, search: 'john', role: 'admin', status: 'active', }); // ๅˆ›ๅปบ็”จๆˆท๏ผˆไป…็ฎก็†ๅ‘˜๏ผ‰ const newUser = await trpc.users.create.mutate({ name: 'John Doe', email: 'john@example.com', password: 'securePassword123', role: 'editor', }); ``` ### ๆ–‡ๆกฃ็ฎก็† ```typescript // ๆŸฅ่ฏขๆ–‡ๆกฃๅˆ—่กจ const docs = await trpc.documents.list.query({ folderId: 'folder-1', status: 'published', tags: ['important'], }); // ๅˆ›ๅปบๆ–‡ๆกฃ const doc = await trpc.documents.create.mutate({ title: '้กน็›ฎ่ง„่Œƒ', content: '# ้กน็›ฎๆฆ‚่ฟฐ\n\n...', folderId: 'folder-docs', status: 'draft', tags: ['project', 'spec'], }); // ่Žทๅ–็‰ˆๆœฌๅކๅฒ const versions = await trpc.documents.getVersions.query({ documentId: 'doc-1' }); // ๆขๅคๅˆฐไน‹ๅ‰็‰ˆๆœฌ await trpc.documents.restoreVersion.mutate({ documentId: 'doc-1', version: 2 }); ``` ### ๆ—ฅๅކ ```typescript // ๆŸฅ่ฏขๆ—ฅๆœŸ่Œƒๅ›ดๅ†…็š„ไบ‹ไปถ const events = await trpc.calendar.list.query({ start: '2024-01-01T00:00:00Z', end: '2024-01-31T23:59:59Z', }); // ๅˆ›ๅปบไบ‹ไปถ const event = await trpc.calendar.create.mutate({ title: 'ๅ›ข้˜Ÿไผš่ฎฎ', start: '2024-01-15T10:00:00Z', end: '2024-01-15T11:00:00Z', location: 'ไผš่ฎฎๅฎค A', recurrence: 'weekly', }); // RSVP await trpc.calendar.updateAttendeeStatus.mutate({ eventId: 'event-1', status: 'accepted', }); ``` ## ๅฎขๆˆท็ซฏ้›†ๆˆ ### Next.js / React ```typescript import { createTRPCClient, httpBatchLink } from '@trpc/client'; import superjson from 'superjson'; import type { AppRouter } from 'halolight-bff'; export const trpc = createTRPCClient({ links: [ httpBatchLink({ url: 'http://localhost:3002/trpc', headers() { const token = localStorage.getItem('token'); return { authorization: token ? `Bearer ${token}` : '' }; }, }), ], transformer: superjson, }); ``` ### React Query ้›†ๆˆ ```typescript import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from 'halolight-bff'; export const trpc = createTRPCReact(); // ๅœจ็ป„ไปถไธญไฝฟ็”จ function UserList() { const { data, isLoading } = trpc.users.list.useQuery({ page: 1 }); if (isLoading) return
ๅŠ ่ฝฝไธญ...
; return ( ); } ``` ## ้กน็›ฎ็ป“ๆž„ ``` src/ โ”œโ”€โ”€ index.ts # ๅ…ฅๅฃๆ–‡ไปถ โ”œโ”€โ”€ server.ts # Express ๆœๅŠกๅ™จ้…็ฝฎ โ”œโ”€โ”€ trpc.ts # tRPC ๅฎžไพ‹ๅ’Œ procedures โ”œโ”€โ”€ context.ts # Context ๅˆ›ๅปบ๏ผˆ็”จๆˆทใ€traceIdใ€ๆœๅŠก๏ผ‰ โ”œโ”€โ”€ schemas/ โ”‚ โ”œโ”€โ”€ index.ts # Schema ๅฏผๅ‡บ โ”‚ โ””โ”€โ”€ common.ts # ้€š็”จ Zod schemas โ”œโ”€โ”€ services/ โ”‚ โ”œโ”€โ”€ index.ts # Service ๅฏผๅ‡บ โ”‚ โ”œโ”€โ”€ httpClient.ts # ๅŽ็ซฏๆœๅŠก HTTP ๅฎขๆˆท็ซฏ โ”‚ โ””โ”€โ”€ serviceRegistry.ts # ๅŽ็ซฏๆœๅŠกๆณจๅ†Œ่กจ โ”œโ”€โ”€ routers/ โ”‚ โ”œโ”€โ”€ index.ts # ๆ น่ทฏ็”ฑ โ”‚ โ”œโ”€โ”€ auth.ts # ่ฎค่ฏ โ”‚ โ”œโ”€โ”€ users.ts # ็”จๆˆท็ฎก็† โ”‚ โ”œโ”€โ”€ dashboard.ts # ไปช่กจ็›˜็ปŸ่ฎก โ”‚ โ”œโ”€โ”€ permissions.ts # ๆƒ้™็ฎก็† โ”‚ โ”œโ”€โ”€ roles.ts # ่ง’่‰ฒ็ฎก็† โ”‚ โ”œโ”€โ”€ teams.ts # ๅ›ข้˜Ÿ็ฎก็† โ”‚ โ”œโ”€โ”€ folders.ts # ๆ–‡ไปถๅคน็ฎก็† โ”‚ โ”œโ”€โ”€ files.ts # ๆ–‡ไปถ็ฎก็† โ”‚ โ”œโ”€โ”€ documents.ts # ๆ–‡ๆกฃ็ฎก็† โ”‚ โ”œโ”€โ”€ calendar.ts # ๆ—ฅๅކไบ‹ไปถ โ”‚ โ”œโ”€โ”€ notifications.ts # ้€š็Ÿฅ โ”‚ โ””โ”€โ”€ messages.ts # ๆถˆๆฏ โ””โ”€โ”€ middleware/ โ””โ”€โ”€ auth.ts # ่ฎค่ฏไธญ้—ดไปถ ``` ## ้ƒจ็ฝฒ ### Docker ```dockerfile FROM node:20-alpine WORKDIR /app COPY package*.json pnpm-lock.yaml ./ RUN npm install -g pnpm && pnpm install --frozen-lockfile --prod COPY . . RUN pnpm build EXPOSE 3002 CMD ["node", "dist/index.js"] ``` ### Docker Compose ```yaml version: '3.8' services: bff: build: . ports: - "3002:3002" environment: - NODE_ENV=production - JWT_SECRET=${JWT_SECRET} - HALOLIGHT_API_PYTHON_URL=http://api-python:8000 depends_on: - api-python ``` ## ่ทฏ็บฟๅ›พ - [x] ๆ ธๅฟƒ่ทฏ็”ฑ๏ผˆ่ฎค่ฏใ€็”จๆˆทใ€ไปช่กจ็›˜๏ผ‰ - [x] ๆƒ้™ๅ’Œ่ง’่‰ฒ็ฎก็† - [x] ๅ›ข้˜Ÿ็ฎก็† - [x] ๆ–‡ไปถๅ’Œๆ–‡ๆกฃ็ฎก็† - [x] ๆ—ฅๅކๅ’Œ้€š็Ÿฅ - [x] ๆถˆๆฏ็ณป็ปŸ - [x] ๅธฆ้‡่ฏ•/่ถ…ๆ—ถ็š„ HTTP ๅฎขๆˆท็ซฏ - [x] ๅคšๅŽ็ซฏๆœๅŠกๆณจๅ†Œ่กจ - [ ] ๆ•ฐๆฎๅบ“้›†ๆˆ๏ผˆPrisma๏ผ‰ - [ ] ๅฎžๆ—ถ WebSocket ๆ”ฏๆŒ - [ ] Redis ็ผ“ๅญ˜ๅฑ‚ - [ ] ้™ๆต - [ ] ๅฎŒๆ•ดๆต‹่ฏ•ๅฅ—ไปถ - [ ] OpenAPI ๆ–‡ๆกฃ ## ่ดก็Œฎ 1. Fork ไป“ๅบ“ 2. ๅˆ›ๅปบๅŠŸ่ƒฝๅˆ†ๆ”ฏ (`git checkout -b feature/amazing-feature`) 3. ๆไบคๆ›ดๆ”น (`git commit -m 'ๆทปๅŠ ๆŸไธชๅŠŸ่ƒฝ'`) 4. ๆŽจ้€ๅˆฐๅˆ†ๆ”ฏ (`git push origin feature/amazing-feature`) 5. ๆ‰“ๅผ€ Pull Request ## ่ฎธๅฏ่ฏ ISC ## ็›ธๅ…ณ้“พๆŽฅ - [ๆ–‡ๆกฃ](https://docs.halolight.h7ml.cn) - [GitHub ไป“ๅบ“](https://github.com/halolight/halolight-bff) - [tRPC ๆ–‡ๆกฃ](https://trpc.io) - [้—ฎ้ข˜่ฟฝ่ธช](https://github.com/halolight/halolight-bff/issues) --- ็”ฑ HaloLight ๅ›ข้˜Ÿไฝฟ็”จ TypeScriptใ€tRPC ๅ’Œ Express ๆž„ๅปบ