choiminyeong f5fd8925fc Docs: UBGitea introduction deck (pptx, pdf, html slides, screenshots)
Agent: main (opus)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 14:11:47 +09:00

239 lines
15 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UBGitea 소개 PPT 생성 (PowerPoint COM). 사용: powershell -File docs\presentation\build-pptx.ps1
# 좌표는 HTML 슬라이드와 같은 1920x1080 px 기준, 0.5배 해서 pt로 넣는다.
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
$img = Join-Path $root 'images'
$out = Join-Path $root 'UBGitea_소개.pptx'
$pdf = Join-Path $root 'UBGitea_소개.pdf'
$KR = '맑은 고딕'; $MONO = 'Consolas'
$BR = [string][char]11
function C($hex) { $r=[Convert]::ToInt32($hex.Substring(0,2),16); $g=[Convert]::ToInt32($hex.Substring(2,2),16); $b=[Convert]::ToInt32($hex.Substring(4,2),16); return $r + $g*256 + $b*65536 }
function P($v) { return [double]$v * 0.5 }
function T($s, $x, $y, $w, $h, $text, $size, $color, $bold=$false, $font=$KR, $align=1, $spacing=1.15) {
$b = $s.Shapes.AddTextbox(1, (P $x), (P $y), (P $w), (P $h))
$tf = $b.TextFrame; $tf.WordWrap = -1; $tf.AutoSize = 0
$tf.MarginLeft = 0; $tf.MarginRight = 0; $tf.MarginTop = 0; $tf.MarginBottom = 0
$r = $tf.TextRange; $r.Text = $text
$r.Font.Name = $font; $r.Font.NameFarEast = $KR; $r.Font.Size = (P $size)
$r.Font.Color.RGB = (C $color); $r.Font.Bold = $(if ($bold) { -1 } else { 0 })
$r.ParagraphFormat.Alignment = $align
$r.ParagraphFormat.LineRuleWithin = -1; $r.ParagraphFormat.SpaceWithin = $spacing
return $b
}
function B($s, $x, $y, $w, $h, $items, $size=26, $color='3E5068') {
$b = T $s $x $y $w $h ($items -join "`r") $size $color $false $KR 1 1.3
$pf = $b.TextFrame.TextRange.ParagraphFormat
$pf.Bullet.Visible = -1; $pf.Bullet.Character = 8226
$pf.LineRuleAfter = 0; $pf.SpaceAfter = 6
$b.TextFrame.Ruler.Levels.Item(1).FirstMargin = 0
$b.TextFrame.Ruler.Levels.Item(1).LeftMargin = 14
return $b
}
function Box($s, $x, $y, $w, $h, $fill, $line=$null, $round=$false) {
$shape = $s.Shapes.AddShape($(if ($round) { 5 } else { 1 }), (P $x), (P $y), (P $w), (P $h))
if ($round) { $shape.Adjustments.Item(1) = 0.06 }
$shape.Fill.ForeColor.RGB = (C $fill)
if ($line) { $shape.Line.ForeColor.RGB = (C $line); $shape.Line.Weight = 1 } else { $shape.Line.Visible = 0 }
$shape.Shadow.Visible = 0
return $shape
}
function I($s, $name, $x, $y, $w, $h, $border='C9DCF2') {
$path = Join-Path $img "$name.png"
$im = [System.Drawing.Image]::FromFile($path); $iw = $im.Width; $ih = $im.Height; $im.Dispose()
$k = [Math]::Min($w / $iw, $h / $ih); $pw = $iw * $k; $ph = $ih * $k
$px = $x + ($w - $pw) / 2; $py = $y + ($h - $ph) / 2
$p = $s.Shapes.AddPicture($path, 0, -1, (P $px), (P $py), (P $pw), (P $ph))
if ($border) { $p.Line.Visible = -1; $p.Line.ForeColor.RGB = (C $border); $p.Line.Weight = 1 }
return $p
}
function NewSlide($bg, $notes) {
$s = $pres.Slides.Add($pres.Slides.Count + 1, 12)
$s.FollowMasterBackground = 0; $s.Background.Fill.Solid(); $s.Background.Fill.ForeColor.RGB = (C $bg)
$s.NotesPage.Shapes.Placeholders.Item(2).TextFrame.TextRange.Text = $notes
return $s
}
function Eyebrow($s, $x, $y, $text, $color='1565C0', $size=26) { T $s $x $y 900 40 $text $size $color $true $MONO | Out-Null }
function H2($s, $x, $y, $w, $h, $text, $size=56, $color='10243F') { T $s $x $y $w $h $text $size $color $true $KR 1 1.1 | Out-Null }
# 왼쪽 글 + 오른쪽 폰 화면 3장
function ThreeShots($bg, $eyebrow, $title, $bullets, $shots, $notes) {
$s = NewSlide $bg $notes
Eyebrow $s 128 250 $eyebrow
H2 $s 128 296 440 160 $title
B $s 128 480 440 420 $bullets | Out-Null
$x = 648
foreach ($sh in $shots) {
I $s $sh[0] $x 130 360 760 | Out-Null
T $s $x 906 360 40 $sh[1] 24 '3E5068' $false $KR 2 | Out-Null
$x += 392
}
}
# 왼쪽 글 + 오른쪽 펼친 화면 1장
function WideShot($bg, $eyebrow, $title, $bullets, $shot, $notes) {
$s = NewSlide $bg $notes
Eyebrow $s 128 280 $eyebrow
H2 $s 128 326 760 160 $title
B $s 128 500 760 420 $bullets | Out-Null
I $s $shot 968 130 824 821 | Out-Null
}
$app = New-Object -ComObject PowerPoint.Application
$pres = $app.Presentations.Add(0)
$pres.PageSetup.SlideWidth = 960; $pres.PageSetup.SlideHeight = 540
# 1 표지
$s = NewSlide 'F4F8FD' '회사 Gitea 서버 조회용 안드로이드 앱. 순서: 개발 배경 → 주요 화면 → 기술 · 개발 방식 → 현황.'
Box $s 1180 0 740 1080 'DCEAF9' | Out-Null
I $s 'logo' 128 250 300 90 $null | Out-Null
$s.Shapes.Item($s.Shapes.Count).Left = (P 128)
Eyebrow $s 128 384 'UBGitea · Android · v0.2.6' '1565C0' 28
T $s 128 444 960 230 ("사내 Gitea" + $BR + "모바일 앱") 96 '10243F' $true $KR 1 1.0 | Out-Null
T $s 128 700 900 60 '팀 활동 · 코드 · 변경 내용 모바일 조회용 사내 Git 앱' 32 '3E5068' | Out-Null
T $s 128 790 900 40 '2026년 10월 · 사내 공유용' 24 '5A6B80' | Out-Null
I $s 'home' 1340 96 420 887 'B9D3F0' | Out-Null
# 2 개발 배경
$s = NewSlide '10243F' '웹 기능 전체 이식 아님. 1순위 팀 활동 확인, 2순위 코드 · 변경 내용 조회. 소스 수정 · 병합 · 삭제 기능 의도적 제외.'
Eyebrow $s 128 128 '개발 배경' '7DB9F5'
H2 $s 128 176 1500 180 ("목적: 이석 중에도" + $BR + "팀 작업 현황 모바일 확인") 64 'F4F8FD'
$cards = @(
@('팀 활동 우선', 'Push 이력 · 열린 PR · 이슈 · 내 확인 필요 항목 첫 화면 표시', '4FA3F7'),
@('필요 부분만 코드 조회', '목차 · 클래스 · 함수 단위 이동, 두 파일 좌우 비교. 팀 주력 언어 C# · C++ 기준', '4FA3F7'),
@('읽기 중심 · 보안', '회사 Gitea 계정 로그인. 쓰기 기능은 저장소 즐겨찾기(별표)만 허용', 'F0A04B'))
$x = 128
foreach ($c in $cards) {
Box $s $x 620 533 332 '1A3558' | Out-Null
Box $s $x 620 533 6 $c[2] | Out-Null
T $s ($x+40) 666 453 50 $c[0] 34 'F4F8FD' $true | Out-Null
T $s ($x+40) 736 453 190 $c[1] 26 'D3E2F4' $false $KR 1 1.4 | Out-Null
$x += 565
}
# 3 탭 구성
$s = NewSlide 'F4F8FD' '우측: Z Fold 펼친 화면. 넓은 화면에서 탭은 좌측 레일로 이동, 홈은 팀 활동 · 타임라인 2단 표시.'
Eyebrow $s 128 220 '화면 구성'
H2 $s 128 266 760 80 '탭 4개 구성'
$rows = @(@('홈','오늘의 팀 활동과 타임라인, 내 확인이 필요한 항목'), @('저장소','전체·즐겨찾기 저장소, 브랜치, 파일, 커밋'), @('작업','팀 전체·리뷰 요청·나에게 할당된 이슈와 PR'), @('알림','Gitea 알림과 즐겨찾기 저장소의 Push 알림'))
$y = 380
foreach ($r in $rows) {
Box $s 128 $y 760 2 'C9DCF2' | Out-Null
T $s 128 ($y+26) 150 50 $r[0] 34 '1565C0' $true | Out-Null
T $s 306 ($y+32) 582 80 $r[1] 26 '3E5068' | Out-Null
$y += 104
}
Box $s 128 $y 760 2 'C9DCF2' | Out-Null
T $s 128 ($y+36) 760 40 '접은 화면: 하단 탭 / 펼친 화면 · 가로 화면: 좌측 레일' 24 '5A6B80' | Out-Null
I $s 'home_wide' 968 130 824 821 | Out-Null
# 4 홈
$s = NewSlide 'FBFCFE' '상단 숫자: 당일 Push, 열린 PR, 신규 이슈. 즐겨찾기 선택 시 별표 저장소 활동만 표시. 하단 타임라인: Push · PR · 이슈 시간순.'
Eyebrow $s 128 250 '홈 · 팀 활동'
H2 $s 128 296 1178 160 ("첫 화면:" + $BR + "당일 팀 활동 요약")
$stats = @(@('Push','당일 커밋'), @('PR','열린 요청'), @('이슈','신규 이슈'))
$x = 128
foreach ($st in $stats) {
Box $s $x 486 368 150 'E6F0FB' $null $true | Out-Null
T $s ($x+28) 508 320 60 $st[0] 44 '1565C0' $true | Out-Null
T $s ($x+28) 582 320 40 $st[1] 24 '3E5068' | Out-Null
$x += 392
}
B $s 128 676 1178 240 @('조회 범위: 내 피드 · 즐겨찾기 · 조직별 (선택 범위 저장)', '활동 저장소별 최근 브랜치 · 활동량 그래프', '타임라인: 작성자 · 브랜치 · Push 내용') 28 | Out-Null
I $s 'home' 1402 128 390 824 | Out-Null
# 5 저장소
ThreeShots 'F4F8FD' '저장소' ("저장소 조회 ·" + $BR + "즐겨찾기") @('조직별 저장소 목록', '별표 저장소: 즐겨찾기 탭 · 홈에 표시', '브랜치 · 태그 목록', '저장소 목록 기기 저장, 오프라인 조회') @(@('repos','전체 저장소'), @('favorites','즐겨찾기'), @('branch','브랜치 · 태그')) '계정 접근 가능 저장소 조직별 표시. 별표는 Gitea 별표와 동기화. 앱 내 유일한 쓰기 작업.'
# 6 코드 보기
ThreeShots 'F4F8FD' '코드 보기' ("함수 단위" + $BR + "빠른 탐색") @('Visual Studio 기본 색상 기준 C# · C++ 강조', '.h 선언 / .cpp 구현 탭 전환', '목차에서 함수 선택 후 이동', '폴더 구조 · 클래스 · 함수 옆 창 표시') @(@('code','코드 · 선언/구현 탭'), @('outline','목차'), @('side_pane','폴더 · 클래스 옆 창')) '파일 전체 열람보다 함수 탐색 위주 설계. 하단 도구 막대: 검색, 목차, 줄바꿈, 글자 크기, 복사, 탭 저장, 비교.'
# 7 펼친 화면 코드
WideShot 'FBFCFE' '펼친 화면 · 코드' ("펼친 화면:" + $BR + "구조 · 코드 동시 표시") @('Z Fold 펼침 · 가로 화면 대응', '좌측: 폴더 구조 · 클래스 · 함수 목록 / 우측: 코드', '옆 창 파일 선택 시 즉시 열림', '클래스 · 함수 선택 시 해당 줄 이동', '두 칸 위아래 순서 변경') 'code_wide' '펼친 화면에서 옆 창 상시 표시. 예시: C# 파일.'
# 8 파일 비교
WideShot 'F4F8FD' '파일 비교' ("저장소 간" + $BR + "동일 파일 비교") @('다른 저장소 · 브랜치 파일 간 좌우 비교', '예시: OC6 PRI 저장소(main) ↔ OC6 저장소(SubMain)', '차이 개수 표시, 이전 · 다음 차이 이동', '추가 · 삭제 · 변경 줄 색상 구분') 'compare_repos' '동일 장비 PRI 저장소 · 현장 저장소의 WeldingRecipeManager.cs 비교. 차이 5곳 중 첫 번째 위치. 사용 순서: 파일에서 비교 → 왼쪽 배치 → 다른 파일에서 비교 실행.'
# 9 커밋
ThreeShots 'FBFCFE' '커밋' ("커밋별 변경 내용" + $BR + "줄 단위 확인") @('브랜치별 커밋 목록', '커밋 선택: 변경 파일 · 추가/삭제 줄 수', '파일 선택: 변경 내용 표시') @(@('commits','커밋 목록'), @('commit_detail','바뀐 파일'), @('diff','변경 내용')) '이동 중 팀원 커밋 즉시 확인. 접은 화면: 상하 배치 / 펼친 화면: 좌우 배치.'
# 10 펼친 화면 변경 내용
WideShot 'F4F8FD' '펼친 화면 · 변경 내용' ("펼친 화면:" + $BR + "변경 전 · 후 좌우 비교") @('PC 비교 도구 방식: 좌측 변경 전 / 우측 변경 후', '삭제: 빨강 / 추가: 초록', '코드 화면과 동일한 문법 강조') 'diff_wide' '코드 리뷰 요청 시 PC 없이 변경 내용 확인 가능.'
# 11 작업 · 알림
ThreeShots 'FBFCFE' '작업 · 알림' ("이슈 · PR ·" + $BR + "알림 통합 조회") @('필터: 팀 전체 · 리뷰 요청 · 나에게 할당 · 내가 작성', '상태 배지: 열림 · 병합됨 · 닫힘', '이슈 · PR 본문 및 댓글 조회', 'Gitea 알림: 읽지 않음 · 전체') @(@('work','작업 탭'), @('issue_detail','이슈 상세'), @('notifications','알림')) '리뷰 요청 · 할당 업무 일괄 확인. 읽기 전용으로 댓글 작성 · 병합은 PC Gitea에서 처리.'
# 12 파일 보기
ThreeShots 'F4F8FD' '파일 보기' ("코드 외" + $BR + "파일 조회") @('이미지', 'CSV 표', 'PDF 문서', '별도 앱 없이 앱 내 열람') @(@('image','이미지'), @('csv','CSV 표'), @('pdf','PDF')) '장비 문서 · 설정 표 등 코드와 함께 관리하는 파일 모바일 확인.'
# 13 설정
$s = NewSlide 'FBFCFE' '신규 버전은 팀 Gitea 릴리스 기준. 업데이트 알림 시 설정에서 바로 설치.'
Eyebrow $s 128 320 '설정'
H2 $s 128 366 772 80 '설정 항목'
B $s 128 470 772 420 @('테마: 시스템 · 라이트 · 다크', '코드 자동 줄바꿈, 글자 크기 11–16sp', '즐겨찾기 저장소 Push 알림', '인증 실패 시 재시도', '팀 Gitea 기반 앱 업데이트') | Out-Null
I $s 'settings' 980 104 390 824 | Out-Null
T $s 980 940 390 40 '설정' 24 '3E5068' $false $KR 2 | Out-Null
I $s 'dark_home' 1402 104 390 824 | Out-Null
T $s 1402 940 390 40 '다크 테마' 24 '3E5068' $false $KR 2 | Out-Null
# 14 기술 · 보안
$s = NewSlide 'F4F8FD' '로그인은 브라우저에서 Gitea 직접 인증, 앱은 발급 토큰만 보관. 저장소 목록 기기 저장으로 오프라인 조회 가능.'
Eyebrow $s 128 128 '기술 · 보안'
H2 $s 128 176 1664 80 '회사 계정 인증 · 읽기 중심 설계'
$rows = @(@('로그인','팀 Gitea OAuth 2.0 + PKCE. 앱 내 비밀번호 입력 없음'), @('토큰 보관','Android Keystore 암호화, 기기 내 저장'), @('권한','읽기 전용. 쓰기는 즐겨찾기 별표만'), @('만든 기술','Kotlin · Jetpack Compose · Material 3'), @('지원 기기','Android 9 (API 28) 이상, 폴더블 · 가로 화면 대응'), @('배포','팀 Gitea 릴리스 배포, 앱 내 업데이트'))
$y = 310
foreach ($r in $rows) {
Box $s 128 $y 1664 2 'C9DCF2' | Out-Null
T $s 128 ($y+24) 320 50 $r[0] 30 '1565C0' $true | Out-Null
$f = $(if ($r[0] -eq '만든 기술') { $MONO } else { $KR })
T $s 488 ($y+28) 1304 50 $r[1] 26 '3E5068' $false $f | Out-Null
$y += 96
}
Box $s 128 $y 1664 2 'C9DCF2' | Out-Null
# 15 개발 방식
$s = NewSlide '10243F' '작업별 완료 기준 파일 선작성 → AI 에이전트 구현 → 별도 세션 리뷰. 전 과정 docs/development-log.md 기록.'
Eyebrow $s 128 128 '만든 방법' 'F0A04B'
H2 $s 128 176 1664 80 'AI 에이전트 활용 개발 · 7주' 56 'FFFFFF'
$stats = @(@('77','작업 (TASK-001 → 077)'), @('7주','2026-08-25 ~ 10-12'), @('104','개발 기록 항목'), @('0.2.6','현재 버전'))
$x = 128
foreach ($st in $stats) {
Box $s $x 320 392 190 '1A3558' $null $true | Out-Null
T $s ($x+32) 346 340 90 $st[0] 60 'F0A04B' $true $MONO | Out-Null
T $s ($x+32) 448 340 40 $st[1] 24 'C9DCF2' | Out-Null
$x += 424
}
$steps = @(@('1','작업 정의','완료 기준 선작성'), @('2','AI 구현','Codex · Claude'), @('3','별도 세션 리뷰','구현과 별도 에이전트'), @('4','빌드 · 테스트','실기기 확인'), @('5','배포','팀 Gitea 릴리스'))
$x = 128
foreach ($st in $steps) {
Box $s $x 600 320 4 'F0A04B' | Out-Null
T $s $x 626 320 34 $st[0] 22 'F0A04B' $false $MONO | Out-Null
T $s $x 670 320 40 $st[1] 26 'FFFFFF' $true | Out-Null
T $s $x 716 320 36 $st[2] 22 'C9DCF2' | Out-Null
$x += 336
}
# 16 현황
$s = NewSlide 'F4F8FD' '개발 완료, 현재 버전 0.2.6. 설치 파일 팀 Gitea 릴리스 제공, 이후 신규 버전 앱 내 알림.'
Eyebrow $s 128 370 '현황'
H2 $s 128 418 640 170 ("개발 완료 ·" + $BR + "사내 배포") 64
T $s 128 610 640 50 '현재 버전 v0.2.6' 28 '3E5068' | Out-Null
$items = @(@('설치','팀 Gitea 릴리스 설치 파일'), @('로그인','회사 Gitea 계정'), @('업데이트','신규 버전 앱 내 알림'))
$y = 330
foreach ($it in $items) {
Box $s 864 $y 928 116 'FFFFFF' 'C9DCF2' $true | Out-Null
T $s 896 ($y+36) 160 50 $it[0] 30 '1565C0' $true | Out-Null
T $s 1084 ($y+36) 680 50 $it[1] 30 '10243F' | Out-Null
$y += 140
}
$pres.SaveAs($out, 24)
$pres.SaveAs($pdf, 32)
$n = $pres.Slides.Count
$pres.Close(); $app.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($app) | Out-Null
"slides=$n"
"pptx=$out"
"pdf=$pdf"