From 22f4a06355c8bf10c82b2ae9fc56e8b2bc27f48b Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 00:23:49 +0900 Subject: [PATCH 01/15] =?UTF-8?q?ci:=20Claude=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=A6=AC=EB=B7=B0=20=EC=9B=8C=ED=81=AC?= =?UTF-8?q?=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/llm-code-review.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/llm-code-review.yml diff --git a/.github/workflows/llm-code-review.yml b/.github/workflows/llm-code-review.yml new file mode 100644 index 000000000..ea0e34d74 --- /dev/null +++ b/.github/workflows/llm-code-review.yml @@ -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 \ No newline at end of file From 3165f99b6bc5a7b41180c6673000d02d216e7c4c Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 11:22:08 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20H2=20Database=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 25dd8fcb7..3fe8c247b 100644 --- a/build.gradle +++ b/build.gradle @@ -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 { From 6f749d2744c9c6bf100a65f773e97304e427ac65 Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 11:23:46 +0900 Subject: [PATCH 03/15] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=95=84=ED=8B=B0=ED=81=B4=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schma.sql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/resources/schma.sql diff --git a/src/main/resources/schma.sql b/src/main/resources/schma.sql new file mode 100644 index 000000000..31320a4b3 --- /dev/null +++ b/src/main/resources/schma.sql @@ -0,0 +1,16 @@ +-- 회원 정보를 위한 테이블 +CREATE TABLE IF NOT EXISTS USERS ( + userId VARCHAR(50) PRIMARY KEY, + password VARCHAR(50) NOT NULL, + name VARCHAR(50) NOT NULL, + email VARCHAR(50) NOT NULL + ); + +-- 게시글 저장을 위한 테이블 +CREATE TABLE IF NOT EXISTS ARTICLE ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + writer VARCHAR(50) NOT NULL, + title VARCHAR(255) NOT NULL, + contents TEXT NOT NULL, + createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); \ No newline at end of file From 43bd76fd60320abd1f92c4bfec0667af512dfdbb Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 11:24:20 +0900 Subject: [PATCH 04/15] =?UTF-8?q?fix:=20schema.sql=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=AA=85=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/{schma.sql => schema.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{schma.sql => schema.sql} (100%) diff --git a/src/main/resources/schma.sql b/src/main/resources/schema.sql similarity index 100% rename from src/main/resources/schma.sql rename to src/main/resources/schema.sql From fb2916c2ad71e8c1bdddb88140515441172dc7fa Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 11:49:27 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor:=20ConnectionManager=EC=9D=98=20?= =?UTF-8?q?DB=20=EC=84=A4=EC=A0=95=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20Config?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/db/ConnectionManager.java | 18 ++++++++++++++++++ src/main/java/webserver/config/Config.java | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/db/ConnectionManager.java diff --git a/src/main/java/db/ConnectionManager.java b/src/main/java/db/ConnectionManager.java new file mode 100644 index 000000000..4ca0d8727 --- /dev/null +++ b/src/main/java/db/ConnectionManager.java @@ -0,0 +1,18 @@ +package db; + +import webserver.config.Config; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class ConnectionManager { + public static Connection getConnection() { + try { + Class.forName("org.h2.Driver"); + return DriverManager.getConnection(Config.DB_URL, Config.DB_USER, Config.DB_PW); + } catch (ClassNotFoundException | SQLException e) { + throw new RuntimeException("Failed to Connect SQL: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/webserver/config/Config.java b/src/main/java/webserver/config/Config.java index e36c4e459..f41780e30 100644 --- a/src/main/java/webserver/config/Config.java +++ b/src/main/java/webserver/config/Config.java @@ -11,4 +11,10 @@ public class Config { public static final String CRLF = "\r\n"; public static final String HEADER_DELIMITER = ": "; + + // h2 database + // TODO: .gitignore로 관리 + public static final String DB_URL = "jdbc:h2:~/jwp-was;MODE=MySQL;AUTO_SERVER=TRUE"; + public static final String DB_USER = "apple"; + public static final String DB_PW = "1q2w3e4r"; } From 6b207b4a6a715d331e6ca986c2f19cf12ba9e47e Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 12:08:46 +0900 Subject: [PATCH 06/15] =?UTF-8?q?feat:=20Article=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/Article.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/model/Article.java diff --git a/src/main/java/model/Article.java b/src/main/java/model/Article.java new file mode 100644 index 000000000..8b1e674df --- /dev/null +++ b/src/main/java/model/Article.java @@ -0,0 +1,6 @@ +package model; + +import java.time.LocalDateTime; + +public record Article (Long id,String writer, String title, String contents, LocalDateTime createdAt) { +} From 2cbce62602b50bb10ab2caa5a1d047a6d631af0a Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 12:27:02 +0900 Subject: [PATCH 07/15] =?UTF-8?q?feat:=20Jdbc=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=EC=9D=98=20ArticleDao=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20DB=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/db/ArticleDao.java | 52 ++++++++++++++++++++++++++++++++ src/main/java/model/Article.java | 3 ++ 2 files changed, 55 insertions(+) create mode 100644 src/main/java/db/ArticleDao.java diff --git a/src/main/java/db/ArticleDao.java b/src/main/java/db/ArticleDao.java new file mode 100644 index 000000000..a06676018 --- /dev/null +++ b/src/main/java/db/ArticleDao.java @@ -0,0 +1,52 @@ +package db; + +import model.Article; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class ArticleDao { + + // 게시글 저장 + public void insert(Article article) { + String sql = "INSERT INTO ARTICLE (writer, title, contents) VALUES (?, ?, ?)"; + + try (Connection connection = ConnectionManager.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(sql)) { + + pstmt.setString(1, article.writer()); + pstmt.setString(2, article.title()); + pstmt.setString(3, article.contents()); + + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException("Failed to save article: " + e.getMessage()); + } + } + + // 게시글 조회 + public List
selectAll() { + String sql = "SELECT * FROM ARTICLE ORDER BY createdAt DESC"; + List
articles = new ArrayList<>(); + + try (Connection connection = ConnectionManager.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + Article article = new Article( + rs.getLong("id"), + rs.getString("writer"), + rs.getString("title"), + rs.getString("contents"), + rs.getTimestamp("createdAt").toLocalDateTime() + ); + articles.add(article); + } + } catch (SQLException e) { + throw new RuntimeException("Failed to retrieve article list: {}", e); + } + return articles; + } +} diff --git a/src/main/java/model/Article.java b/src/main/java/model/Article.java index 8b1e674df..729adda3b 100644 --- a/src/main/java/model/Article.java +++ b/src/main/java/model/Article.java @@ -3,4 +3,7 @@ import java.time.LocalDateTime; public record Article (Long id,String writer, String title, String contents, LocalDateTime createdAt) { + public Article(String writer, String title, String contents) { + this(null, writer, title, contents, null); + } } From e0bf06492cd688afc53bb2ef8fd933f561aa1770 Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 14:01:33 +0900 Subject: [PATCH 08/15] =?UTF-8?q?feat:=20AppConfig=EC=97=90=20ArticleDao?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EB=B0=8F=20=EA=B8=80=EC=93=B0=EA=B8=B0?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/config/AppConfig.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/webserver/config/AppConfig.java b/src/main/java/webserver/config/AppConfig.java index c401094b2..382ffa2a1 100644 --- a/src/main/java/webserver/config/AppConfig.java +++ b/src/main/java/webserver/config/AppConfig.java @@ -1,6 +1,8 @@ package webserver.config; +import db.ArticleDao; import db.Database; +import model.Article; import model.User; import webserver.SessionManager; import webserver.handler.Handler; @@ -13,11 +15,14 @@ public class AppConfig { private static final Database database = new Database(); + private static final ArticleDao articleDao = new ArticleDao(); private static final Handler userHandler = new UserRequestHandler(database); private static final Handler loginHandler = new LoginRequestHandler(database); private static final Handler logoutHandler = new LogoutRequestHandler(database); + private static final Handler articleWriteHandler = new ArticleWriteHandler(articleDao); + public static Map getRouteMappings() { Map mappings = new HashMap<>(); @@ -25,6 +30,8 @@ public static Map getRouteMappings() { mappings.put("/user/login", loginHandler); mappings.put("/user/logout", logoutHandler); + mappings.put("/article/create", articleWriteHandler); + Map staticPages = Map.of( "/", Config.DEFAULT_PAGE, "/registration", Config.REGISTRATION_PAGE, From 58576c6bf13d45a5fd42e61ac0fb47ef50c1b3ee Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 14:53:07 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor:=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=20=EC=A3=BC=EC=9E=85=20=EC=B2=B4=EA=B3=84=EC=97=90=20article?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/config/AppConfig.java | 5 +---- src/main/java/webserver/handler/ArticleWriteHandler.java | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 src/main/java/webserver/handler/ArticleWriteHandler.java diff --git a/src/main/java/webserver/config/AppConfig.java b/src/main/java/webserver/config/AppConfig.java index 382ffa2a1..78d39b42c 100644 --- a/src/main/java/webserver/config/AppConfig.java +++ b/src/main/java/webserver/config/AppConfig.java @@ -5,10 +5,7 @@ import model.Article; import model.User; import webserver.SessionManager; -import webserver.handler.Handler; -import webserver.handler.LoginRequestHandler; -import webserver.handler.LogoutRequestHandler; -import webserver.handler.UserRequestHandler; +import webserver.handler.*; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/webserver/handler/ArticleWriteHandler.java b/src/main/java/webserver/handler/ArticleWriteHandler.java new file mode 100644 index 000000000..cf85fb9b9 --- /dev/null +++ b/src/main/java/webserver/handler/ArticleWriteHandler.java @@ -0,0 +1,4 @@ +package webserver.handler; + +public class ArticleWriteHandler implements Handler { +} From cb4038ac729a8e9ad49f1d6f8a118594e43022ec Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 15:15:25 +0900 Subject: [PATCH 10/15] =?UTF-8?q?feat:=20article=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20ArticleWriteHandler=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/ArticleWriteHandler.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/webserver/handler/ArticleWriteHandler.java b/src/main/java/webserver/handler/ArticleWriteHandler.java index cf85fb9b9..c1267481d 100644 --- a/src/main/java/webserver/handler/ArticleWriteHandler.java +++ b/src/main/java/webserver/handler/ArticleWriteHandler.java @@ -1,4 +1,32 @@ package webserver.handler; +import db.ArticleDao; +import model.Article; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import webserver.HttpRequest; +import webserver.HttpResponse; +import webserver.config.Config; + public class ArticleWriteHandler implements Handler { + private static final Logger logger = LoggerFactory.getLogger(ArticleWriteHandler.class); + + private final ArticleDao articleDao; + + public ArticleWriteHandler(ArticleDao articleDao) { + this.articleDao = articleDao; + } + + @Override + public void process(HttpRequest request, HttpResponse response) { + String writer = request.getParameter("writer"); + String title = request.getParameter("title"); + String contents = request.getParameter("contents"); + + Article article = new Article(writer, title, contents); + + articleDao.insert(article); + + response.sendRedirect(Config.DEFAULT_PAGE); + } } From 213f2036dacb93cea00b02d7260052e21ea4c47f Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Tue, 13 Jan 2026 15:20:34 +0900 Subject: [PATCH 11/15] =?UTF-8?q?feat:=20article/index.html=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/config/AppConfig.java | 3 ++- src/main/java/webserver/config/Config.java | 1 + src/main/resources/static/article/index.html | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/webserver/config/AppConfig.java b/src/main/java/webserver/config/AppConfig.java index 78d39b42c..8802bf027 100644 --- a/src/main/java/webserver/config/AppConfig.java +++ b/src/main/java/webserver/config/AppConfig.java @@ -33,7 +33,8 @@ public static Map getRouteMappings() { "/", Config.DEFAULT_PAGE, "/registration", Config.REGISTRATION_PAGE, "/login", Config.LOGIN_PAGE, - "/mypage", Config.MY_PAGE + "/mypage", Config.MY_PAGE, + "/article", Config.ARTICLE_PAGE ); staticPages.forEach((path, filePath) -> diff --git a/src/main/java/webserver/config/Config.java b/src/main/java/webserver/config/Config.java index f41780e30..371689f71 100644 --- a/src/main/java/webserver/config/Config.java +++ b/src/main/java/webserver/config/Config.java @@ -7,6 +7,7 @@ public class Config { public static final String LOGIN_PAGE = "/login/index.html"; public static final String MAIN_PAGE = "/main/index.html"; public static final String MY_PAGE = "/mypage/index.html"; + public static final String ARTICLE_PAGE = "/article/index.html"; public static final String UTF_8 = "utf-8"; public static final String CRLF = "\r\n"; diff --git a/src/main/resources/static/article/index.html b/src/main/resources/static/article/index.html index 6d2c8eeef..7ae994591 100644 --- a/src/main/resources/static/article/index.html +++ b/src/main/resources/static/article/index.html @@ -12,7 +12,7 @@
  • - 글쓰기 + 글쓰기