TreeMap
무료 오픈소스 디스크 사용량 시각화 도구로, 사각형 트리맵·중복 파일 탐색·디스크 가득 예측·정리 시 파일을 휴지통으로만 이동한다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기FollowUp 프론트엔드 — 회의록 AI 분석 기반 후속 업무 관리 (React + Vite + TypeScript)
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
회의록을 넣으면 AI가 결정 사항과 후속 업무를 추출하고, 다음 회의까지 이어서 관리하는 서비스의 프론트엔드입니다. • 스택: React 18 · TypeScript · Vite · Tailwind CSS · React Router · TanStack Query · React Hook Form · Zod · Axios · Recharts · dayjs • 디자인: Cal.com 디자인 시스템 토큰 (tailwind.config.js 에 전부 정의) • 백엔드: Spring Boot (AWS EC2 + RDS), OpenAPI 문서 /swagger-ui/index.html VS Code 에서 이 폴더를 열고 터미널에서 한 줄씩 실행하세요. 브라우저에서 http://localhost:3000 을 엽니다. 테스트 계정은 로그인 화면의 테스트 계정 채우기 버튼으로 채울 수 있습니다. lint 는 tsc --noEmit 타입 검사입니다. 백엔드는 http 이고 CORS 가 열려 있지 않습니다. 그래서 브라우저에서 백엔드를 직접 호출하면 두 가지 이유로 막힙니다.README 전문 보기 ↗
회의록을 넣으면 AI가 결정 사항과 후속 업무를 추출하고, 다음 회의까지 이어서 관리하는 서비스의 프론트엔드입니다.
tailwind.config.js 에 전부 정의)<백엔드 주소>/swagger-ui/index.htmlVS Code 에서 이 폴더를 열고 터미널에서 한 줄씩 실행하세요.
npm install
npm run dev
브라우저에서 http://localhost:3000 을 엽니다.
테스트 계정은 로그인 화면의 테스트 계정 채우기 버튼으로 채울 수 있습니다.
| 항목 | 값 |
|---|---|
| 이메일 | [email protected] |
| 비밀번호 | 1111qqqq! |
npm run build
npm run preview
npm run lint
lint 는 tsc --noEmit 타입 검사입니다.
백엔드는 http 이고 CORS 가 열려 있지 않습니다. 그래서 브라우저에서 백엔드를 직접 호출하면 두 가지 이유로 막힙니다.
OPTIONS /api/projects → 403 Invalid CORS request)그래서 이 프로젝트는 항상 같은 오리진으로 /api/... 를 호출하고, 프록시가 백엔드로 넘겨주는 구조를 씁니다.
[브라우저] --/api/...--> [Vite dev server 또는 Vercel 프록시 함수] --> [<백엔드 주소>/api/...]
| 환경 | 프록시 설정 위치 |
|---|---|
| 로컬 개발 | vite.config.ts 의 server.proxy |
| Vercel 배포 | api/proxy.ts (Vercel Function) + vercel.json 의 rewrite |
로컬은 .env 의 VITE_DEV_PROXY_TARGET, 배포는 Vercel 환경변수 BACKEND_ORIGIN 을 봅니다.
백엔드 주소는 저장소에 두지 않습니다. 주소가 바뀌면 배포는 Vercel 환경변수만 고치고 재배포하면 되고,
코드 변경은 필요 없습니다.
vercel.json의 rewrite destination 은 환경변수 보간을 지원하지 않습니다. 그래서 rewrite 로 주소를 직접 적는 대신, 런타임에process.env.BACKEND_ORIGIN을 읽는 프록시 함수(api/proxy.ts)를 두었습니다.
프록시가 Origin / Referer 를 떼어내는 것도 중요합니다. 서버 대 서버 호출에는 CORS 가 의미 없는데,
브라우저가 붙인 Origin 을 그대로 넘기면 백엔드 CORS 필터가 403 Invalid CORS request 로 막습니다.
.env (.env.example 참고)
| 변수 | 기본값 | 설명 |
|---|---|---|
VITE_API_BASE_URL | (빈 값) | 비워 두면 같은 오리진(/api)으로 호출합니다. 백엔드가 https + CORS 를 지원하게 되면 여기에 백엔드 주소를 넣어 직접 호출할 수 있습니다. |
VITE_DEV_PROXY_TARGET | http://localhost:8080 | 로컬 dev server 가 /api 를 넘길 대상. 배포된 백엔드를 보려면 그 주소를 넣으세요. |
로컬 백엔드로 붙는 경우:
echo "VITE_DEV_PROXY_TARGET=http://localhost:8080" >> .env
accessToken 을 localStorage 에 저장하고, axios 요청 인터셉터가 Authorization: Bearer ... 를 붙입니다./api/auth/me 같은 엔드포인트가 없어서, JWT 의 sub 클레임에서 userId 를 읽습니다. (src/lib/auth.ts)GET /api/project/{id}/members)에서 내 userId 를 찾아 채웁니다. (src/features/projects/ProjectContext.tsx)src/api/client.ts)| 항목 | 값 |
|---|---|
| 배포 주소 | https://followup-frontend-pied.vercel.app |
| GitHub | FollowUp0907/followup-frontend (public) |
| Vercel | 팀 FollowUp / 프로젝트 followup-frontend |
| 배포 기준 브랜치 | main |
main 에 push 하면 Production 자동 배포, 그 외 브랜치·PR 은 Preview 자동 배포입니다.
주의:
followup-frontend.vercel.app은 다른 사람의 프로젝트입니다. 위-pied주소를 쓰세요.-follow-up7이 붙은 주소는 팀 보호(Vercel Authentication)가 걸려 외부에서 열리지 않습니다.
| 이름 | 값 | 비고 |
|---|---|---|
BACKEND_ORIGIN | 백엔드 오리진 (예: http://1.2.3.4:8080) | 필수. 프록시 함수가 읽습니다. VITE_ 접두사가 없어 번들에 포함되지 않습니다 |
VITE_API_BASE_URL | (비워 둠) | 채우면 프록시를 타지 않아 CORS·mixed content 에 막힙니다 |
VITE_GOOGLE_CLIENT_ID | (선택) | 비우면 구글 로그인 버튼이 표시되지 않습니다 |
백엔드 IP 가 바뀌면 BACKEND_ORIGIN 만 수정하고 재배포하면 됩니다. 코드 변경은 필요 없습니다.
(환경변수 변경은 재배포 시점에 반영됩니다. 재배포조차 없애려면 EC2 에 Elastic IP 를 붙이거나 도메인을 두세요.)
npx vercel --prod --scope follow-up7
https://<도메인>/api/health 가 {"status":"ok"} 면 프록시가 정상입니다.src/
├─ api/ API 호출을 리소스별로 한 곳에서 관리
│ ├─ client.ts axios 인스턴스, 토큰 주입, 에러 정규화
│ ├─ authApi.ts 회원가입 / 로그인 / health
│ ├─ projectApi.ts 프로젝트 + 프로젝트 멤버
│ ├─ meetingApi.ts 회의
│ ├─ actionItemApi.ts 후속 업무
│ ├─ aiApi.ts AI 분석 요청 / 조회 / 확정
│ └─ dashboardApi.ts 대시보드
├─ components/
│ ├─ ui/ 디자인 시스템 컴포넌트 (Button, Field, Card, Badge, Modal, Toast, NavPillGroup …)
│ └─ layout/ TopNav, Footer, AppShell, PageHeader, RouteGuards, ErrorBoundary
├─ features/ 도메인별 react-query 훅 + 컨텍스트
│ ├─ auth/ AuthContext (로그인 상태)
│ ├─ projects/ ProjectContext (프로젝트 · 멤버 · 권한 · 담당자 이름 매칭)
│ ├─ meetings/ actionItems/ analysis/ dashboard/ members/
├─ lib/ auth(JWT), date(dayjs), constants(라벨·색), queryKeys, cn
├─ pages/ 라우트 단위 화면
└─ types/api.ts 백엔드 DTO 타입 (OpenAPI 스펙 기준)
| 경로 | 화면 | 인증 |
|---|---|---|
/ | 랜딩 | — |
/login, /signup | 로그인 / 회원가입 | 비로그인만 |
/projects | 프로젝트 목록 · 생성 | 필요 |
/projects/:projectId | 프로젝트 대시보드 | 필요 |
/projects/:projectId/meetings | 회의 목록 | 필요 |
/projects/:projectId/meetings/new | 회의 생성 (참여자 · 이전 미완료 업무 연결 · 회의록) | 필요 |
/projects/:projectId/meetings/:meetingId | 회의 상세 (회의록 편집 · 결정 사항 · 생성된 업무) | 필요 |
/projects/:projectId/meetings/:meetingId/analysis | AI 분석 결과 검토 · 확정 | 필요 |
/projects/:projectId/tasks | 후속 업무 보드 / 목록 + 필터 | 필요 |
/projects/:projectId/tasks/:actionItemId | 업무 상세 · 수정 · 상태 변경 | 필요 |
/projects/:projectId/members | 구성원 조회 · 추가 · 제거 | 필요 |
/projects/:projectId/settings | 프로젝트 수정 · 삭제 | 필요 |
이 서비스의 핵심 화면입니다. src/pages/AnalysisPage.tsx
회의 상세에서 [AI 분석하기]
↓
POST /api/meeting/{meetingId}/analysis
├─ 201: 새 분석 생성 (status: PROCESSING)
└─ 200: 재사용 가능한 기존 분석 반환
↓
status 가 PROCESSING 인 동안 GET /api/analysis/{id} 를 2초 간격으로 폴링
↓
GENERATED → 초안을 편집 가능한 로컬 상태로 옮김
├─ AI 가 준 assigneeName(문자열)을 프로젝트 멤버 이름과 매칭해 userId 로 변환
│ (완전 일치 → 공백 제거 후 포함 관계 순으로 매칭, 실패하면 "담당자를 찾지 못했습니다" 경고)
├─ 항목 수정 / 추가 / 삭제
└─ 확정 전에는 서버에 아무것도 저장되지 않음
↓
POST /api/analysis/{id}/confirm ← 사용자가 확정한 값만 전송
↓
후속 업무 생성 → 업무 보드로 이동
FAILED 상태면 백엔드가 준 errorMessage 를 그대로 보여주고, 회의록 수정 / 다시 분석 두 가지 선택지를 줍니다. 실패해도 회의록은 그대로 남습니다.CONFIRMED 상태면 편집이 잠기고 읽기 전용으로 표시됩니다.GET /api/project/{id}/action-items 응답에 originMeetingId 가 없습니다. 그래서 "이 회의에서 생성된 후속 업무" 는 목록을 받은 뒤 상세를 각각 조회해 클라이언트에서 조인합니다. (src/features/actionItems/useMeetingActionItems.ts) 목록 응답에 originMeetingId 가 추가되면 이 훅은 통째로 지울 수 있습니다.memberProgress.completionRate 의 단위(0toPercent() in src/lib/date.ts)구글 로그인은 VITE_GOOGLE_CLIENT_ID 가 설정돼 있을 때만 로그인/회원가입 화면에 버튼이 나타납니다.
비워 두면 버튼이 아예 렌더링되지 않으므로, 설정 전에도 앱은 정상 동작합니다.
http://localhost:3000
https://<vercel-배포-도메인>
.env 에 넣습니다.
VITE_GOOGLE_CLIENT_ID=1234567890-xxxxxxxx.apps.googleusercontent.com
Vercel 은 Settings → Environment Variables 에 같은 이름으로 추가한 뒤 재배포하세요.
환경변수를 바꾸면 dev 서버를 재시작해야 반영됩니다.
백엔드에 POST /api/auth/google 이 있어야 실제 로그인이 됩니다.
구글 ID 토큰만으로는 우리 API 를 호출할 수 없고, 백엔드가 검증 후 자체 JWT 를 발급해야 하기 때문입니다.
명세와 Spring 구현 예시는 BACKEND_NOTES.md 마지막 섹션에 정리해 뒀습니다.
백엔드와 프론트는 같은 클라이언트 ID 를 써야 합니다. (백엔드는 aud 검증에 사용)
이 API 가 없는 동안 버튼을 누르면 "백엔드에 구글 로그인 API(/api/auth/google)가 아직 없습니다" 안내가 표시되고, 이메일 로그인은 그대로 사용할 수 있습니다.
구글 버튼 클릭
↓ Google Identity Services 가 ID 토큰 발급
POST /api/auth/google { idToken }
↓ 백엔드가 구글 공개키로 검증 → 없으면 자동 가입 → 우리 JWT 발급
{ accessToken, tokenType, expiresIn } ← 기존 로그인과 동일한 응답
↓ localStorage 저장 → /projects 이동
관련 파일: src/lib/googleAuth.ts, src/components/auth/GoogleLoginButton.tsx, src/api/authApi.ts
/api 프록시가 동작하지 않으면vercel.json 의 rewrite 는 대상이 http:// 인 외부 주소입니다. 혹시 이 방식이 막히면(502 등),
아래 서버리스 함수로 바꾸면 동일하게 동작합니다.
api/[...path].ts 파일을 만들고 아래 내용을 넣습니다.// api/[...path].ts — Vercel 서버리스 프록시 (rewrite 대안)
export const config = { runtime: 'nodejs' }
const BACKEND = process.env.BACKEND_ORIGIN
export default async function handler(req: Request) {
const url = new URL(req.url)
const target = BACKEND + url.pathname + url.search
const headers = new Headers(req.headers)
headers.delete('host')
headers.delete('content-length')
const res = await fetch(target, {
method: req.method,
headers,
body: ['GET', 'HEAD'].includes(req.method) ? undefined : await req.text(),
})
return new Response(res.body, {
status: res.status,
headers: { 'content-type': res.headers.get('content-type') ?? 'application/json' },
})
}
vercel.json 에서 /api/:path* rewrite 를 지웁니다. (SPA fallback rewrite 는 그대로 둡니다){
"rewrites": [
{ "source": "/((?!api/).*)", "destination": "/index.html" }
]
}
프론트 코드는 그대로 /api/... 를 호출하므로 수정할 필요가 없습니다.