fix: harden unicode safety checks

This commit is contained in:
Affaan Mustafa
2026-03-29 08:59:06 -04:00
parent dd675d4258
commit 866d9ebb53
239 changed files with 3780 additions and 3962 deletions

View File

@@ -12,7 +12,7 @@ description: Backend architecture patterns, API design, database optimization, a
### RESTful API 結構
```typescript
// 基於資源的 URL
// PASS: 基於資源的 URL
GET /api/markets #
GET /api/markets/:id #
POST /api/markets #
@@ -20,7 +20,7 @@ PUT /api/markets/:id # 替換資源
PATCH /api/markets/:id #
DELETE /api/markets/:id #
// 用於過濾、排序、分頁的查詢參數
// PASS: 用於過濾、排序、分頁的查詢參數
GET /api/markets?status=active&sort=volume&limit=20&offset=0
```
@@ -120,7 +120,7 @@ export default withAuth(async (req, res) => {
### 查詢優化
```typescript
// 良好:只選擇需要的欄位
// PASS: 良好:只選擇需要的欄位
const { data } = await supabase
.from('markets')
.select('id, name, status, volume')
@@ -128,7 +128,7 @@ const { data } = await supabase
.order('volume', { ascending: false })
.limit(10)
// 不良:選擇所有欄位
// FAIL: 不良:選擇所有欄位
const { data } = await supabase
.from('markets')
.select('*')
@@ -137,13 +137,13 @@ const { data } = await supabase
### N+1 查詢問題預防
```typescript
// 不良N+1 查詢問題
// FAIL: 不良N+1 查詢問題
const markets = await getMarkets()
for (const market of markets) {
market.creator = await getUser(market.creator_id) // N 次查詢
}
// 良好:批次取得
// PASS: 良好:批次取得
const markets = await getMarkets()
const creatorIds = markets.map(m => m.creator_id)
const creators = await getUsers(creatorIds) // 1 次查詢

View File

@@ -86,7 +86,7 @@ ORDER BY hour DESC;
### 高效過濾
```sql
-- 良好:先使用索引欄位
-- PASS: 良好:先使用索引欄位
SELECT *
FROM markets_analytics
WHERE date >= '2025-01-01'
@@ -95,7 +95,7 @@ WHERE date >= '2025-01-01'
ORDER BY date DESC
LIMIT 100;
-- 不良:先過濾非索引欄位
-- FAIL: 不良:先過濾非索引欄位
SELECT *
FROM markets_analytics
WHERE volume > 1000
@@ -106,7 +106,7 @@ WHERE volume > 1000
### 聚合
```sql
-- 良好:使用 ClickHouse 特定聚合函式
-- PASS: 良好:使用 ClickHouse 特定聚合函式
SELECT
toStartOfDay(created_at) AS day,
market_id,
@@ -119,7 +119,7 @@ WHERE created_at >= today() - INTERVAL 7 DAY
GROUP BY day, market_id
ORDER BY day DESC, total_volume DESC;
-- 使用 quantile 計算百分位數(比 percentile 更高效)
-- PASS: 使用 quantile 計算百分位數(比 percentile 更高效)
SELECT
quantile(0.50)(trade_size) AS median,
quantile(0.95)(trade_size) AS p95,
@@ -162,7 +162,7 @@ const clickhouse = new ClickHouse({
}
})
// 批量插入(高效)
// PASS: 批量插入(高效)
async function bulkInsertTrades(trades: Trade[]) {
const values = trades.map(trade => `(
'${trade.id}',
@@ -178,7 +178,7 @@ async function bulkInsertTrades(trades: Trade[]) {
`).toPromise()
}
// 個別插入(慢)
// FAIL: 個別插入(慢)
async function insertTrade(trade: Trade) {
// 不要在迴圈中這樣做!
await clickhouse.query(`

View File

@@ -38,12 +38,12 @@ description: Universal coding standards, best practices, and patterns for TypeSc
### 變數命名
```typescript
// 良好:描述性名稱
// PASS: 良好:描述性名稱
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000
// 不良:不清楚的名稱
// FAIL: 不良:不清楚的名稱
const q = 'election'
const flag = true
const x = 1000
@@ -52,12 +52,12 @@ const x = 1000
### 函式命名
```typescript
// 良好:動詞-名詞模式
// PASS: 良好:動詞-名詞模式
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }
// 不良:不清楚或只有名詞
// FAIL: 不良:不清楚或只有名詞
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }
@@ -66,7 +66,7 @@ function email(e) { }
### 不可變性模式(關鍵)
```typescript
// 總是使用展開運算符
// PASS: 總是使用展開運算符
const updatedUser = {
...user,
name: 'New Name'
@@ -74,7 +74,7 @@ const updatedUser = {
const updatedArray = [...items, newItem]
// 永遠不要直接修改
// FAIL: 永遠不要直接修改
user.name = 'New Name' // 不良
items.push(newItem) // 不良
```
@@ -82,7 +82,7 @@ items.push(newItem) // 不良
### 錯誤處理
```typescript
// 良好:完整的錯誤處理
// PASS: 良好:完整的錯誤處理
async function fetchData(url: string) {
try {
const response = await fetch(url)
@@ -98,7 +98,7 @@ async function fetchData(url: string) {
}
}
// 不良:無錯誤處理
// FAIL: 不良:無錯誤處理
async function fetchData(url) {
const response = await fetch(url)
return response.json()
@@ -108,14 +108,14 @@ async function fetchData(url) {
### Async/Await 最佳實務
```typescript
// 良好:可能時並行執行
// PASS: 良好:可能時並行執行
const [users, markets, stats] = await Promise.all([
fetchUsers(),
fetchMarkets(),
fetchStats()
])
// 不良:不必要的順序執行
// FAIL: 不良:不必要的順序執行
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()
@@ -124,7 +124,7 @@ const stats = await fetchStats()
### 型別安全
```typescript
// 良好:正確的型別
// PASS: 良好:正確的型別
interface Market {
id: string
name: string
@@ -136,7 +136,7 @@ function getMarket(id: string): Promise<Market> {
// 實作
}
// 不良:使用 'any'
// FAIL: 不良:使用 'any'
function getMarket(id: any): Promise<any> {
// 實作
}
@@ -147,7 +147,7 @@ function getMarket(id: any): Promise<any> {
### 元件結構
```typescript
// 良好:具有型別的函式元件
// PASS: 良好:具有型別的函式元件
interface ButtonProps {
children: React.ReactNode
onClick: () => void
@@ -172,7 +172,7 @@ export function Button({
)
}
// 不良:無型別、結構不清楚
// FAIL: 不良:無型別、結構不清楚
export function Button(props) {
return <button onClick={props.onClick}>{props.children}</button>
}
@@ -181,7 +181,7 @@ export function Button(props) {
### 自訂 Hooks
```typescript
// 良好:可重用的自訂 hook
// PASS: 良好:可重用的自訂 hook
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
@@ -203,25 +203,25 @@ const debouncedQuery = useDebounce(searchQuery, 500)
### 狀態管理
```typescript
// 良好:正確的狀態更新
// PASS: 良好:正確的狀態更新
const [count, setCount] = useState(0)
// 基於先前狀態的函式更新
setCount(prev => prev + 1)
// 不良:直接引用狀態
// FAIL: 不良:直接引用狀態
setCount(count + 1) // 在非同步情境中可能過時
```
### 條件渲染
```typescript
// 良好:清晰的條件渲染
// PASS: 良好:清晰的條件渲染
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}
// 不良:三元地獄
// FAIL: 不良:三元地獄
{isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}
```
@@ -244,7 +244,7 @@ GET /api/markets?status=active&limit=10&offset=0
### 回應格式
```typescript
// 良好:一致的回應結構
// PASS: 良好:一致的回應結構
interface ApiResponse<T> {
success: boolean
data?: T
@@ -275,7 +275,7 @@ return NextResponse.json({
```typescript
import { z } from 'zod'
// 良好Schema 驗證
// PASS: 良好Schema 驗證
const CreateMarketSchema = z.object({
name: z.string().min(1).max(200),
description: z.string().min(1).max(2000),
@@ -338,14 +338,14 @@ types/market.types.ts # 型別用 camelCase 加 .types 後綴
### 何時註解
```typescript
// 良好:解釋「為什麼」而非「什麼」
// PASS: 良好:解釋「為什麼」而非「什麼」
// 使用指數退避以避免在服務中斷時壓垮 API
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)
// 為了處理大陣列的效能,此處刻意使用突變
items.push(newItem)
// 不良:陳述顯而易見的事實
// FAIL: 不良:陳述顯而易見的事實
// 將計數器加 1
count++
@@ -385,12 +385,12 @@ export async function searchMarkets(
```typescript
import { useMemo, useCallback } from 'react'
// 良好:記憶化昂貴的計算
// PASS: 良好:記憶化昂貴的計算
const sortedMarkets = useMemo(() => {
return markets.sort((a, b) => b.volume - a.volume)
}, [markets])
// 良好:記憶化回呼函式
// PASS: 良好:記憶化回呼函式
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
@@ -401,7 +401,7 @@ const handleSearch = useCallback((query: string) => {
```typescript
import { lazy, Suspense } from 'react'
// 良好:延遲載入重型元件
// PASS: 良好:延遲載入重型元件
const HeavyChart = lazy(() => import('./HeavyChart'))
export function Dashboard() {
@@ -416,13 +416,13 @@ export function Dashboard() {
### 資料庫查詢
```typescript
// 良好:只選擇需要的欄位
// PASS: 良好:只選擇需要的欄位
const { data } = await supabase
.from('markets')
.select('id, name, status')
.limit(10)
// 不良:選擇所有欄位
// FAIL: 不良:選擇所有欄位
const { data } = await supabase
.from('markets')
.select('*')
@@ -449,12 +449,12 @@ test('calculates similarity correctly', () => {
### 測試命名
```typescript
// 良好:描述性測試名稱
// PASS: 良好:描述性測試名稱
test('returns empty array when no markets match query', () => { })
test('throws error when OpenAI API key is missing', () => { })
test('falls back to substring search when Redis unavailable', () => { })
// 不良:模糊的測試名稱
// FAIL: 不良:模糊的測試名稱
test('works', () => { })
test('test search', () => { })
```
@@ -465,12 +465,12 @@ test('test search', () => { })
### 1. 過長函式
```typescript
// 不良:函式超過 50 行
// FAIL: 不良:函式超過 50 行
function processMarketData() {
// 100 行程式碼
}
// 良好:拆分為較小的函式
// PASS: 良好:拆分為較小的函式
function processMarketData() {
const validated = validateData()
const transformed = transformData(validated)
@@ -480,7 +480,7 @@ function processMarketData() {
### 2. 過深巢狀
```typescript
// 不良5 層以上巢狀
// FAIL: 不良5 層以上巢狀
if (user) {
if (user.isAdmin) {
if (market) {
@@ -493,7 +493,7 @@ if (user) {
}
}
// 良好:提前返回
// PASS: 良好:提前返回
if (!user) return
if (!user.isAdmin) return
if (!market) return
@@ -505,11 +505,11 @@ if (!hasPermission) return
### 3. 魔術數字
```typescript
// 不良:無解釋的數字
// FAIL: 不良:無解釋的數字
if (retryCount > 3) { }
setTimeout(callback, 500)
// 良好:命名常數
// PASS: 良好:命名常數
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500

View File

@@ -12,7 +12,7 @@ description: Frontend development patterns for React, Next.js, state management,
### 組合優於繼承
```typescript
// 良好:元件組合
// PASS: 良好:元件組合
interface CardProps {
children: React.ReactNode
variant?: 'default' | 'outlined'
@@ -283,17 +283,17 @@ export function useMarkets() {
### 記憶化
```typescript
// useMemo 用於昂貴計算
// PASS: useMemo 用於昂貴計算
const sortedMarkets = useMemo(() => {
return markets.sort((a, b) => b.volume - a.volume)
}, [markets])
// useCallback 用於傳遞給子元件的函式
// PASS: useCallback 用於傳遞給子元件的函式
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
// React.memo 用於純元件
// PASS: React.memo 用於純元件
export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
return (
<div className="market-card">
@@ -309,7 +309,7 @@ export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
```typescript
import { lazy, Suspense } from 'react'
// 延遲載入重型元件
// PASS: 延遲載入重型元件
const HeavyChart = lazy(() => import('./HeavyChart'))
const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))
@@ -504,7 +504,7 @@ export class ErrorBoundary extends React.Component<
```typescript
import { motion, AnimatePresence } from 'framer-motion'
// 列表動畫
// PASS: 列表動畫
export function AnimatedMarketList({ markets }: { markets: Market[] }) {
return (
<AnimatePresence>
@@ -523,7 +523,7 @@ export function AnimatedMarketList({ markets }: { markets: Market[] }) {
)
}
// Modal 動畫
// PASS: Modal 動畫
export function Modal({ isOpen, onClose, children }: ModalProps) {
return (
<AnimatePresence>

View File

@@ -27,12 +27,12 @@ description: Pattern for progressively refining context retrieval to solve the s
┌─────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ DISPATCH │─────│ EVALUATE │ │
│ │ DISPATCH │─────│ EVALUATE │ │
│ └──────────┘ └──────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ LOOP │─────│ REFINE │ │
│ │ LOOP │─────│ REFINE │ │
│ └──────────┘ └──────────┘ │
│ │
│ 最多 3 個循環,然後繼續 │

View File

@@ -21,13 +21,13 @@ description: Use this skill when adding authentication, handling user input, wor
### 1. 密鑰管理
#### 絕不這樣做
#### FAIL: 絕不這樣做
```typescript
const apiKey = "sk-proj-xxxxx" // 寫死的密鑰
const dbPassword = "password123" // 在原始碼中
```
#### 總是這樣做
#### PASS: 總是這樣做
```typescript
const apiKey = process.env.OPENAI_API_KEY
const dbUrl = process.env.DATABASE_URL
@@ -107,14 +107,14 @@ function validateFileUpload(file: File) {
### 3. SQL 注入預防
#### 絕不串接 SQL
#### FAIL: 絕不串接 SQL
```typescript
// 危險 - SQL 注入漏洞
const query = `SELECT * FROM users WHERE email = '${userEmail}'`
await db.query(query)
```
#### 總是使用參數化查詢
#### PASS: 總是使用參數化查詢
```typescript
// 安全 - 參數化查詢
const { data } = await supabase
@@ -139,10 +139,10 @@ await db.query(
#### JWT Token 處理
```typescript
// 錯誤localStorage易受 XSS 攻擊)
// FAIL: 錯誤localStorage易受 XSS 攻擊)
localStorage.setItem('token', token)
// 正確httpOnly cookies
// PASS: 正確httpOnly cookies
res.setHeader('Set-Cookie',
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
```
@@ -299,18 +299,18 @@ app.use('/api/search', searchLimiter)
#### 日誌記錄
```typescript
// 錯誤:記錄敏感資料
// FAIL: 錯誤:記錄敏感資料
console.log('User login:', { email, password })
console.log('Payment:', { cardNumber, cvv })
// 正確:遮蔽敏感資料
// PASS: 正確:遮蔽敏感資料
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
```
#### 錯誤訊息
```typescript
// 錯誤:暴露內部細節
// FAIL: 錯誤:暴露內部細節
catch (error) {
return NextResponse.json(
{ error: error.message, stack: error.stack },
@@ -318,7 +318,7 @@ catch (error) {
)
}
// 正確:通用錯誤訊息
// PASS: 正確:通用錯誤訊息
catch (error) {
console.error('Internal error:', error)
return NextResponse.json(

View File

@@ -24,7 +24,7 @@
#### 最小權限原則
```yaml
# 正確:最小權限
# PASS: 正確:最小權限
iam_role:
permissions:
- s3:GetObject # 只有讀取存取
@@ -32,7 +32,7 @@ iam_role:
resources:
- arn:aws:s3:::my-bucket/* # 只有特定 bucket
# 錯誤:過於廣泛的權限
# FAIL: 錯誤:過於廣泛的權限
iam_role:
permissions:
- s3:* # 所有 S3 動作
@@ -65,14 +65,14 @@ aws iam enable-mfa-device \
#### 雲端密鑰管理器
```typescript
// 正確:使用雲端密鑰管理器
// PASS: 正確:使用雲端密鑰管理器
import { SecretsManager } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManager({ region: 'us-east-1' });
const secret = await client.getSecretValue({ SecretId: 'prod/api-key' });
const apiKey = JSON.parse(secret.SecretString).key;
// 錯誤:寫死或只在環境變數
// FAIL: 錯誤:寫死或只在環境變數
const apiKey = process.env.API_KEY; // 未輪換、未稽核
```
@@ -99,7 +99,7 @@ aws secretsmanager rotate-secret \
#### VPC 和防火牆設定
```terraform
# 正確:限制的安全群組
# PASS: 正確:限制的安全群組
resource "aws_security_group" "app" {
name = "app-sg"
@@ -118,7 +118,7 @@ resource "aws_security_group" "app" {
}
}
# 錯誤:對網際網路開放
# FAIL: 錯誤:對網際網路開放
resource "aws_security_group" "bad" {
ingress {
from_port = 0
@@ -142,7 +142,7 @@ resource "aws_security_group" "bad" {
#### CloudWatch/日誌設定
```typescript
// 正確:全面日誌記錄
// PASS: 正確:全面日誌記錄
import { CloudWatchLogsClient, CreateLogStreamCommand } from '@aws-sdk/client-cloudwatch-logs';
const logSecurityEvent = async (event: SecurityEvent) => {
@@ -177,7 +177,7 @@ const logSecurityEvent = async (event: SecurityEvent) => {
#### 安全管線設定
```yaml
# 正確:安全的 GitHub Actions 工作流程
# PASS: 正確:安全的 GitHub Actions 工作流程
name: Deploy
on:
@@ -237,7 +237,7 @@ jobs:
#### Cloudflare 安全設定
```typescript
// 正確:帶安全標頭的 Cloudflare Workers
// PASS: 正確:帶安全標頭的 Cloudflare Workers
export default {
async fetch(request: Request): Promise<Response> {
const response = await fetch(request);
@@ -281,7 +281,7 @@ export default {
#### 自動備份
```terraform
# 正確:自動 RDS 備份
# PASS: 正確:自動 RDS 備份
resource "aws_db_instance" "main" {
allocated_storage = 20
engine = "postgres"
@@ -327,10 +327,10 @@ resource "aws_db_instance" "main" {
### S3 Bucket 暴露
```bash
# 錯誤:公開 bucket
# FAIL: 錯誤:公開 bucket
aws s3api put-bucket-acl --bucket my-bucket --acl public-read
# 正確:私有 bucket 並有特定存取
# PASS: 正確:私有 bucket 並有特定存取
aws s3api put-bucket-acl --bucket my-bucket --acl private
aws s3api put-bucket-policy --bucket my-bucket --policy file://policy.json
```
@@ -338,12 +338,12 @@ aws s3api put-bucket-policy --bucket my-bucket --policy file://policy.json
### RDS 公開存取
```terraform
# 錯誤
# FAIL: 錯誤
resource "aws_db_instance" "bad" {
publicly_accessible = true # 絕不這樣做!
}
# 正確
# PASS: 正確
resource "aws_db_instance" "good" {
publicly_accessible = false
vpc_security_group_ids = [aws_security_group.db.id]

View File

@@ -313,39 +313,39 @@ npm run test:coverage
## 常見測試錯誤避免
### 錯誤:測試實作細節
### FAIL: 錯誤:測試實作細節
```typescript
// 不要測試內部狀態
expect(component.state.count).toBe(5)
```
### 正確:測試使用者可見行為
### PASS: 正確:測試使用者可見行為
```typescript
// 測試使用者看到的內容
expect(screen.getByText('Count: 5')).toBeInTheDocument()
```
### 錯誤:脆弱的選擇器
### FAIL: 錯誤:脆弱的選擇器
```typescript
// 容易壞掉
await page.click('.css-class-xyz')
```
### 正確:語意選擇器
### PASS: 正確:語意選擇器
```typescript
// 對變更有彈性
await page.click('button:has-text("Submit")')
await page.click('[data-testid="submit-button"]')
```
### 錯誤:無測試隔離
### FAIL: 錯誤:無測試隔離
```typescript
// 測試互相依賴
test('creates user', () => { /* ... */ })
test('updates same user', () => { /* 依賴前一個測試 */ })
```
### 正確:獨立測試
### PASS: 正確:獨立測試
```typescript
// 每個測試設置自己的資料
test('creates user', () => {