Communitygithub.com

포트폴리오 출고 — Feishu 베이스 → GitHub Pages + Actions

Feishu 다차원 테이블로 GitHub Pages 포트폴리오를 생성·게시하고 Actions로 임시 미디어 링크를 주기 갱신. 소재가 Feishu에 있는 크리에이터용(블로그/이커머스/쓰기 백엔드 비권장).

포트폴리오 출고 — Feishu 베이스 → GitHub Pages + Actions란 무엇인가요?

Personal websites 3단계(ship): feishu-portfolio-launch. Feishu SSOT → 생성 사이트 → Pages + 예약 링크 갱신.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add Jane-xiaoer/feishu-portfolio-launch

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Feishu Portfolio Launch

이 Skill의 기능

한 마디로 말하면: Feishu 다차원 테이블 링크를 주면, 포트폴리오 웹사이트를 구축하고 'Feishu 임시 링크 만료' 문제를 자동화하여 처리합니다.

기본 인도물:

  • index.html 또는 정적 프론트엔드 페이지
  • api/videos.json
  • api/covers.json
  • api/portfolio.json
  • refresh.py
  • .github/workflows/refresh.yml
  • 애니메이션이 적용된 프론트엔드 상호작용 레이어 (CSS / JS / Canvas / Three.js 모두 가능)

내장 템플릿 리소스:

목표 결과:

  • GitHub Pages에 웹사이트 배포
  • Feishu 미디어 링크는 GitHub Actions에 의해 12시간마다 자동으로 새로고침
  • 사용자가 자신의 컴퓨터를 켜둘 필요 없음
  • 페이지는 단순 정적 레이아웃이 아니며, 최소한 완전한 진입 / 스크롤 / 호버 / 페이지 전환 애니메이션 세트를 갖춤

적용 시나리오

✅ 적합:

  • AI 비디오 / 이미지 포트폴리오
  • 사진, 디자인, 크리에이티브 샘플 라이브러리
  • 고객 사례 소개 사이트
  • '콘텐츠는 Feishu 첨부 파일에 있고, 프론트엔드는 표시만 담당'하는 모든 시나리오

❌ 부적합:

  • 텍스트/이미지 블로그
  • 전자상거래, 결제, 로그인 시스템
  • 데이터베이스 쓰기 및 백엔드 비즈니스 로직이 필요한 웹사이트

핵심 원칙

Feishu 임시 URL을 영구 리소스로 간주하지 마십시오.

Feishu 첨부 파일의 재생/다운로드 주소는 만료됩니다. 올바른 방법은 사용자가 로컬 컴퓨터에서 정기적으로 스크립트를 실행하도록 하는 것이 아니라:

  1. Feishu 다차원 테이블에서 최신 레코드 읽기
  2. Feishu API를 호출하여 첨부 파일의 file_token을 임시 URL로 변환
  3. api/*.json 생성
  4. GitHub 저장소에 커밋
  5. GitHub Pages가 자동으로 다시 배포하도록 함

즉:

Feishu Bitable -> refresh.py -> api/*.json -> GitHub Pages


실행 흐름

Step 0: 환경 확인

먼저 로컬에 초기화에 필요한 도구가 있는지 확인합니다:

for cmd in node python3 gh git; do
  which "$cmd" >/dev/null 2>&1 && echo "OK  $cmd" || echo "MISS $cmd"
done
lark-cli --version >/dev/null 2>&1 && echo "OK  lark-cli" || echo "MISS lark-cli"
gh auth status >/dev/null 2>&1 && echo "OK  GitHub auth" || echo "MISS GitHub auth"

도구가 없으면 사용자에게 설치를 요청합니다. gh가 로그인되지 않았으면 먼저 GitHub 로그인을 완료합니다.


Step 1: Feishu Base와 올바른 데이터 테이블 찾기

사용자에게 Feishu 다차원 테이블 링크를 요청합니다. 예:

https://my.feishu.cn/base/AbCdEfGhIjk

URL에서 app_token을 추출합니다.

그런 다음 모든 테이블을 나열합니다:

lark-cli api GET "/open-apis/bitable/v1/apps/${APP_TOKEN}/tables"

기본적으로 첫 번째 테이블을 선택하지 마십시오. 많은 Base에는 '빈 템플릿 테이블'과 '실제 작품이 있는 자료 테이블'이 동시에 존재할 수 있습니다. 계속 레코드를 읽고 확인해야 합니다:

  • 어떤 테이블에 실제 첨부 파일 필드가 있는가
  • 어떤 테이블의 레코드 수가 올바른가
  • 어떤 테이블의 필드 이름이 사용자가 표시하려는 콘텐츠인가

다음 필드를 우선적으로 찾습니다:

  • 비디오 필드: 샘플 / 비디오 / 첨부 파일
  • 커버 필드: 커버 / 커버 이미지 / 포스터 / 이미지
  • 제목 필드: 내용 / 제목 / 작품 이름
  • 카테고리 필드: 유형 / 카테고리
  • 길이 필드: 길이
  • 도구 필드: AI 도구 / 도구
  • 정렬 필드: 순서

어떤 테이블에 텍스트 / 단일 선택 / 날짜 / 첨부 파일과 같은 빈 템플릿 필드만 있으면 계속 테이블을 바꾸고 웹사이트를 생성하지 마십시오.


Step 2: Feishu 권한 확인

GitHub Actions가 자동으로 새로고침하려면 Feishu 앱이 최소한 다음 작업을 수행할 수 있어야 합니다:

  • 다차원 테이블 레코드 읽기
  • 첨부 파일 미디어 링크 읽기

실행 계획에서 다음 4개의 secrets에 명시적으로 의존해야 합니다:

  • LARK_APP_ID
  • LARK_APP_SECRET
  • LARK_BASE_TOKEN
  • LARK_TABLE_ID

사용자 로컬에 이미 사용 가능한 Feishu 앱 구성이 있으면 재사용할 수 있습니다. 그렇지 않으면 사용자에게 Feishu Open Platform에서 권한과 키를 추가하도록 명확히 알려야 합니다.


Step 3: 구조화된 작품 데이터 내보내기

file_token 목록만 추출하지 마십시오. 프론트엔드에서 직접 사용할 수 있는 구조화된 데이터를 구축해야 하며, 최소한 다음을 포함합니다:

  • title
  • categories
  • duration
  • tools
  • order
  • video_token
  • cover_token

권장 출력:

  • api/portfolio.json: 전체 작품 배열
  • api/videos.json: video_token -> tmp_download_url
  • api/covers.json: cover_token -> tmp_download_url

구조 샘플은 저장소 내 assets/portfolio.sample.json을 직접 참조할 수 있습니다.

프론트엔드는 계속 정적 HTML + JS를 사용하거나 portfolio.json으로 완전히 렌더링할 수 있습니다.


Step 4: 프론트엔드 페이지 생성

기본적으로 정적 페이지를 생성하며, 다음을 요구합니다:

  • 반응형 작품 그리드
  • 카테고리 필터링
  • 카드 클릭 시 재생
  • 전체 화면 확대 재생
  • 한 번에 하나의 비디오만 재생 허용
  • 커버는 Feishu 커버 필드를 우선 사용하고, 커버가 없으면 poster 없이 폴백 허용

애니메이션 효과는 기본적으로 함께 제공되어야 하며, 단순히 '열 수 있는' 정적 페이지만 제공하지 마십시오:

  • 첫 화면에는 최소한 하나의 진입 애니메이션 세트가 있어야 합니다. 예: 제목, 설명, 통계 숫자가 fade-up으로 순차적으로 나타남
  • 내비게이션은 스크롤 후 blur / background / border 변경을 허용
  • 카드 hover에는 최소한 한 가지 가벼운 피드백이 있어야 합니다. 예: 떠오름, 확대, 오버레이, 제목 색상 변경
  • 페이지 전환 또는 섹션 전환에는 트랜지션이 있어야 하며, 갑작스러운 깜빡임 전환 금지
  • About / 연락처 / 기술 모듈과 같은 정보 영역에는 scroll reveal을 우선 추가
  • 사용자가 더 강력한 시각적 표현을 원하면 Canvas 또는 Three.js 배경 애니메이션을 추가할 수 있음

구현 경계:

  • 기본 CSS transition / keyframes / IntersectionObserver를 우선 사용
  • 지속적인 움직임 배경이 필요할 때만 requestAnimationFrame 사용
  • Three.js를 사용하는 경우 모바일에서 빈 화면, 멈춤 또는 주요 콘텐츠 가림이 발생하지 않도록 해야 함
  • 애니메이션은 비디오 재생, 필터링, 팝업, 모바일 스크롤 및 첫 화면 가독성에 영향을 주지 않음
  • 기본적으로 폴백 경로를 제공하여 스크립트가 실패해도 텍스트와 콘텐츠가 계속 보임

데이터 바인딩 원칙:

  • HTML에 만료된 URL을 하드코딩하지 마십시오
  • 페이지 런타임에 /api/videos.json 및 /api/covers.json 가져오기
  • 또는 직접 /api/portfolio.json을 가져와 카드 렌더링

사용자가 기존 사이트를 가지고 있으면 기존 시각적 스타일을 우선 유지하고 데이터 소스와 새로고침 메커니즘만 교체합니다.

사용자가 명시적으로 기존 사이트 스타일을 참조한다면, 다음 애니메이션 유형을 우선 재사용합니다:

  • hero 텍스트 진입
  • sticky filter / nav의 스크롤 상태 전환
  • masonry 카드 hover 애니메이션
  • 페이지 fade-in/fade-out 전환
  • About 페이지의 stagger reveal
  • 선택적 Three.js / Canvas 배경 움직임

Step 5: 저장소 생성 및 GitHub Pages 배포

표준 절차:

gh repo create <repo-name> --public --source=. --remote=origin --push

그런 다음 Pages 소스를 확인합니다:

  • branch: main
  • path: /

확인:

gh api repos/<owner>/<repo>/pages

반드시 확인해야 할 사항:

  • Pages가 활성화되었는가
  • cname이 정상적인가 (사용자 정의 도메인이 있는 경우)
  • source가 main과 루트 디렉토리를 가리키는가

Step 6: 자동 새로고침 스크립트 생성

새로고침 스크립트는 다음 경로를 따라야 합니다:

  1. app_id + app_secret으로 tenant_access_token 요청
  2. Bitable records 읽기
  3. 레코드에서 비디오 및 커버 첨부 파일 token 추출
  4. batch_get_tmp_download_url 일괄 호출
  5. api/videos.json, api/covers.json, api/portfolio.json에 쓰기

핵심 요구 사항:

  • 페이징된 records 읽기 지원
  • 배치 요청은 5개의 token을 그룹으로 처리
  • token 목록을 스크립트에 하드코딩하지 마십시오
  • 실제 테이블 레코드에서 동적으로 생성하는 것을 우선
  • 여러 필드 이름 후보 허용

권장 파일 이름:

  • refresh.py

skill에 내장된 템플릿을 직접 복사하는 것을 우선:

cp ~/.claude/skills/feishu-portfolio-launch/assets/refresh.py ./refresh.py

그런 다음 필드 후보 배열만 수정하고, 구체적인 token이나 URL을 하드코딩하지 마십시오.


Step 7: GitHub Actions Workflow 생성

더 이상 로컬 launchd를 기본 솔루션으로 사용하지 마십시오. 기본 솔루션은 GitHub Actions여야 합니다.

워크플로 요구 사항:

  • workflow_dispatch 지원
  • schedule 지원, 기본적으로 12시간마다 실행
  • python refresh.py 실행
  • api/videos.json, api/covers.json, api/portfolio.json 자동 커밋

표준 secrets:

  • LARK_APP_ID
  • LARK_APP_SECRET
  • LARK_BASE_TOKEN
  • LARK_TABLE_ID

표준 파일:

  • .github/workflows/refresh.yml

skill에 내장된 템플릿을 직접 복사하는 것을 우선:

mkdir -p .github/workflows
cp ~/.claude/skills/feishu-portfolio-launch/assets/refresh.yml .github/workflows/refresh.yml

Step 8: Secrets를 저장소에 구성

현재 환경에 이러한 값이 있고 사용자가 명시적으로 적용을 요청하면 직접 구성합니다:

gh secret set LARK_APP_ID -R <owner>/<repo>
gh secret set LARK_APP_SECRET -R <owner>/<repo>
gh secret set LARK_BASE_TOKEN -R <owner>/<repo>
gh secret set LARK_TABLE_ID -R <owner>/<repo>

그런 다음 확인:

gh secret list -R <owner>/<repo>

값이 누락되면 여기서 멈추고 사용자에게 어떤 값이 누락되었는지 명확히 알리며, 위조하지 마십시오.


Step 9: 수동 트리거 및 전체 체인 확인

구성이 완료되면 즉시 수동으로 workflow를 한 번 실행합니다:

gh workflow run refresh.yml -R <owner>/<repo>
gh run list -R <owner>/<repo> --limit 3
gh run watch <run-id> -R <owner>/<repo> --exit-status

그런 다음 온라인 결과를 확인합니다:

python3 - <<'PY'
import json, urllib.request, time
url = f'https://<domain-or-pages-url>/api/videos.json?t={int(time.time())}'
with urllib.request.urlopen(url, timeout=20) as r:
    data = json.load(r)
print(data.get('_refreshed_at'))
print(data.get('_count'))
PY

그런 다음 1개의 비디오를 샘플링하여 확인:

  • 상태 코드는 206 또는 200이어야 함
  • content-type은 video/mp4 또는 재생 가능한 미디어 유형이어야 함

온라인 api/videos.json이 여전히 이전 시간인 경우:

  • 먼저 Pages 배포가 완료되었는지 확인
  • 그런 다음 workflow가 실제로 새 JSON을 커밋했는지 확인
  • 마지막으로 Pages source가 올바른 브랜치와 디렉토리를 가리키는지 확인

Step 10: 도메인 바인딩

사용자가 사용자 정의 도메인을 원하는 경우:

  • CNAME 파일
  • GitHub Pages 사용자 정의 도메인 설정
  • DNS 구성 안내

이 부분은 GitHub Pages 표준 절차를 따르며 Feishu 로직과 결합할 필요가 없습니다.


사용자를 위한 기본 설명

'웹사이트는 열리지만 비디오가 재생되지 않는' 경우, 우선 판단:

  1. api/videos.json이 여전히 오래된 것인가
  2. 내부 Feishu URL이 이미 만료되었는가
  3. 자동 새로고침 workflow가 실패했는가
  4. Pages가 아직 다시 배포되지 않았는가

기본적으로 플레이어나 프론트엔드 스타일을 먼저 의심하지 마십시오.

사용자가 '페이지가 너무 딱딱하다' 또는 '포트폴리오처럼 더 생동감 있게'라고 말하면, 기본적으로 기본으로 색상과 레이아웃만 변경하지 말고 애니메이션 레이어를 추가합니다.


성공 기준

이 Skill이 완료되면 최소한 다음을 충족해야 합니다:

  • 웹사이트가 온라인 상태
  • GitHub Pages에 접근 가능
  • 비디오 재생 가능
  • 저장소에 자동 새로고침 workflow가 있음
  • 저장소에 4개의 LARK_* secrets가 있음
  • 수동 트리거 workflow 성공
  • 온라인 api/videos.json의 _refreshed_at이 새로운 시간임

더 이상 기본적으로 하지 말아야 할 것

  • 기본적으로 로컬 launchd를 생성하지 마십시오
  • 기본적으로 사용자 Mac이 항상 켜져 있다고 가정하지 마십시오
  • 모든 file_token을 하드코딩하지 마십시오
  • 첫 번째 테이블만 보고 계속 진행하지 마십시오
  • videos.json만 생성하고 커버와 구조화된 레코드를 무시하지 마십시오

참조 구현

이미 검증된 방법이 필요하면, 먼저 skill 저장소의 내장 템플릿을 직접 재사용하십시오:

  • assets/refresh.py
  • assets/refresh.yml
  • assets/portfolio.sample.json

실제 프로젝트에서는 결국 다음 파일이 생성됩니다:

  • refresh.py
  • .github/workflows/refresh.yml
  • api/videos.json
  • api/covers.json
  • api/portfolio.json

기존 저장소 패턴을 우선 재사용한 다음 사용자 사이트 스타일에 맞게 조정하십시오.

관련 스킬