Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
9c6ae54
feat: フロントページのスタイルを更新
umekikazuya Apr 21, 2026
13f0256
chore: 管理画面でアニメーション等が当たらないよう実装を見直し
umekikazuya Apr 21, 2026
85b7e9f
Merge branch 'develop' into feat/brushup-frontpage
umekikazuya Apr 22, 2026
7526013
feat: 記事検索、タグの開閉ボタンにaria-属性を追加
umekikazuya Apr 22, 2026
d76910a
fix: ビューポート外でスポットライトが残留する可能性があるのでケア
umekikazuya Apr 22, 2026
2c93fb3
Merge branch 'develop' into feat/brushup-frontpage
umekikazuya Apr 23, 2026
de60aed
Merge branch 'develop' into feat/admin-theme
umekikazuya Apr 23, 2026
1d18eda
Merge branch 'develop' into feat/brushup-frontpage
umekikazuya Apr 23, 2026
afb1029
feat: 選択中のタグを折りたたみ表示で隠さないように実装を更新
umekikazuya Apr 23, 2026
9ff448b
fix: レビュー対応
umekikazuya Apr 23, 2026
dc2e854
fix: レビュー対応
umekikazuya Apr 23, 2026
d834883
Merge pull request #73 from umekikazuya/feat/brushup-frontpage
umekikazuya Apr 23, 2026
3c28d41
Merge branch 'develop' into feat/admin-theme
umekikazuya Apr 23, 2026
95435ea
Merge pull request #74 from umekikazuya/feat/admin-theme
umekikazuya Apr 23, 2026
f23d530
feat: カラートークンの整理
umekikazuya Apr 23, 2026
a9c450e
Merge pull request #79 from umekikazuya/feat/color-token
umekikazuya Apr 23, 2026
9f29e62
refactor: フロントエンドのルーティングの責務を明文化
umekikazuya Apr 23, 2026
f5f86c6
feat: テーマ設定
umekikazuya Apr 23, 2026
d4bf57c
feat: ロギング設計
umekikazuya Apr 23, 2026
a947592
fix: デバッグコードの削除
umekikazuya Apr 23, 2026
7b6805d
feat: リクエストの整理
umekikazuya Apr 23, 2026
b97e366
feat: リアーキ
umekikazuya Apr 23, 2026
e18a30f
feat: otel導入
umekikazuya Apr 23, 2026
169634f
fix: レビュー対応
umekikazuya Apr 23, 2026
872197a
fix: レビュー対応
umekikazuya Apr 24, 2026
76c0279
fix: レビュー対応
umekikazuya Apr 24, 2026
eb5892e
Merge pull request #80 from umekikazuya/feat/logging
umekikazuya Apr 24, 2026
d261319
feat: APIのグレースフルシャットダウン機能
umekikazuya Apr 24, 2026
102bfc9
Merge branch 'develop' into refactor/front-context
umekikazuya Apr 24, 2026
db98466
refactor: 責務見直し
umekikazuya Apr 24, 2026
4d30a99
feat: コンポーネント設計を見直し
umekikazuya Apr 25, 2026
ee9e42e
fix: apply CodeRabbit auto-fixes
coderabbitai[bot] Apr 25, 2026
3b61562
Merge pull request #83 from umekikazuya/coderabbitai/autofix/d261319
umekikazuya Apr 25, 2026
12f9307
feat: コンポーネント設計
umekikazuya Apr 25, 2026
e39866b
feat: レイヤ設計を見直し
umekikazuya Apr 25, 2026
a94647a
fix: フォーマット設定
umekikazuya Apr 25, 2026
2cac241
fix: レビュー対応
umekikazuya Apr 26, 2026
1248d41
feat: コンポーネント設計
umekikazuya Apr 26, 2026
bd5c0fb
feat: コンポーネント設計
umekikazuya Apr 26, 2026
b03e099
Merge pull request #81 from umekikazuya/refactor/front-context
umekikazuya Apr 26, 2026
c69b7a7
chore: biomeのリント設定に複雑度を厳格に見るよう指定
umekikazuya Apr 26, 2026
116b8da
feat: miseツールに gotestsum を追加
umekikazuya Apr 26, 2026
e863b9a
fix: 複雑度のCi設定を警告からエラーに引き上げ
umekikazuya Apr 26, 2026
037b6a0
Merge pull request #85 from umekikazuya/chore/tool-gotestsum
umekikazuya Apr 26, 2026
d807d8c
Merge pull request #84 from umekikazuya/chore/biome-lint
umekikazuya Apr 26, 2026
9b1e3fb
fix: シャットダウンについて指摘事項修正
umekikazuya Apr 26, 2026
0694c22
Merge pull request #82 from umekikazuya/feat/api-graceful-shutdown
umekikazuya Apr 26, 2026
972036b
chore: slog-lintを導入
umekikazuya Apr 26, 2026
620ecd3
fix: slog-lint: key-naming-case設定を削除
umekikazuya Apr 26, 2026
4cb243d
Merge pull request #86 from umekikazuya/chore/slog-lint
umekikazuya Apr 26, 2026
04c1e22
refactor: 管理画面コードのリファクタリング
umekikazuya Apr 26, 2026
92085bd
fix: リントの適用
umekikazuya Apr 26, 2026
8878673
fix: レビュー対応
umekikazuya Apr 26, 2026
2b2ad36
fix: アニメーション
umekikazuya Apr 26, 2026
5130c29
Merge pull request #87 from umekikazuya/refactor/admin-page
umekikazuya Apr 26, 2026
4e1350d
fix: biome設定を更新
umekikazuya Apr 27, 2026
3aa7769
Merge pull request #89 from umekikazuya/fix/88
umekikazuya Apr 27, 2026
36b89c0
refactor: 仕様書に基づいてコンポーネントを再設計
umekikazuya Apr 27, 2026
524658e
feat: `data-theme`初期化ロジックを見直し
umekikazuya Apr 27, 2026
528f22c
feat: ログインページでセッション再確認を実行するよう調整
umekikazuya Apr 27, 2026
f769209
docs: サブモジュール更新
umekikazuya Apr 27, 2026
8e17c6f
Merge pull request #91 from umekikazuya/docs/sync
umekikazuya Apr 27, 2026
2456786
Merge pull request #90 from umekikazuya/refactor/frontend
umekikazuya Apr 27, 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
6 changes: 6 additions & 0 deletions backend/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ linters:
- nolintlint
- prealloc
- rowserrcheck
- sloglint
- sqlclosecheck
- staticcheck
- tparallel
- unconvert
- unparam
- whitespace
- wrapcheck
settings:
sloglint:
no-mixed-args: true
context: scope
static-msg: true
exclusions:
rules:
- text: '(slog|log)\.\w+'
Expand Down
118 changes: 105 additions & 13 deletions backend/cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ package main
import (
"context"
"encoding/json"
"errors"
"log/slog"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"

"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"

"github.com/umekikazuya/me/internal/app/eventhandler"
"github.com/umekikazuya/me/internal/app/identity"
appme "github.com/umekikazuya/me/internal/app/me"
Expand All @@ -18,27 +23,65 @@ import (
infraevent "github.com/umekikazuya/me/internal/infra/event"
"github.com/umekikazuya/me/internal/infra/token"
"github.com/umekikazuya/me/pkg/middleware"
"github.com/umekikazuya/me/pkg/slogx"
"github.com/umekikazuya/me/pkg/obs"
)

// shutdownTimeout は SIGINT/SIGTERM 受信後にインフライトリクエストを捌き切る猶予。
// ALB / API Gateway のドレイン時間との整合を意識して設定する。
const shutdownTimeout = 30 * time.Second

func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
// run に集約するのは os.Exit が defer をスキップするため。
// 直接 main で os.Exit すると obs の shutdown が走らず traces/metrics が flush されない。
os.Exit(run())
}

// ロガー初期化
slog.SetDefault(slogx.New(os.Stdout))
func run() int {
ctx := context.Background()

// 観測性基盤初期化: logs / traces / metrics を stdout に出す。
// アクセスログはインフラ層 (API Gateway/ALB 等) の責務とし、アプリでは出さない。
prov, shutdown, err := obs.Bootstrap(ctx, obs.Config{
ServiceName: "api",
Level: obs.ParseLevel(os.Getenv("LOG_LEVEL")),
SensitiveKeys: []string{"password", "password_hash", "authorization", "cookie", "set-cookie", "token", "refresh_token"},
AddSource: true,
EnableTraces: true,
EnableMetrics: true,
})
if err != nil {
slog.Error("観測性基盤の初期化に失敗しました", "error", err)
return 1
}
// shutdown は長寿命な ctx に縛られないよう、呼び出し時に bounded な context を渡す。
// ListenAndServe から戻った時点では元 ctx が cancel 済みの可能性があり、
// その場合 tracer/meter の flush が即座に諦められてしまう。
// signal 受信時に作成した共有 shutdownCtx を使うことで、HTTP と observability の
// shutdown が同一タイムアウト予算を共有し、合計で shutdownTimeout 以内に収まる。
var shutdownCtx context.Context
var shutdownCancel context.CancelFunc
defer func() {
if shutdownCtx == nil {
shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), 5*time.Second)
}
Comment on lines +63 to +66
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

シャットダウンタイムアウトの不整合

Line 31 で shutdownTimeout = 30 * time.Second と定義されていますが、Line 65 のフォールバックでは 5*time.Second がハードコードされています。一貫性のため、定数を使用するか、フォールバック用に別の定数を定義することを推奨します。

🐛 修正案
 		if shutdownCtx == nil {
-			shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), 5*time.Second)
+			shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), shutdownTimeout)
 		}

または、早期終了時の短いタイムアウトが意図的であれば、コメントでその理由を説明してください。

📝 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
defer func() {
if shutdownCtx == nil {
shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), 5*time.Second)
}
defer func() {
if shutdownCtx == nil {
shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), shutdownTimeout)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/cmd/api/main.go` around lines 63 - 66, The defer uses a hardcoded 5s
fallback which mismatches the previously defined shutdownTimeout
(30*time.Second); replace the hardcoded 5*time.Second with the existing
shutdownTimeout constant (or introduce and use a clearly named constant like
shortShutdownTimeout if a shorter value is intentional) and update the defer
block that assigns shutdownCtx and shutdownCancel (referencing shutdownCtx,
shutdownCancel, shutdownTimeout) or add a brief comment explaining why a
different fallback is used.

_ = shutdown(shutdownCtx)
if shutdownCancel != nil {
shutdownCancel()
}
}()
slog.SetDefault(prov.Logger)

// 具像実装の初期化
meRepo, identityRepo, sessionRepo, articleInteractor, err := setupRepo(ctx)
if err != nil {
slog.Error("インフラの初期化に失敗しました", "error", err)
os.Exit(1)
return 1
}
articleHandler := handlerarticle.NewHandler(articleInteractor)
jwtSecret := strings.TrimSpace(os.Getenv("JWT_SECRET"))
if jwtSecret == "" {
slog.Error("JWT_SECRET が未設定です")
os.Exit(1)
return 1
}
tokenSrv := token.NewJWTTokenService(
jwtSecret,
Expand Down Expand Up @@ -129,19 +172,68 @@ func main() {
),
))

slog.Info("サーバーを起動します")

// サーバー起動
// middleware chain (外側 → 内側):
// RequestID (obs.WithRequestID で context に積む)
// → otelhttp (root span を作成、trace_id を context に載せる)
// → Recover (panic → 500 ProblemDetail + ERROR ログ、trace_id が自動で付く)
// → router
srv := &http.Server{
Addr: ":8080",
Handler: middleware.RequestID(middleware.Logging(r)),
Addr: ":8080",
Handler: middleware.RequestID(
otelhttp.NewHandler(
middleware.Recover(r),
"api",
),
),
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}
if err := srv.ListenAndServe(); err != nil {

// signal 受信準備を ListenAndServe の goroutine 起動より前に行う。
// 先に goroutine を起動すると、早期の SIGINT/SIGTERM がデフォルトハンドラで
// 処理され、graceful shutdown が実行されないリスクがある。
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigCh)

// ListenAndServe は別 goroutine で動かし、main は signal 受信を待つ。
// 起動直後に失敗 (port 競合など) した場合は srvErrCh から即座に戻る。
srvErrCh := make(chan error, 1)
go func() {
srvErrCh <- srv.ListenAndServe()
}()

slog.Info("サーバーを起動します")

select {
case err := <-srvErrCh:
// SIGINT/SIGTERM を受ける前に ListenAndServe が返った = 起動失敗。
// Shutdown 経由の終了ではないので ErrServerClosed は来ない想定だが、念のため除外。
if err != nil && !errors.Is(err, http.ErrServerClosed) {
slog.Error("起動エラー", "error", err)
return 1
}
return 0
case sig := <-sigCh:
slog.Info("シャットダウン開始", "signal", sig.String())
}

// HTTP shutdown と observability shutdown の両方で共有する単一の context を作成。
// 合計で shutdownTimeout 以内に両方の shutdown を完了させる。
shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), shutdownTimeout)
if err := srv.Shutdown(shutdownCtx); err != nil {
// Shutdown が猶予内に完了できなかった = インフライトが残っている。
// それでも ListenAndServe は Close 済みで戻るので、goroutine は解放される。
slog.Error("サーバーシャットダウン失敗", "error", err)
}
// Shutdown 後は ListenAndServe が ErrServerClosed で戻る。goroutine のクローズ待ち。
if err := <-srvErrCh; err != nil && !errors.Is(err, http.ErrServerClosed) {
slog.Error("起動エラー", "error", err)
os.Exit(1) // TODO: SIGINT/SIGTERM グレースフルシャットダウン
return 1
}
slog.Info("サーバーを停止しました")
return 0
}
27 changes: 26 additions & 1 deletion backend/cmd/batch/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"log/slog"
"os"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
Expand All @@ -14,14 +15,37 @@ import (
"github.com/umekikazuya/me/internal/infra/db"
"github.com/umekikazuya/me/internal/infra/fetcher"
"github.com/umekikazuya/me/internal/infra/tokenizer"
"github.com/umekikazuya/me/pkg/obs"
)

var targetPlatforms = []string{"qiita", "zenn"}

func main() {
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil)))
ctx := context.Background()

prov, shutdown, err := obs.Bootstrap(ctx, obs.Config{
ServiceName: "batch",
Level: obs.ParseLevel(os.Getenv("LOG_LEVEL")),
AddSource: true,
EnableTraces: true,
EnableMetrics: true,
})
if err != nil {
slog.Error("観測性基盤の初期化に失敗しました", "error", err)
os.Exit(1)
}
// shutdown は bounded な context で呼ぶ。呼び出し時点で ctx が cancel
// されていると tracer/meter の flush が即座に諦められてしまう。
defer func() {
shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_ = shutdown(shutdownCtx)
}()
Comment on lines +39 to +43
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

シャットダウンエラーのログ出力を検討

shutdown(shutdownCtx) のエラーを _ で無視していますが、tracer/meter の flush 失敗時にログを残すと、観測性データの欠損を把握しやすくなります。

♻️ エラーログ追加案
 	defer func() {
 		shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 		defer cancel()
-		_ = shutdown(shutdownCtx)
+		if err := shutdown(shutdownCtx); err != nil {
+			slog.Error("observability shutdown failed", "error", err)
+		}
 	}()
📝 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
defer func() {
shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_ = shutdown(shutdownCtx)
}()
defer func() {
shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := shutdown(shutdownCtx); err != nil {
slog.Error("observability shutdown failed", "error", err)
}
}()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/cmd/batch/local.go` around lines 39 - 43, The deferred shutdown call
currently ignores the error from shutdown(shutdownCtx); change the defer body in
the anonymous func to capture the returned error (e.g., err :=
shutdown(shutdownCtx)) and, if err != nil, log it so flush/finalization failures
for tracer/meter are visible; keep the existing context cancel() defer and use
your project's logger (or log.Printf) to emit a clear message referencing
shutdown and shutdownCtx when err != nil.

slog.SetDefault(prov.Logger)
// RecoverProcess はログ出力後に re-panic するので、batch のプロセス終了は
// 非ゼロ exit になる (runtime のデフォルト panic ハンドラが exit 2 を返す)。
defer obs.RecoverProcess(ctx, "batch.main")

Comment on lines +45 to +48
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

defer obs.RecoverProcess が期待通りに動作しない

recover.go で指摘した通り、この defer パターンでは recover() がパニックを捕捉できません。正しく動作させるには無名関数でラップする必要があります。

🐛 修正案
-	defer obs.RecoverProcess(ctx, "batch.main")
+	defer func() {
+		obs.RecoverProcess(ctx, "batch.main")
+	}()

または RecoverProcess の設計を変更し、クロージャを返すようにしてください。

📝 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
// RecoverProcess はログ出力後に re-panic するので、batch のプロセス終了は
// 非ゼロ exit になる (runtime のデフォルト panic ハンドラが exit 2 を返す)。
defer obs.RecoverProcess(ctx, "batch.main")
// RecoverProcess はログ出力後に re-panic するので、batch のプロセス終了は
// 非ゼロ exit になる (runtime のデフォルト panic ハンドラが exit 2 を返す)。
defer func() {
obs.RecoverProcess(ctx, "batch.main")
}()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/cmd/batch/local.go` around lines 45 - 48, The defer call to
obs.RecoverProcess in backend/cmd/batch/local.go won't catch panics because
recover must be called from the deferred function itself; wrap the call in an
anonymous function (e.g., defer func(){ obs.RecoverProcess(ctx, "batch.main")
}() ) so RecoverProcess runs inside a deferred closure that can call recover, or
alternatively change the RecoverProcess API to return a closure (e.g., func
RecoverProcess(...) func()) and defer the returned function; update any callers
accordingly.

// TODO: パラメータを注入する機構を考える(実行環境も)
endpoint := os.Getenv("DYNAMODB_ENDPOINT")
tableName := os.Getenv("DYNAMODB_TABLE_NAME")
Expand Down Expand Up @@ -93,3 +117,4 @@ func main() {
os.Exit(1)
}
}

15 changes: 14 additions & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,25 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect
github.com/aws/smithy-go v1.25.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/ikawaha/kagome-dict v1.1.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/text v0.36.0 // indirect
)
31 changes: 29 additions & 2 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,19 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcu
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo=
github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U=
github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
Expand All @@ -60,8 +69,26 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
Expand Down
20 changes: 10 additions & 10 deletions backend/internal/app/article/interactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (i *interactor) Search(ctx context.Context, input InputSearchDto) (*OutputS
}
result, err := i.repo.FindAll(ctx, criteria)
if err != nil {
return nil, errs.WrapInternal(ctx, "article.repo.FindAll", err)
return nil, errs.WrapInternal("article.repo.FindAll", err)
}

items := make([]OutputArticleItemDto, 0, len(result.Articles))
Expand All @@ -84,7 +84,7 @@ func (i *interactor) Search(ctx context.Context, input InputSearchDto) (*OutputS
func (i *interactor) GetTagsAll(ctx context.Context) (*OutputTagAllDto, error) {
tags, err := i.repo.AllTags(ctx)
if err != nil {
return nil, errs.WrapInternal(ctx, "article.repo.AllTags", err)
return nil, errs.WrapInternal("article.repo.AllTags", err)
}

items := make([]OutputTagItemDto, 0, len(tags))
Expand All @@ -97,11 +97,11 @@ func (i *interactor) GetTagsAll(ctx context.Context) (*OutputTagAllDto, error) {
func (i *interactor) GetSuggests(ctx context.Context, input InputGetSuggestDto) (*OutputGetSuggestAllDto, error) {
tags, err := i.repo.AllTags(ctx)
if err != nil {
return nil, errs.WrapInternal(ctx, "article.repo.AllTags", err)
return nil, errs.WrapInternal("article.repo.AllTags", err)
}
tokens, err := i.repo.AllTokens(ctx)
if err != nil {
return nil, errs.WrapInternal(ctx, "article.repo.AllTokens", err)
return nil, errs.WrapInternal("article.repo.AllTokens", err)
}

var suggestions []OutputGetSuggestItemDto
Expand Down Expand Up @@ -135,7 +135,7 @@ func (i *interactor) GetSuggests(ctx context.Context, input InputGetSuggestDto)
func (i *interactor) Register(ctx context.Context, input InputRegisterDto) error {
existing, err := i.repo.FindByExternalID(ctx, input.ExternalID)
if err != nil {
return errs.WrapInternal(ctx, "article.repo.FindByExternalID", err)
return errs.WrapInternal("article.repo.FindByExternalID", err)
}
if existing != nil {
return fmt.Errorf("article already exists: %s: %w", input.ExternalID, errs.ErrConflict)
Expand All @@ -157,15 +157,15 @@ func (i *interactor) Register(ctx context.Context, input InputRegisterDto) error
return fmt.Errorf("%s: %w", err.Error(), errs.ErrUnprocessable)
}
if err := i.repo.Save(ctx, article); err != nil {
return errs.WrapInternal(ctx, "article.repo.Save", err)
return errs.WrapInternal("article.repo.Save", err)
}
return nil
}

func (i *interactor) Update(ctx context.Context, input InputUpdateDto) error {
article, err := i.repo.FindByExternalID(ctx, input.ExternalID)
if err != nil {
return errs.WrapInternal(ctx, "article.repo.FindByExternalID", err)
return errs.WrapInternal("article.repo.FindByExternalID", err)
}
if article == nil {
return fmt.Errorf("article not found: %s: %w", input.ExternalID, errs.ErrNotFound)
Expand All @@ -186,15 +186,15 @@ func (i *interactor) Update(ctx context.Context, input InputUpdateDto) error {
return fmt.Errorf("%s: %w", err.Error(), errs.ErrUnprocessable)
}
if err := i.repo.Save(ctx, article); err != nil {
return errs.WrapInternal(ctx, "article.repo.Save", err)
return errs.WrapInternal("article.repo.Save", err)
}
return nil
}

func (i *interactor) Remove(ctx context.Context, input InputRemoveDto) error {
article, err := i.repo.FindByExternalID(ctx, input.ExternalID)
if err != nil {
return errs.WrapInternal(ctx, "article.repo.FindByExternalID", err)
return errs.WrapInternal("article.repo.FindByExternalID", err)
}
if article == nil {
return fmt.Errorf("article not found: %s: %w", input.ExternalID, errs.ErrNotFound)
Expand All @@ -204,7 +204,7 @@ func (i *interactor) Remove(ctx context.Context, input InputRemoveDto) error {
return fmt.Errorf("%s: %w", err.Error(), errs.ErrUnprocessable)
}
if err := i.repo.Save(ctx, article); err != nil {
return errs.WrapInternal(ctx, "article.repo.Save", err)
return errs.WrapInternal("article.repo.Save", err)
}
return nil
}
Expand Down
Loading