Feature/node api - #31
Conversation
概要新しいNode.js/TypeScriptウェブアプリケーション用の完全なプロジェクト構成が 変更内容
推定コード審査時間🎯 3 (中程度) | ⏱️ ~20 分 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
webapp/node/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
webapp/node/.gitignorewebapp/node/Dockerfilewebapp/node/README.mdwebapp/node/package.jsonwebapp/node/src/index.tswebapp/node/tsconfig.json
| .env | ||
| .env.production |
There was a problem hiding this comment.
環境ファイルの無視パターンを広げた方が安全です。
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.
| .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.
| 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"] |
There was a problem hiding this comment.
コンテナが 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.
| 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
(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.
| ``` | ||
| npm install | ||
| npm run dev | ||
| ``` |
There was a problem hiding this comment.
コードフェンスに言語指定を追加してください。
Line 1 と Line 6 の fenced code block に言語指定がなく、markdownlint (MD040) 警告が発生します。
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 を再実行してください。
| 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', | ||
| }) |
There was a problem hiding this comment.
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.
| 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.
| // 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] |
There was a problem hiding this comment.
更新処理の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.
There was a problem hiding this comment.
@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).
Summary by CodeRabbit
リリースノート
New Features
Chores
Documentation