Skip to content

Feat/add account#3

Open
hirotokaede0506-dotcom wants to merge 6 commits into
mainfrom
feat/add-account
Open

Feat/add account#3
hirotokaede0506-dotcom wants to merge 6 commits into
mainfrom
feat/add-account

Conversation

@hirotokaede0506-dotcom

@hirotokaede0506-dotcom hirotokaede0506-dotcom commented May 25, 2026

Copy link
Copy Markdown
Collaborator

account削除を作成
論理削除で削除されたらDBに時間を挿入

Summary by CodeRabbit

  • New Features

    • Added an authenticated account “delete me” endpoint that soft-deletes the current user and clears the active session.
    • Introduced request validation for the deletion payload (password with minimum length).
  • Bug Fixes / Security

    • Updated current-user authentication to treat soft-deleted accounts as unauthorized, preventing access after deletion.
  • Refactor

    • Organized the account APIs into dedicated routing and handler modules for cleaner expansion.

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: 6fe683c4-7042-4d30-944b-537ebcf2b073

📥 Commits

Reviewing files that changed from the base of the PR and between 6f41612 and 3cf10ad.

📒 Files selected for processing (5)
  • apps/api/src/extractors.rs
  • apps/api/src/handlers/accounts.rs
  • apps/api/src/handlers/mod.rs
  • apps/api/src/routes/accounts.rs
  • apps/api/src/routes/mod.rs
✅ Files skipped from review due to trivial changes (1)
  • apps/api/src/routes/accounts.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/src/handlers/mod.rs

📝 Walkthrough

Walkthrough

This PR introduces account deletion capability with two handler implementations: a session-based POST /delete endpoint and an authenticated POST /v1/accounts/me endpoint. Both validate a password-protected DeleteRequest, perform soft-delete by setting deleted_at timestamps, clear the user session, and enforce soft-delete filtering in the CurrentUser authentication extractor.

Changes

Account Deletion Endpoint

Layer / File(s) Summary
DeleteRequest payload contract
apps/api/src/payloads/account.rs, apps/api/src/payloads/mod.rs
DeleteRequest struct with a password field enforcing minimum 8-character validation; payload module exports the type for handler use.
Soft-delete filtering in authentication
apps/api/src/extractors.rs
CurrentUser extractor imports ColumnTrait and adds a query constraint to filter out users where deleted_at is not null, treating soft-deleted users as unauthorized.
Session-based account deletion handler
apps/api/src/handlers/account.rs, apps/api/src/handlers/mod.rs, apps/api/src/routes/account.rs
delete handler reads user_id from session, loads the user record, verifies the password hash, sets deleted_at to current UTC time, persists the update, removes user_id from session, and returns a success response. Endpoint documented with utoipa as POST /delete. Routes module registered in handlers/mod.rs.
Authenticated account deletion handler and route integration
apps/api/src/handlers/accounts.rs, apps/api/src/routes/accounts.rs, apps/api/src/routes/mod.rs
delete handler uses AuthUser extractor to obtain the authenticated user, verifies password, performs soft-delete, clears the session, and returns success for POST /v1/accounts/me. Routes are wired into the /v1/accounts namespace via routes/mod.rs.

Sequence Diagram

sequenceDiagram
  participant Client
  participant AuthUser as AuthUser extractor
  participant DeleteHandler as delete handler
  participant DB as SeaORM DB
  participant Session
  
  Client->>DeleteHandler: POST /v1/accounts/me with password
  DeleteHandler->>AuthUser: Extract authenticated user_id
  AuthUser->>DB: Load user (DeletedAt IS NULL)
  DeleteHandler->>DB: Verify password hash
  DeleteHandler->>DB: Update user.deleted_at = now
  DeleteHandler->>Session: Remove user_id
  DeleteHandler->>Client: Return "Delete success"
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A carrot account bids its farewell,
With password checked and timestamp's bell,
Soft-deleted now from auth's embrace,
A graceful exit, time and space. 🥕✨


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

@gemini-code-assist gemini-code-assist 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.

Code Review

このプルリクエストでは、ユーザーアカウントの論理削除機能が追加されました。具体的には、usersエンティティへのdeleted_atフィールドの追加、アカウント削除用のハンドラーの実装、および関連するルーティングの設定が行われています。レビューでは、セッションからのuser_id取得時における型不一致(i64ではなくUuidを使用すべき点)という重大なバグの指摘に加え、未使用のインポートの削除、タイムスタンプ取得処理の簡略化、およびインポート記述の一貫性に関する改善提案が行われました。

Comment on lines +25 to +27
let user_id:i64 = session
.get::<i64>("user_id")
.ok_or(AuthError::Forbidden)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

セッションから user_id を取得する際、型が i64 と指定されていますが、users エンティティの主キーは uuid::Uuid 型です。auth.rs でのセッション保存時も Uuid が使用されているため、このままでは型不一致によりセッションの取得に失敗し、常に Forbidden エラーが返されることになります。

Suggested change
let user_id:i64 = session
.get::<i64>("user_id")
.ok_or(AuthError::Forbidden)?;
let user_id = session
.get::<uuid::Uuid>("user_id")
.ok_or(AuthError::Forbidden)?;

Comment thread apps/api/src/handlers/account.rs Outdated
use sea_orm::{ColumnTrait, QueryFilter};
use chrono::{Utc, FixedOffset};
use crate::entities::users;
use crate::{AppState, models::user, utils::auth::AuthError};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

crate::models::user はこのファイル内で使用されていないため、インポートを削除できます。

Suggested change
use crate::{AppState, models::user, utils::auth::AuthError};
use crate::{AppState, utils::auth::AuthError};

Comment thread apps/api/src/handlers/account.rs Outdated
.one(&state.db)
.await?
.ok_or(AuthError::Forbidden)?;
let now = Utc::now().with_timezone(&FixedOffset::east_opt(0).unwrap());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

現在時刻の取得は Utc::now().fixed_offset() を使用することで、より簡潔に記述できます。これは auth.rs など他の箇所で使用されているスタイルとも一致します。

Suggested change
let now = Utc::now().with_timezone(&FixedOffset::east_opt(0).unwrap());
let now = Utc::now().fixed_offset();

Comment thread apps/api/src/routes/mod.rs Outdated
use utoipa_axum::router::OpenApiRouter;

use crate::AppState;
use crate::{AppState, routes::auth::routes};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

routes::auth::routes をインポートしていますが、下の nest メソッド内では完全修飾名 crate::routes::auth::routes() が使用されています。一貫性のため、このインポートは削除することをお勧めします。

Suggested change
use crate::{AppState, routes::auth::routes};
use crate::AppState;

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 1, 2026

Copy link
Copy Markdown

Deploying storage with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3cf10ad
Status: ✅  Deploy successful!
Preview URL: https://27d6f9e1.storage-2lm.pages.dev
Branch Preview URL: https://feat-add-account.storage-2lm.pages.dev

View logs

@SHO-Y-Git
SHO-Y-Git marked this pull request as draft June 1, 2026 05:03
@yupix
yupix force-pushed the feat/add-account branch from eb1d3f7 to ab8d356 Compare June 8, 2026 03:58
@hirotokaede0506-dotcom
hirotokaede0506-dotcom marked this pull request as ready for review June 8, 2026 06:02
Repository owner deleted a comment from netlify Bot Jun 8, 2026

@yupix yupix left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

レビュー結果

アカウント削除機能には、動作を妨げる重大な問題が4件あります。

  • 削除ルーターがアプリケーションへ登録されていない
  • API仕様の DELETE /v1/accounts/me と実装が一致しない
  • 論理削除後も再ログインできる
  • セッションの user_idi64 として取得している

user_id の型不一致については、既存のインラインコメントですでに具体的に指摘されていますが、現在の先端コミットでも未修正です。ログイン時には Uuid を保存しているため、削除処理側も Uuid として取得する必要があります。

4件とも、アカウント削除機能を正常に成立させるための P1(優先度: 高) の問題です。


pub fn routes() -> OpenApiRouter<AppState> {
OpenApiRouter::<AppState>::new()
.routes(routes!(crate::handlers::account::delete))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

[P1] アカウント削除ルーターを登録する

このルーターは routes/mod.rs でモジュールとして公開されておらず、create_routes() にもネストされていません。そのため、削除エンドポイントへのリクエストは常に 404 になります。pub mod account; を追加し、/v1/accounts 配下へこのルーターを登録してください。


#[utoipa::path(
post,
path = "/delete",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

[P1] API仕様どおりのメソッドとパスを公開する

API仕様は DELETE /v1/accounts/me ですが、現在は POST /delete として定義されています。ルーターを登録しても仕様準拠のクライアントから利用できないため、メソッドを delete、パスを /me に合わせてください。

let now = Utc::now().fixed_offset();
// 削除
let mut active: users::ActiveModel = user.into();
active.deleted_at = Set(Some(now));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

[P1] 論理削除済みユーザーの再認証を拒否する

ここで deleted_at を設定してセッションを削除しても、ログイン処理は deleted_at を確認していません。そのため、削除直後に同じメールアドレスとパスワードで再ログインできます。ログイン検索時に未削除ユーザーだけを対象にし、認証Extractor側でも論理削除済みユーザーを拒否してください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants