Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
a17d5d5
refactor: HttpRequest 헤더 저장 로직 추가 및 Keep-Alive 기반 마련
shinminkyoung1 Jan 4, 2026
ded7ef9
auto merge script
dangle-j Jan 4, 2026
3c9f827
directory typo
dangle-j Jan 4, 2026
5fad39f
Merge branch 'softeerbootcamp-7th:main' into main
shinminkyoung1 Jan 5, 2026
62078d0
Merge branch 'main' of https://github.com/shinminkyoung1/be-was
shinminkyoung1 Jan 5, 2026
138f2c4
Merge branch 'task1-2'
shinminkyoung1 Jan 5, 2026
22f4a06
ci: Claude 자동 코드 리뷰 워크플로우 추가
shinminkyoung1 Jan 12, 2026
cda0f8c
fix: main 브랜치 충돌 해결
shinminkyoung1 Jan 13, 2026
3165f99
feat: H2 Database 의존성 추가
shinminkyoung1 Jan 13, 2026
6f749d2
feat: 유저 및 아티클 테이블 설계
shinminkyoung1 Jan 13, 2026
43bd76f
fix: schema.sql 파일명 오타 수정
shinminkyoung1 Jan 13, 2026
fb2916c
refactor: ConnectionManager의 DB 설정 정보를 Config 클래스로 분리
shinminkyoung1 Jan 13, 2026
6b207b4
feat: Article 모델 생성
shinminkyoung1 Jan 13, 2026
2cbce62
feat: Jdbc 기반의 ArticleDao 구현 및 DB 연동
shinminkyoung1 Jan 13, 2026
e0bf064
feat: AppConfig에 ArticleDao 등록 및 글쓰기 경로 매핑
shinminkyoung1 Jan 13, 2026
58576c6
refactor: 의존성 주입 체계에 article 기능 통합
shinminkyoung1 Jan 13, 2026
cb4038a
feat: article 작성을 위한 ArticleWriteHandler 구현
shinminkyoung1 Jan 13, 2026
213f203
feat: article/index.html 연결을 위한 경로 등록
shinminkyoung1 Jan 13, 2026
5864095
feat: 로그인한 유저 기반 게시글 저장 로직 구현
shinminkyoung1 Jan 13, 2026
1278e3d
feat: h2기반 유저 저장 로직 구현
shinminkyoung1 Jan 13, 2026
ea5fac8
refactor: article 작성 호출 url create->write로 변경
shinminkyoung1 Jan 13, 2026
2a592af
feat: 유저 기반 게시글 작성 및 동적 HTML 적용
shinminkyoung1 Jan 13, 2026
ba908a0
fix: TODO 목록 삭제
shinminkyoung1 Jan 13, 2026
9630dc8
refactor: 아티클 작성 폼 내 제목과 내용 규격 통일
shinminkyoung1 Jan 13, 2026
4974f96
fix: 아티클 저장 정상화를 위한 라우팅 수정
shinminkyoung1 Jan 13, 2026
940825b
feat: 아티클 작성 폼 내 이미지 첨부 칸 추가 및 멀티파트 설정
shinminkyoung1 Jan 13, 2026
7ef1a97
feat: MultipartPart 모델 구현
shinminkyoung1 Jan 13, 2026
fd9a6f8
feat: MultipartPart 파서 구현
shinminkyoung1 Jan 13, 2026
d5a6255
feat: Multipart 파서 도입 및 게시글 파일 업로드 기능 추가
shinminkyoung1 Jan 14, 2026
3b7e8db
fix: 스트림 읽기 방식 개선을 통한 broken pipe 에러 해결
shinminkyoung1 Jan 14, 2026
115a241
refactor: HTTP Request 바이트 스트림 기반으로 개편
shinminkyoung1 Jan 14, 2026
35b1104
refactor: HttpResponse 내 contentType get로직 개편
shinminkyoung1 Jan 14, 2026
a479181
feat: 이미지 서빙을 위한 pageRender 내 이미지 영역 추가
shinminkyoung1 Jan 14, 2026
231b35d
feat: MyPageHandler 구현
shinminkyoung1 Jan 14, 2026
b8a0cd4
feat: 프로필 이미지 변경 db 저장 로직 구현
shinminkyoung1 Jan 14, 2026
790cf8d
fix: 수정 프로필 이미지 업로드 경로 수정
shinminkyoung1 Jan 14, 2026
5b366c5
refactor: 데이터 메서드 전달을 위한 파일 판단 방식 변경
shinminkyoung1 Jan 14, 2026
17b3caa
refactor: 프로필 이미지 형식에 맞게 리사이징
shinminkyoung1 Jan 14, 2026
01e0e05
feat: 에러 전용 Html 페이지 구성
shinminkyoung1 Jan 14, 2026
ea671f7
feat: 커스텀 에러 페이지(404, 405, 500) 핸들링 기능 구현
shinminkyoung1 Jan 14, 2026
82c4d38
fix: 아티클 작성 정적 파일 재연결
shinminkyoung1 Jan 14, 2026
9be87fd
refactor: 아티클 페이지 내 로고 클릭 시 메인 페이지 이동
shinminkyoung1 Jan 14, 2026
7c6df03
docs: javadoc 설정을 위한 docs 추가
shinminkyoung1 Jan 15, 2026
5ed37ed
fix: task3-3과 병합 중 충돌 해결
shinminkyoung1 Jan 15, 2026
12f5654
feat: 최신 게시글 1개를 렌더링하는 메서드 구현
shinminkyoung1 Jan 15, 2026
33c4b2d
feat: 좋아요 카운트 기능 구현
shinminkyoung1 Jan 15, 2026
12138d2
feat: Comment 모델 구현
shinminkyoung1 Jan 15, 2026
11e0dee
feat: 특정 게시글의 댓글 목록 조회 dao 구현
shinminkyoung1 Jan 15, 2026
1917ef4
feat: 아티클 좋아요 기능 구현
shinminkyoung1 Jan 15, 2026
6dd0c84
feat: 댓글 저장 commentDao 구현
shinminkyoung1 Jan 15, 2026
a60148a
feat: AppConfig 내 댓글 작성 정적 페이지 연결 추가
shinminkyoung1 Jan 15, 2026
4ad6748
feat: comment 페이지 핸들러 추가
shinminkyoung1 Jan 15, 2026
797dba5
feat: 모든 댓글 보기를 위한 스크립트 추가
shinminkyoung1 Jan 15, 2026
525438f
feat: 이전 글 / 다음 글 이동 구현
shinminkyoung1 Jan 15, 2026
f0cba94
feat: 회원가입 시 글자수 제한 유효성 검증 추가
shinminkyoung1 Jan 15, 2026
a93c1fa
feat: 회원가입 후 리다이렉트 설정 및 유효성 검증 스킄립트 추가
shinminkyoung1 Jan 15, 2026
166e514
feat: 회원가입 시 중복 아이디/닉네임 제한
shinminkyoung1 Jan 15, 2026
0652794
refactor: 존재하지 않는 아이디일 경우 회원가입으로 연결
shinminkyoung1 Jan 15, 2026
30c8d20
refactor: 로그인 시 상단 GNB 멘트 변경
shinminkyoung1 Jan 15, 2026
e9ad0f4
feat: 아티클/댓글 페이지 로그아웃 구현
shinminkyoung1 Jan 15, 2026
2e24f13
refactor: 댓글 작성자 프로필 이미지 렌더링 구현
shinminkyoung1 Jan 15, 2026
ab75412
refactor: 댓글 작성 후 리다이렉트 페이지 변경
shinminkyoung1 Jan 15, 2026
b3bc639
refactor: 좋아요 시 해당 페이지 잔류 구현
shinminkyoung1 Jan 15, 2026
71d1660
feat: 아티클 작성 시 파일 첨부 여부 검증 추가
shinminkyoung1 Jan 15, 2026
4ad1448
feat: 마이페이지 정보 변경 구현
shinminkyoung1 Jan 15, 2026
9375b97
docs: 이미지 업로드 .gitignore 추가
shinminkyoung1 Jan 16, 2026
3163812
fix: 회원가입 기본 이미지 적용 오류 수정
shinminkyoung1 Jan 16, 2026
fa57425
refactor: 게시글 및 댓글 작성자 표시 id에서 이름으로 변경
shinminkyoung1 Jan 16, 2026
80dffee
fix: 프로필 이미지 변경 시 비밀번호 갱신 문제 해결
shinminkyoung1 Jan 16, 2026
28e40d0
refactor: 회원 정보 수정 글자수 제한 추가
shinminkyoung1 Jan 16, 2026
89fb8ba
Merge pull request #1 from shinminkyoung1/task3-4
shinminkyoung1 Jan 16, 2026
0abbd48
fix: db 연결 문제 해결
shinminkyoung1 Jan 16, 2026
dcf8854
refactor: 댓글 페이지 내 로고 리다이렉트 수정
shinminkyoung1 Jan 16, 2026
8b795d3
refactor: 미포함 항목 추가
shinminkyoung1 Jan 16, 2026
3bf443e
Merge branch 'task3-3'
shinminkyoung1 Jan 16, 2026
8fc63bd
Merge branch 'main' of https://github.com/shinminkyoung1/be-was
shinminkyoung1 Jan 16, 2026
ec6b33a
fx: 누락 메서드 포함
shinminkyoung1 Jan 16, 2026
697fb97
refactor: 이미지 확장자에 따른 파일 경로 재설정
shinminkyoung1 Jan 16, 2026
17d375e
fix: 불필요 파일 제거
shinminkyoung1 Jan 16, 2026
011687b
refactor: 확장자에 따른 이미지 저장 경로 변경
shinminkyoung1 Jan 16, 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
138 changes: 138 additions & 0 deletions .github/workflows/auto_merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
name: "PR merge on time v3.3 by crong"

on:
schedule:
- cron: "0 15 * * 1-3" # 월>화, 화>수, 수>목 자정(00:00)
- cron: "30 15 * * 1-3" # 월>화, 화>수, 수>목 00:30
workflow_dispatch:

permissions:
contents: write
pull-requests: write
issues: write

jobs:
merge:
name: "Auto Merge on time"
runs-on: "ubuntu-latest"

steps:
- name: "Merge pull request"
uses: "actions/github-script@v6"
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const query = `query($owner:String!, $name:String!) {
repository(owner: $owner, name: $name) {
pullRequests(last: 100, states: OPEN) {
edges {
node {
number
headRefName
baseRefName
author {
login
}
repository {
name
}
mergeable
labels(first: 10) {
nodes {
name
}
}
reviews(last: 1) {
nodes {
state
}
}
}
}
}
}
}`
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
}
const {repository:{pullRequests:{edges: list}}} = await github.graphql(query, variables)
for (let {node} of list) {
console.log("\n----------------------------------------");
console.log(`PR #${node.number} 처리 시작`);
console.log(`PR node 정보: ${JSON.stringify(node, null, 2)}`);
if (node.baseRefName === "main" || !node.labels.nodes.length) {
console.log(`PR #${node.number}: main 브랜치이거나 라벨이 없음`);
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: node.number,
body: "main 브랜치로 병합 시도 || 적절한 라벨이 있는지 확인해 주세요."
});
console.log(`PR #${node.number}에 main브랜치 || 라벨없음 코멘트 추가 완료`);
} catch (e) {
console.log(`PR #${node.number}에 main브랜치 || 라벨없음 코멘트 추가 실패:`, e);
}
continue;
}
const hasSkipLabel = node.labels.nodes.some(label => label.name.toLowerCase() === 'review');
if (hasSkipLabel) {
console.log(`PR #${node.number}: 'review' 라벨이 있어 병합 생략`);
continue;
}
if (node.reviews?.nodes?.[0]?.state === "CHANGES_REQUESTED") {
console.log(`PR #${node.number}: 변경 요청 상태, 병합 연기`);
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: node.number,
body: "변경 요청 중인 브랜치의 머지를 연기합니다."
});
console.log(`PR #${node.number}에 변경 요청 상태 코멘트 추가 완료`);
} catch (e) {
console.log(`PR #${node.number}에 변경 요청 상태 코멘트 추가 실패:`, e);
}
continue;
}
if (node.mergeable === "CONFLICTING") {
try {
console.log(`PR #${node.number}: 충돌상황 closed 처리 시작`);

// PR 닫기 로직
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: node.number,
state: "closed"
});
console.log(`PR #${node.number} 충돌상황 closed 처리 완료`);

// 충돌 코멘트 추가
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: node.number,
body: "충돌로 인해 자동 병합이 불가능합니다."
});
console.log(`PR #${node.number}에 충돌 코멘트 추가 완료`);

} catch (e) {
console.log(`PR #${node.number}에 충돌 closed 처리 중 에러 발생:`, e);
}
} else {
console.log(`PR #${node.number} 병합 시작`);
try {
await github.rest.pulls.merge({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: node.number,
merge_method: "merge"
});
console.log(`PR #${node.number} 병합 완료`);
} catch (e) {
console.log(`PR #${node.number} 병합 실패:`, e);
}
}
}
24 changes: 24 additions & 0 deletions .github/workflows/llm-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Claude Auto PR Review
on:
pull_request:
types: [opened, edited, synchronize]

permissions:
contents: read
pull-requests: write
checks: write
id-token: write

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Simple LLM Code Review
uses: codingbaraGo/simple-llm-code-review@latest
with:
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
language: korean
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ fabric.properties
# Mobile Tools for Java (J2ME)
.mtj.tmp/

### Custom Upload Files ###
# 프로젝트 내 업로드된 이미지 파일 제외
**/static/uploads/*
/uploads/

# Package Files #
*.jar
*.war
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# be-was-2025
코드스쿼드 백엔드 교육용 WAS 2025 개정판
## 학습 기록
- [학습 Wiki 바로가기](https://github.com/shinminkyoung1/be-was/wiki)
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ dependencies {
implementation 'ch.qos.logback:logback-classic:1.2.3'
testImplementation 'org.assertj:assertj-core:3.16.1'


// h2 database
implementation 'com.h2database:h2:2.2.224'
}

test {
Expand Down
6 changes: 6 additions & 0 deletions db/jwp-was.lock.db
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#FileLock
#Fri Jan 16 13:48:25 KST 2026
server=localhost\:49707
hostName=localhost
method=file
id=19bc5126dc59a1e993ea0de86029c70ff00912b1a1b
Binary file added db/jwp-was.mv.db
Binary file not shown.
80 changes: 80 additions & 0 deletions db/jwp-was.trace.db
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
2026-01-16 11:02:22.798440+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ARTICLE" not found (this database is empty); SQL statement:
SELECT * FROM ARTICLE WHERE id = ? [42104-224]
2026-01-16 11:02:38.098359+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:04:58.715530+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:04:58.851620+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:04:58.962955+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:05:03.739660+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:05:03.887840+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:05:04.010547+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
SELECT * FROM USERS WHERE userId = ? [42104-224]
2026-01-16 11:11:53.554822+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "TITLE" not found; SQL statement:
INSERT INTO ARTICLE (writer, title, contents, imagePath) VALUES (?, ?, ?, ?) [42122-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:514)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
at org.h2.message.DbException.get(DbException.java:223)
at org.h2.message.DbException.get(DbException.java:199)
at org.h2.table.Table.getColumn(Table.java:759)
at org.h2.command.Parser.parseColumn(Parser.java:1190)
at org.h2.command.Parser.parseColumnList(Parser.java:1175)
at org.h2.command.Parser.parseInsert(Parser.java:1549)
at org.h2.command.Parser.parsePrepared(Parser.java:719)
at org.h2.command.Parser.parse(Parser.java:592)
at org.h2.command.Parser.parse(Parser.java:564)
at org.h2.command.Parser.prepareCommand(Parser.java:483)
at org.h2.engine.SessionLocal.prepareLocal(SessionLocal.java:639)
at org.h2.engine.SessionLocal.prepareCommand(SessionLocal.java:559)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1166)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:93)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:316)
at db.ArticleDao.insert(ArticleDao.java:19)
at webserver.handler.ArticleWriteHandler.process(ArticleWriteHandler.java:71)
at webserver.RequestHandler.run(RequestHandler.java:56)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:840)
2026-01-16 13:31:13.101146+09:00 database: wrong user or password; user: "APPLE"
org.h2.message.DbException: Wrong user name or password [28000-240]
at org.h2.message.DbException.get(DbException.java:223)
at org.h2.message.DbException.get(DbException.java:199)
at org.h2.message.DbException.get(DbException.java:188)
at org.h2.engine.Engine.openSession(Engine.java:154)
at org.h2.engine.Engine.openSession(Engine.java:222)
at org.h2.engine.Engine.createSession(Engine.java:201)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:350)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:124)
at org.h2.util.JdbcUtils.getConnection(JdbcUtils.java:291)
at org.h2.server.web.WebServer.getConnection(WebServer.java:811)
at org.h2.server.web.WebApp.login(WebApp.java:1038)
at org.h2.server.web.WebApp.process(WebApp.java:226)
at org.h2.server.web.WebApp.processRequest(WebApp.java:176)
at org.h2.server.web.WebThread.process(WebThread.java:154)
at org.h2.server.web.WebThread.run(WebThread.java:103)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.h2.jdbc.JdbcSQLInvalidAuthorizationSpecException: Wrong user name or password [28000-240]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:522)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
... 16 more
2026-01-16 13:31:36.992704+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "delete from ARTICLE\000d\000awhere id [*]4 and 6"; SQL statement:
delete from ARTICLE
where id 4 and 6 [42000-240]
2026-01-16 13:31:41.041881+09:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "delete from ARTICLE\000d\000awhere id in [*]4 and 6"; expected "("; SQL statement:
delete from ARTICLE
where id in 4 and 6 [42001-240]
Loading