Skip to content
This repository was archived by the owner on Apr 17, 2026. It is now read-only.

Feature/node api - #31

Merged
kirikirisu merged 2 commits into
mainfrom
feature/node-api
Mar 6, 2026
Merged

Feature/node api#31
kirikirisu merged 2 commits into
mainfrom
feature/node-api

Conversation

@kirikirisu

@kirikirisu kirikirisu commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

リリースノート

  • New Features

    • プレスリリース管理用のAPI機能を追加しました。個別のプレスリリースの取得と更新が可能になります。
  • Chores

    • Node.js/TypeScriptプロジェクト環境を新規構築しました。Docker対応、開発用スクリプト、依存関係管理を含みます。
  • Documentation

    • セットアップと開発手順のドキュメントを追加しました。

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown

概要

新しいNode.js/TypeScriptウェブアプリケーション用の完全なプロジェクト構成が webapp/node ディレクトリに追加された。Hono フレームワークを使用したHTTP APIサーバー、PostgreSQL統合、開発環境設定、Dockerコンテナ化設定を含む。

変更内容

コホート / ファイル 概要
プロジェクト設定
webapp/node/package.json, webapp/node/tsconfig.json, webapp/node/.gitignore
Node.js ESMプロジェクトの依存関係定義、TypeScript設定(ESNext、NodeNext、strict型チェック、Hono JSX)、開発アーティファクト用の除外パターン。
コンテナ化とドキュメント
webapp/node/Dockerfile, webapp/node/README.md
Node.js 24ベースのDockerイメージ、PostgreSQLクライアント統合、開発手順ドキュメント。
APIサーバー実装
webapp/node/src/index.ts
Honoフレームワークを使用したHTTP APIサーバー。PostgreSQL接続プーラ(シングルトン)、GET/POSTエンドポイント(プレスリリース取得・更新)、Zod検証、CORS対応、ISO 8601タイムスタンプフォーマット、構造化エラーハンドリング。

推定コード審査時間

🎯 3 (中程度) | ⏱️ ~20 分

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive タイトル「Feature/node api」は変更セットの主要な内容を十分に説明しておらず、不正確かつ曖昧です。実際の変更はNode.js HTTPサーバー、PostgreSQL統合、複数の設定ファイルを含む新しいモジュールの追加ですが、タイトルはこれらを明確に伝えていません。 例えば「Add Node.js API server with PostgreSQL integration」など、変更の主要な目的をより具体的に説明するタイトルに変更してください。
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/node-api

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@webapp/node/.gitignore`:
- Around line 15-16: Update the .gitignore patterns so all env variants are
ignored: replace the specific entries ".env" and ".env.production" with a single
inclusive pattern ".env.*" and explicitly allow the example file by adding an
exception for ".env.example"; ensure the final .gitignore contains the ".env.*"
ignore rule and a "!.env.example" allow rule so that .env.local,
.env.development, etc. are ignored but the sample file remains tracked.

In `@webapp/node/Dockerfile`:
- Around line 1-27: The Dockerfile currently runs as root because there is no
USER instruction; fix by creating or switching to a non-root user and ensuring
/app is owned by that user before running build/run steps: add a non-root user
(or use existing 'node' user in node:24-slim), chown the WORKDIR (/app) and any
created files (after COPY and before RUN npm run build), and add a USER
<username> line (placed before EXPOSE/CMD) so the runtime and build steps do not
execute as root; reference symbols: Dockerfile, WORKDIR /app, COPY . ., RUN npm
run build, CMD ["npm", "start"], and the USER directive.

In `@webapp/node/README.md`:
- Around line 1-4: README.md の2つの fenced code block(1〜2行の "npm install / npm run
dev" ブロックと 6〜8行の "open http://localhost:3000" ブロック)に言語指定がなく markdownlint の MD040
警告が出ているので、それぞれの開始バックティックに言語タグを追加してください(例: ```bash)。該当箇所は "npm install" と "npm
run dev" を含むコードブロック、及び "open http://localhost:3000" を含むコードブロックです。タグを追加したら
README.md を保存して lint を再実行してください。

In `@webapp/node/src/index.ts`:
- Around line 133-152: The current three-query flow (checkResult query, UPDATE,
then SELECT) can race and cause a 500 if the row vanishes; replace it with a
single parameterized UPDATE ... RETURNING id, title, content, created_at,
updated_at using the existing pool and parameters (id, title, content) and use
the returned rows: if no rows returned, return c.json({ code: 'NOT_FOUND',
message: 'Press release not found' }, 404); otherwise use the returned row as
the updated press release; ensure you remove the separate existence check and
SELECT and keep error handling around the single UPDATE ... RETURNING operation.
- Around line 17-25: getPool currently passes parseInt(process.env.DB_PORT ||
'5432') directly to new Pool which can yield NaN for invalid DB_PORT; validate
and sanitize process.env.DB_PORT (use parseInt(...,10)), check Number.isInteger
and that port is within valid TCP range (1–65535), and fall back to 5432 when
invalid; update the port value used in the Pool config inside getPool and
reference process.env.DB_PORT, getPool, and Pool when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 66ffaa34-033c-4b9e-ae3d-05fb17c3693e

📥 Commits

Reviewing files that changed from the base of the PR and between 41d776a and 55b82f3.

⛔ Files ignored due to path filters (1)
  • webapp/node/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • webapp/node/.gitignore
  • webapp/node/Dockerfile
  • webapp/node/README.md
  • webapp/node/package.json
  • webapp/node/src/index.ts
  • webapp/node/tsconfig.json

Comment thread webapp/node/.gitignore
Comment on lines +15 to +16
.env
.env.production

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

環境ファイルの無視パターンを広げた方が安全です。

Line 15〜16 だと .env.local.env.development が追跡対象になり得ます。秘密情報混入防止のため .env.* を包括し、共有用に .env.example だけ許可する形が安全です。

🔐 修正案
 .env
-.env.production
+.env.*
+!.env.example
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.env
.env.production
.env
.env.*
!.env.example
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webapp/node/.gitignore` around lines 15 - 16, Update the .gitignore patterns
so all env variants are ignored: replace the specific entries ".env" and
".env.production" with a single inclusive pattern ".env.*" and explicitly allow
the example file by adding an exception for ".env.example"; ensure the final
.gitignore contains the ".env.*" ignore rule and a "!.env.example" allow rule so
that .env.local, .env.development, etc. are ignored but the sample file remains
tracked.

Comment thread webapp/node/Dockerfile
Comment on lines +1 to +27
FROM node:24-slim

WORKDIR /app

# Install PostgreSQL client libraries
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy application files
COPY . .

# Build TypeScript
RUN npm run build

# Expose port
EXPOSE 8080

# Run the application
CMD ["npm", "start"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

コンテナが root 実行のままです。

Line 1〜27 では USER 指定がなく、実行時に root 権限になります。侵害時の影響を下げるため non-root 実行にしてください。

🔒 修正案
 FROM node:24-slim
@@
 # Build TypeScript
 RUN npm run build
+
+RUN chown -R node:node /app
+USER node
 
 # Expose port
 EXPOSE 8080
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM node:24-slim
WORKDIR /app
# Install PostgreSQL client libraries
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy application files
COPY . .
# Build TypeScript
RUN npm run build
# Expose port
EXPOSE 8080
# Run the application
CMD ["npm", "start"]
FROM node:24-slim
WORKDIR /app
# Install PostgreSQL client libraries
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy application files
COPY . .
# Build TypeScript
RUN npm run build
RUN chown -R node:node /app
USER node
# Expose port
EXPOSE 8080
# Run the application
CMD ["npm", "start"]
🧰 Tools
🪛 Trivy (0.69.2)

[error] 1-1: Image user should not be 'root'

Specify at least 1 USER command in Dockerfile with non-root user as argument

Rule: DS-0002

Learn more

(IaC/Dockerfile)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webapp/node/Dockerfile` around lines 1 - 27, The Dockerfile currently runs as
root because there is no USER instruction; fix by creating or switching to a
non-root user and ensuring /app is owned by that user before running build/run
steps: add a non-root user (or use existing 'node' user in node:24-slim), chown
the WORKDIR (/app) and any created files (after COPY and before RUN npm run
build), and add a USER <username> line (placed before EXPOSE/CMD) so the runtime
and build steps do not execute as root; reference symbols: Dockerfile, WORKDIR
/app, COPY . ., RUN npm run build, CMD ["npm", "start"], and the USER directive.

Comment thread webapp/node/README.md
Comment on lines +1 to +4
```
npm install
npm run dev
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

コードフェンスに言語指定を追加してください。

Line 1 と Line 6 の fenced code block に言語指定がなく、markdownlint (MD040) 警告が発生します。

🔧 修正案
-```
+```bash
 npm install
 npm run dev

- +bash
open http://localhost:3000

Also applies to: 6-8

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 1-1: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webapp/node/README.md` around lines 1 - 4, README.md の2つの fenced code
block(1〜2行の "npm install / npm run dev" ブロックと 6〜8行の "open http://localhost:3000"
ブロック)に言語指定がなく markdownlint の MD040 警告が出ているので、それぞれの開始バックティックに言語タグを追加してください(例:
```bash)。該当箇所は "npm install" と "npm run dev" を含むコードブロック、及び "open
http://localhost:3000" を含むコードブロックです。タグを追加したら README.md を保存して lint を再実行してください。

Comment thread webapp/node/src/index.ts
Comment on lines +17 to +25
function getPool(): pkg.Pool {
if (!pool) {
pool = new Pool({
host: process.env.DB_HOST || 'postgresql',
port: parseInt(process.env.DB_PORT || '5432'),
database: process.env.DB_NAME || 'press_release_db',
user: process.env.DB_USER || 'press_release',
password: process.env.DB_PASSWORD || 'press_release',
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

DB_PORT が不正値のときに NaN が接続設定へ渡ります。

Line 21 は環境変数が不正な場合でも parseInt の結果をそのまま使うため、接続失敗時の原因が分かりづらくなります。整数・範囲チェック付きでフォールバックしてください。

🛠️ 修正案
 function getPool(): pkg.Pool {
   if (!pool) {
+    const parsedPort = Number(process.env.DB_PORT)
+    const dbPort = Number.isInteger(parsedPort) && parsedPort > 0 ? parsedPort : 5432
+
     pool = new Pool({
       host: process.env.DB_HOST || 'postgresql',
-      port: parseInt(process.env.DB_PORT || '5432'),
+      port: dbPort,
       database: process.env.DB_NAME || 'press_release_db',
       user: process.env.DB_USER || 'press_release',
       password: process.env.DB_PASSWORD || 'press_release',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function getPool(): pkg.Pool {
if (!pool) {
pool = new Pool({
host: process.env.DB_HOST || 'postgresql',
port: parseInt(process.env.DB_PORT || '5432'),
database: process.env.DB_NAME || 'press_release_db',
user: process.env.DB_USER || 'press_release',
password: process.env.DB_PASSWORD || 'press_release',
})
function getPool(): pkg.Pool {
if (!pool) {
const parsedPort = Number(process.env.DB_PORT)
const dbPort = Number.isInteger(parsedPort) && parsedPort > 0 ? parsedPort : 5432
pool = new Pool({
host: process.env.DB_HOST || 'postgresql',
port: dbPort,
database: process.env.DB_NAME || 'press_release_db',
user: process.env.DB_USER || 'press_release',
password: process.env.DB_PASSWORD || 'press_release',
})
}
return pool
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webapp/node/src/index.ts` around lines 17 - 25, getPool currently passes
parseInt(process.env.DB_PORT || '5432') directly to new Pool which can yield NaN
for invalid DB_PORT; validate and sanitize process.env.DB_PORT (use
parseInt(...,10)), check Number.isInteger and that port is within valid TCP
range (1–65535), and fall back to 5432 when invalid; update the port value used
in the Pool config inside getPool and reference process.env.DB_PORT, getPool,
and Pool when making the change.

Comment thread webapp/node/src/index.ts
Comment on lines +133 to +152
// Check if press release exists
const checkResult = await pool.query('SELECT id FROM press_releases WHERE id = $1', [id])

if (checkResult.rows.length === 0) {
return c.json({ code: 'NOT_FOUND', message: 'Press release not found' }, 404)
}

// Update press release
await pool.query(
'UPDATE press_releases SET title = $1, content = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $3',
[title, content, id]
)

// Get updated data
const result = await pool.query(
'SELECT id, title, content, created_at, updated_at FROM press_releases WHERE id = $1',
[id]
)

const row = result.rows[0]

@coderabbitai coderabbitai Bot Mar 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

更新処理の3クエリ構成は競合時に 500 を返し得ます。

Line 133〜152 の 存在確認 -> UPDATE -> SELECT は、並行更新や削除が入ると row が取れず 500 へ落ちる可能性があります。UPDATE ... RETURNING に統合して、0件更新を 404 で返す方が安全です。

🧩 修正案
-    // Check if press release exists
-    const checkResult = await pool.query('SELECT id FROM press_releases WHERE id = $1', [id])
-
-    if (checkResult.rows.length === 0) {
-      return c.json({ code: 'NOT_FOUND', message: 'Press release not found' }, 404)
-    }
-
-    // Update press release
-    await pool.query(
-      'UPDATE press_releases SET title = $1, content = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $3',
-      [title, content, id]
-    )
-
-    // Get updated data
-    const result = await pool.query(
-      'SELECT id, title, content, created_at, updated_at FROM press_releases WHERE id = $1',
-      [id]
-    )
-
-    const row = result.rows[0]
+    const updateResult = await pool.query(
+      `UPDATE press_releases
+       SET title = $1, content = $2, updated_at = CURRENT_TIMESTAMP
+       WHERE id = $3
+       RETURNING id, title, content, created_at, updated_at`,
+      [title, content, id]
+    )
+
+    if (updateResult.rows.length === 0) {
+      return c.json({ code: 'NOT_FOUND', message: 'Press release not found' }, 404)
+    }
+
+    const row = updateResult.rows[0]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webapp/node/src/index.ts` around lines 133 - 152, The current three-query
flow (checkResult query, UPDATE, then SELECT) can race and cause a 500 if the
row vanishes; replace it with a single parameterized UPDATE ... RETURNING id,
title, content, created_at, updated_at using the existing pool and parameters
(id, title, content) and use the returned rows: if no rows returned, return
c.json({ code: 'NOT_FOUND', message: 'Press release not found' }, 404);
otherwise use the returned row as the updated press release; ensure you remove
the separate existence check and SELECT and keep error handling around the
single UPDATE ... RETURNING operation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

他言語と合わせるためスキップ

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirikirisu、承知しました。他言語実装との一貫性を優先するご判断、了解です。


🧠 Learnings used
Learnt from: CR
Repo: PRTIMES/hackathon2026-spring-press-release-editor PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-16T09:55:54.673Z
Learning: API endpoints must implement GET /press-releases/:id and POST /press-releases/:id (for updates only), returning 404 for non-existent IDs

Learnt from: lll-lll-lll-lll
Repo: PRTIMES/prtimes-frontend PR: 12733
File: apps/prtimes/src/features/press-release-editor-v3/hooks/use-verify-blocklist-domains/index.ts:0-0
Timestamp: 2026-02-25T04:33:11.959Z
Learning: PRTIMES/prtimes-frontend の apps/prtimes/src/features/press-release-editor-v3/hooks/use-verify-blocklist-domains において、現在のエラーハンドリング実装は暫定的なもので、将来的にTanStack Queryのエラーハンドリング機構に統合される予定。そのため、catch ブロック内の error シリアライズ処理の改善は不要。
<!-- [add_learning]

Learnt from: miyabin4113
Repo: PRTIMES/prtimes-frontend PR: 12381
File: apps/prtimes/src/features/press-release-editor-v3/components/AnnouncementBanner/announcement-banner.stories.tsx:1-88
Timestamp: 2026-02-06T02:36:44.258Z
Learning: PRTIMES/prtimes-frontend リポジトリでは、人間のレビュアーがPRを確認する前に、CodeRabbitのレビューコメントを全てクローズ(解決)しておくことが好ましい。これは、CodeRabbitの指摘が正しかった場合だけでなく、指摘が誤りであった場合も含む。

Learnt from: lll-lll-lll-lll
Repo: PRTIMES/prtimes-frontend PR: 12734
File: apps/prtimes/src/features/press-release-editor-v3/layouts/pc/edit-template.tsx:0-0
Timestamp: 2026-02-25T03:43:27.914Z
Learning: PRTIMES/prtimes-frontend の apps/prtimes/src/features/press-release-editor-v3/layouts/pc/edit-template.tsx において、編集画面オープン時のブロックリストドメイン判定API (verifyBlocklistDomains) で例外が発生した場合は、エラーを握りつぶして編集作業を継続可能な状態にする。これは補助的な警告機能であるため、検証失敗時もユーザーの編集作業を妨げないフェイルセーフ設計が採用されている。

Learnt from: dungbuike-prts
Repo: PRTIMES/prtimes PR: 13638
File: tests/docker/initdb/01_schema.sql:26874-26875
Timestamp: 2025-12-10T08:16:37.923Z
Learning: PRTIMES/prtimes `#13638` (GROO-656): media_user_login_history のインデックスは (media_user_id, login_timestamp DESC) が正で、PR objectives にあった media_id は company 側仕様からの誤転記のため不要。今後のレビューでは media_id を要求しない。

Learnt from: miyabin4113
Repo: PRTIMES/prtimes-frontend PR: 12406
File: apps/prtimes/src/features/press-release-editor-v3/hooks/api/use-auto-save.tsx:171-206
Timestamp: 2026-02-05T07:04:31.299Z
Learning: PRTIMES/prtimes-frontend の apps/prtimes/src/features/press-release-editor-v3/hooks/api/use-auto-save.tsx では、PressReleaseImageAtomIdListState の重複画像削除処理は API 呼び出し前に実行される。これは保存時に毎回UI状態の不整合を即座に修正するためで、画像が上書き保存されるためサーバー側との一時的な不整合は許容される設計となっている。

Learnt from: raiga0310
Repo: PRTIMES/prtimes PR: 13809
File: htdocs/inc/PRTIMES/PrTimes/Feature/MonolithApi/Repo/PressReleaseRepo.php:63-63
Timestamp: 2026-01-08T09:37:02.431Z
Learning: In PRTIMES/prtimes monolith-api replacement (PRTIMES-6229), the agency_name field in the /press_releases endpoint should return m_company.pr_company_name according to the monolith-api specification, not an empty string. The test GetPressReleasesActionTest expects 'テストPR会社' for agency_name.

Learnt from: shogogg
Repo: PRTIMES/prtimes PR: 13748
File: htdocs/inc/PRTIMES/PrTimes/Feature/Dashboard/Repo/StartupChallengeCompanyRepo.php:41-44
Timestamp: 2025-12-22T08:52:19.706Z
Learning: Repository: PRTIMES/prtimes
Context: Database usage
Learning: このリポジトリは PostgreSQL を使用している。PostgreSQL では `column != 0` のような比較演算は native boolean 型を返すため、PDO 経由で取得する際に明示的な bool キャストは不要である。

Learnt from: shogogg
Repo: PRTIMES/prtimes PR: 13578
File: .coderabbit.yaml:1-40
Timestamp: 2025-12-03T04:43:28.405Z
Learning: In the PR `#13578` for PRTIMES-6211, the user shogogg is taking a two-step approach: first organizing and tidying the .coderabbit.yaml configuration file (current PR), then implementing the actual feature change to disable label suggestions (next PR).

@kirikirisu
kirikirisu merged commit 86aef67 into main Mar 6, 2026
3 checks passed
@sucalul
sucalul deleted the feature/node-api branch March 6, 2026 12:27
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant