Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b897bde
v2.18.8 (#271) (#272)
OnCloud125252 Mar 8, 2026
ba91a1a
feat: enhance version fetching and validation logic
HACO8888 Apr 6, 2026
75985b8
fix(providers): instantiate QueryClient per request to prevent memory…
OnCloud125252 Apr 7, 2026
ed4e0a2
fix(layout): move md-editor-rt config out of Server Component
OnCloud125252 Apr 7, 2026
6a816b0
fix(api): remove unused sweetalert2 import and handle webhook promise
OnCloud125252 Apr 7, 2026
1bc245d
docs: restructure agent guide and extract topic docs
OnCloud125252 Apr 7, 2026
9552f8a
docs: rewrite README with user-facing content
OnCloud125252 Apr 7, 2026
28138c6
chore(config): rename lint to check script and use Node.js built-in s…
OnCloud125252 Apr 7, 2026
0aabb01
fix(hooks): correct useEffect dependency arrays
OnCloud125252 Apr 7, 2026
730c4d7
refactor: apply biome code style fixes across codebase
OnCloud125252 Apr 7, 2026
54f8cc0
chore: add Claude-related files to .gitignore
OnCloud125252 Apr 7, 2026
ee2ffd9
refactor: extract shared utilities and remove dead code
OnCloud125252 Apr 7, 2026
0549bb7
chore(biome): upgrade to 2.3.13 and expand lint rules
OnCloud125252 Apr 7, 2026
9cbc9c8
docs(agents): replace env vars with Biome code style rules
OnCloud125252 Apr 7, 2026
a87ab62
style: apply new Biome lint rules across codebase
OnCloud125252 Apr 7, 2026
c381aef
fix(types): tighten nullability in ThreadInfo and ThreadsList
OnCloud125252 Apr 7, 2026
ba8d27f
chore(git): add pre-push hook to enforce quality checks
OnCloud125252 Apr 7, 2026
d45d31d
chore(git): add post-merge hook to sync dependencies after pull
OnCloud125252 Apr 7, 2026
702e589
chore(hooks): add security scans and smart triggers to git hooks
OnCloud125252 Apr 7, 2026
b6ae125
chore(prepare): replace prepare script with .env.local bootstrapping
OnCloud125252 Apr 7, 2026
148fb08
fix(edit): unwrap async params with React.use() for Next.js 15
OnCloud125252 Apr 7, 2026
203371b
refactor: remove dead code and unused modules
OnCloud125252 Apr 7, 2026
b5e3830
style(a11y): add prefers-reduced-motion media query
OnCloud125252 Apr 7, 2026
3601dc1
chore(hooks): remove redundant console.log check from pre-push hook
OnCloud125252 Apr 7, 2026
61ef2f8
fix: address review feedback from PR #273
OnCloud125252 Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ NEXTAUTH_URL=
NEXTAUTH_SECRET=

# GitHub token that have read access to MingdaoSIG-Frontend repo
NEXT_PUBLIC_GITHUB_TOKEN=
GITHUB_TOKEN=

# Discord webhook URL for displaying login log
NEXT_PUBLIC_WEBHOOK_LOGIN=

# Local Only
# NODE_ENV=development,no-strict

# Production Only
# FORCE_CONTAINERIZED=1
# NODE_OPTIONS=--max-old-space-size=512
118 changes: 118 additions & 0 deletions .githooks/post-merge
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env bash

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# MDSIG Frontend — Post-Merge Hook
# Syncs deps, cleans stale caches, and notifies about env changes.
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

# Colors
_CLI_GREEN='\033[0;32m'
_CLI_YELLOW='\033[0;33m'
_CLI_CYAN='\033[0;36m'
_CLI_PURPLE='\033[0;35m'
_CLI_RED='\033[0;31m'
_CLI_BLUE='\033[0;34m'
_CLI_GRAY='\033[0;90m'
_CLI_NC='\033[0m'

# Symbols
_CLI_CHECK="${_CLI_GREEN}[✓]${_CLI_NC}"
_CLI_CROSS="${_CLI_RED}[✗]${_CLI_NC}"
_CLI_WARN="${_CLI_YELLOW}[!]${_CLI_NC}"
_CLI_INFO="${_CLI_CYAN}[i]${_CLI_NC}"

# Helpers
log_info() { echo -e "$_CLI_INFO $1"; }
log_success() { echo -e "$_CLI_CHECK $1"; }
log_warn() { echo -e "$_CLI_WARN $1"; }
log_error() { echo -e "$_CLI_CROSS $1"; }

print_divider() {
local color="${1:-$_CLI_PURPLE}" label="${2:-}"
local width="${COLUMNS:-$(tput cols 2>/dev/null || echo 80)}"
if [[ -n "$label" ]]; then
local padding=$((width - ${#label} - 6))
local fill
printf -v fill '%*s' "$padding" ''
printf '%b━━━━[%s]%s%b\n' "$color" "$label" "${fill// /━}" "$_CLI_NC"
else
local fill
printf -v fill '%*s' "$width" ''
printf '%b%s%b\n' "$color" "${fill// /━}" "$_CLI_NC"
fi
}

# Get list of files changed in this merge
changed_files() {
git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD 2>/dev/null
}

# ── Main ──────────────────────────────────────────────────────────

echo ""
print_divider "$_CLI_PURPLE" "Post-Merge"
echo ""

CHANGED=$(changed_files)

# 1. Run pnpm install only if lockfile changed
if echo "$CHANGED" | grep -qE "(pnpm-lock\.yaml|package\.json)"; then
log_info "Dependencies changed — running ${_CLI_CYAN}pnpm install${_CLI_NC}..."
if pnpm install; then
echo ""
log_success "Dependencies updated"
else
echo ""
log_error "pnpm install failed — run it manually"
fi
else
log_success "Dependencies unchanged — skipping install"
fi

echo ""

# 2. Clean .next cache when next.config.js changed
if echo "$CHANGED" | grep -qE "next\.config\.(js|mjs|ts)"; then
log_warn "next.config changed — cleaning ${_CLI_BLUE}.next${_CLI_NC} cache..."
if [[ -d ".next" ]]; then
rm -rf .next
log_success "Cleared ${_CLI_BLUE}.next${_CLI_NC} cache"
log_info "Run ${_CLI_CYAN}pnpm dev${_CLI_NC} or ${_CLI_CYAN}pnpm build${_CLI_NC} to rebuild"
else
log_info "No .next cache to clean"
fi
echo ""
fi

# 3. Notify when .env.local.example changed
if echo "$CHANGED" | grep -q ".env.local.example"; then
echo ""
print_divider "$_CLI_YELLOW" "Environment Update Required"
echo ""
log_warn "The ${_CLI_BLUE}.env.local.example${_CLI_NC} file was updated!"
echo ""
log_info "Review the changes and update your local ${_CLI_BLUE}.env.local${_CLI_NC}:"
echo ""
echo -e " ${_CLI_CYAN}git diff ORIG_HEAD HEAD -- .env.local.example${_CLI_NC}"
echo ""
# Show the actual diff inline for convenience
diff_output=$(git diff ORIG_HEAD HEAD -- .env.local.example 2>/dev/null)
if [[ -n "$diff_output" ]]; then
log_info "Changes:"
echo ""
echo "$diff_output" | while IFS= read -r line; do
if [[ "$line" == +* && "$line" != "+++"* ]]; then
echo -e " ${_CLI_GREEN}${line}${_CLI_NC}"
elif [[ "$line" == -* && "$line" != "---"* ]]; then
echo -e " ${_CLI_RED}${line}${_CLI_NC}"
fi
done
echo ""
fi
print_divider "$_CLI_YELLOW"
echo ""
fi

echo ""
print_divider "$_CLI_PURPLE"
echo ""
167 changes: 167 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#!/usr/bin/env bash

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# MDSIG Frontend — Pre-Push Hook
# Runs security scans, lint/format, type-check, and build before pushing.
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

TOTAL_STEPS=8
BUNDLE_SIZE_LIMIT_MB=50

# Colors
_CLI_RED='\033[0;31m'
_CLI_GREEN='\033[0;32m'
_CLI_YELLOW='\033[0;33m'
_CLI_BLUE='\033[0;34m'
_CLI_PURPLE='\033[0;35m'
_CLI_CYAN='\033[0;36m'
_CLI_GRAY='\033[0;90m'
_CLI_NC='\033[0m'

# Symbols
_CLI_CHECK="${_CLI_GREEN}[✓]${_CLI_NC}"
_CLI_CROSS="${_CLI_RED}[✗]${_CLI_NC}"
_CLI_WARN="${_CLI_YELLOW}[!]${_CLI_NC}"
_CLI_INFO="${_CLI_CYAN}[i]${_CLI_NC}"

# Helpers
log_info() { echo -e "$_CLI_INFO $1"; }
log_success() { echo -e "$_CLI_CHECK $1"; }
log_warn() { echo -e "$_CLI_WARN $1"; }
log_error() { echo -e "$_CLI_CROSS $1"; }

print_divider() {
local color="${1:-$_CLI_PURPLE}" label="${2:-}"
local width="${COLUMNS:-$(tput cols 2>/dev/null || echo 80)}"
if [[ -n "$label" ]]; then
local padding=$((width - ${#label} - 6))
local fill
printf -v fill '%*s' "$padding" ''
printf '%b━━━━[%s]%s%b\n' "$color" "$label" "${fill// /━}" "$_CLI_NC"
else
local fill
printf -v fill '%*s' "$width" ''
printf '%b%s%b\n' "$color" "${fill// /━}" "$_CLI_NC"
fi
}

run_step() {
local step_num="$1"
local step_name="$2"
local step_cmd="$3"

log_info "${_CLI_GRAY}[${step_num}/${TOTAL_STEPS}]${_CLI_NC} Running ${_CLI_CYAN}${step_name}${_CLI_NC}..."

if eval "$step_cmd"; then
log_success "${_CLI_GRAY}[${step_num}/${TOTAL_STEPS}]${_CLI_NC} ${step_name}"
return 0
else
echo ""
log_error "${_CLI_GRAY}[${step_num}/${TOTAL_STEPS}]${_CLI_NC} ${step_name} ${_CLI_RED}failed${_CLI_NC}"
echo ""
log_info "Fix the errors above, then try pushing again."
echo ""
print_divider "$_CLI_RED"
echo ""
return 1
fi
}

# ── Check Functions ───────────────────────────────────────────────

check_env_secrets() {
local failed=0

# Check for .env files being pushed
local env_files
env_files=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E '\.env(\..*)?\.local$' || true)
if [[ -z "$env_files" ]]; then
env_files=$(git diff origin/HEAD --name-only --diff-filter=ACM 2>/dev/null | grep -E '\.env(\..*)?\.local$' || true)
fi

if [[ -n "$env_files" ]]; then
echo ""
log_error "Secret files detected in changes:"
while IFS= read -r f; do
echo -e " ${_CLI_RED}✗${_CLI_NC} $f"
done <<< "$env_files"
echo ""
log_info "Add these to ${_CLI_CYAN}.gitignore${_CLI_NC} or unstage them."
failed=1
fi

# Grep source files for hardcoded secret patterns
local secret_patterns='(GOOGLE_CLIENT_SECRET|NEXTAUTH_SECRET|GITHUB_TOKEN|NEXT_PUBLIC_WEBHOOK_LOGIN|DISCORD_WEBHOOK)\s*=\s*["\x27][^"\x27]{8,}'
local hits
hits=$(git diff origin/HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' 2>/dev/null \
| grep -E '^\+' \
| grep -iE "$secret_patterns" || true)

if [[ -n "$hits" ]]; then
echo ""
log_error "Possible hardcoded secrets in diff:"
echo -e " ${_CLI_GRAY}${hits}${_CLI_NC}"
failed=1
fi

return $failed
}

check_bundle_size() {
if [[ ! -d ".next" ]]; then
log_warn "No .next directory found — skipping bundle size check"
return 0
fi

local size_kb
size_kb=$(du -sk .next 2>/dev/null | cut -f1)
local size_mb=$(( size_kb / 1024 ))
local limit_kb=$(( BUNDLE_SIZE_LIMIT_MB * 1024 ))

if [[ "$size_kb" -gt "$limit_kb" ]]; then
echo ""
log_error "Bundle size ${_CLI_RED}${size_mb}MB${_CLI_NC} exceeds limit of ${_CLI_CYAN}${BUNDLE_SIZE_LIMIT_MB}MB${_CLI_NC}"
echo ""
log_info "Check for large imports or unoptimized assets."
return 1
fi

log_info " Bundle size: ${_CLI_CYAN}${size_mb}MB${_CLI_NC} ${_CLI_GRAY}(limit: ${BUNDLE_SIZE_LIMIT_MB}MB)${_CLI_NC}"
return 0
}

# ── Main ──────────────────────────────────────────────────────────

echo ""
print_divider "$_CLI_PURPLE" "Pre-Push Checks"
echo ""
log_info "Verifying codebase before push..."
echo ""

# 1. Secret detection with gitleaks
if command -v gitleaks &> /dev/null; then
run_step 1 "gitleaks (secret scan)" "gitleaks protect --staged --verbose" || exit 1
else
log_warn "${_CLI_GRAY}[1/${TOTAL_STEPS}]${_CLI_NC} gitleaks not installed — skipping"
log_info "Install with: ${_CLI_CYAN}brew install gitleaks${_CLI_NC}"
echo ""
fi

# 2. Check for .env secrets in staged files
run_step 2 "env secrets check" "check_env_secrets" || exit 1

# 3–7. Install, lint, type-check, build
run_step 3 "pnpm install" "pnpm install" || exit 1
run_step 4 "pnpm run check:fix" "pnpm run check:fix" || exit 1
run_step 5 "pnpm run check:fix-unsafe" "pnpm run check:fix-unsafe" || exit 1
run_step 6 "pnpm run types" "pnpm run types" || exit 1
run_step 7 "pnpm build" "pnpm build" || exit 1

# 8. Bundle size check (after build)
run_step 8 "bundle size check" "check_bundle_size" || exit 1

echo ""
log_success "All pre-push checks passed"
echo ""
print_divider "$_CLI_PURPLE"
echo ""
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ next-env.d.ts
# Other Package Manager (Remove if needed, just one PM one time)
bun.lockb
package-lock.json

/.claude/worktrees
/.claude/.recent_work_last_update
/.claude/RECENT_WORK.md
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
"[xml]": {
"editor.defaultFormatter": "redhat.vscode-xml"
},
"css.lint.unknownAtRules": "ignore",
"css.lint.unknownAtRules": "ignore"
}
59 changes: 59 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# MDSIG Frontend — Agent Guide

MDSIG is a community sharing platform for Mingdao High School students and teachers to exchange ideas and insights.

## Commands

```bash
pnpm install # Install dependencies
pnpm dev # Dev server (DO NOT use for build verification)
pnpm build # Production build (USE THIS for build verification)
pnpm types # Type check only (no emit)
pnpm check:fix # Biome auto-fix (safe fixes only)
```

## Code Style Rules (Biome)

Run `pnpm check` after every change. All generated code **must** follow these rules (enforced by Biome via `biome.json`):

### Formatting

- Use **2 spaces** for indentation, never tabs
- Keep lines within **80 characters**
- Always end statements with a **semicolon**
- Use **double quotes** for strings and JSX attributes
- Always include **trailing commas** in JS/TS (but never in JSON)
- Always wrap arrow function parameters in **parentheses**: `(x) => x`
- Include spaces inside braces: `{ value }`

### Code You Must Write

- Always use **block statements** (`{}`) with `if`, `else`, `for`, `while` — no single-line bodies
- Use **`for...of`** instead of `.forEach()` for iteration
- Use **`console.error`**, **`console.warn`**, **`console.info`**, or **`console.assert`** only — never bare `console.log`
- Keep Tailwind CSS class names **sorted** (Biome enforces `useSortedClasses`)

### Code You Must Avoid

- Do NOT leave **unused imports** or **unused variables** — remove them
- Do NOT use **array index as React key** when a stable identifier is available
- Do NOT leave **empty block statements** (`{}`) — add a comment or remove the block
- Do NOT write **`else` after `return`/`break`/`continue`** — use early return instead
- Avoid **`any`** type — use a specific type whenever possible

### Rules That Are NOT Enforced

These rules are intentionally **off** — do not "fix" code to satisfy them:

- `useImportType` — using `import` instead of `import type` is fine
- `useExhaustiveDependencies` — React hook dependency arrays are not auto-checked
- `noInferrableTypes` — explicit type annotations on inferred values are allowed
- `noStaticElementInteractions`, `noSvgWithoutTitle`, `useKeyWithClickEvents` — a11y rules are off

## Docs

- [Architecture & project structure](docs/architecture.md)
- [API patterns & authentication](docs/api.md)
- [Code style & naming conventions](docs/code-style.md)
- [TypeScript interfaces & permissions](docs/data-types.md)
- [Feature implementation details](docs/features.md)
1 change: 1 addition & 0 deletions CLAUDE.md
1 change: 1 addition & 0 deletions GEMINI.md
Loading
Loading