Skip to content

DB seederを追加#2979

Open
ramdos0207 wants to merge 2 commits into
masterfrom
db-seed
Open

DB seederを追加#2979
ramdos0207 wants to merge 2 commits into
masterfrom
db-seed

Conversation

@ramdos0207
Copy link
Copy Markdown
Contributor

@ramdos0207 ramdos0207 commented Apr 4, 2026

本番と同じぐらいの重さにするためのseederを追加

Summary by CodeRabbit

  • New Features
    • Added a new seed command to populate the database with synthetic test data.
    • The seeding process creates sample users, channels, messages, and stamps to support development and testing.
    • A corresponding Makefile target enables easy execution of the seed operation through Docker Compose.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 4, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new database seeding feature to the application. It adds a seed Makefile target, registers a seed CLI command in the root command handler, and implements the seeding logic that populates the database with synthetic users, channels, messages, stamps, and reactions in sequential phases.

Changes

Cohort / File(s) Summary
Infrastructure
Makefile
Added .PHONY target and recipe to execute the seed command via Docker Compose, running docker compose run --rm --entrypoint ./traQ backend seed.
CLI Implementation
cmd/root.go
Registered seedCommand() as a new subcommand on the root Cobra command, exposing the seed functionality alongside existing commands.
Seeding Logic
cmd/seed.go
Implemented comprehensive seeding workflow: initializes logging and database connection, establishes file storage and GORM repository, creates system roles and admin user, then sequentially generates users (with random deactivations), public channels (with hierarchical nesting), batch-inserted messages (with ~20% tracked for reactions), PNG stamp images per user, and message stamp reactions with randomized assignments. Handles "already exists" cases via warnings; propagates other errors as command failures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 ✨ A seed command hops into the codebase,
Planting users, channels, messages in their place,
With stamps and reactions all in a row,
The database blooms in a wonderful show! 🌱

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'DB seederを追加' accurately reflects the main change—adding a database seeder feature across Makefile, cmd/root.go, and cmd/seed.go files.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch db-seed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

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

Inline comments:
In `@cmd/seed.go`:
- Around line 191-203: The seed command currently hard-codes creation of an
admin user "traq"/"traq" using file.GenerateIconFile and repo.CreateUser
(CreateUserArgs with role.Admin); change this so the admin user is only created
in non-production/dev environments and the password is not embedded: add a check
for the runtime environment (e.g., config.Environment or an
IsDevelopment/isLocal guard) and skip creating the default admin unless that
check passes OR an explicit admin password is provided via a CLI flag (e.g.,
--admin-password) or env var (e.g., ADMIN_PASSWORD); read the password from that
flag/env var and pass it into repo.CreateUser instead of the hard-coded "traq"
value, and ensure role.Admin is only assigned under the gated condition.
- Around line 406-416: The backfill can return multiple rows per channel when
several messages share MAX(created_at); change the INSERT SELECT so each channel
yields exactly one row by choosing a deterministic tie-breaker (e.g., the
largest message id among rows with the max created_at). Replace the SELECT block
with a grouped query that joins the max created_at per channel and then GROUPs
BY m.channel_id selecting MAX(m.id) AS message_id and MAX(m.created_at) AS
date_time (so each channel contributes a single (channel_id, message_id,
date_time) tuple), then keep the ON DUPLICATE KEY UPDATE as-is; refer to the
channel_latest_messages table and the messages table/columns used in this diff
and note the primary key on channel_id defined in model/messages.go for locating
where to apply the change.
- Around line 154-156: Replace the detached context creation in the RunE of the
seed command with the Cobra-provided context (use cmd.Context()) and ensure that
all GORM operations use db.WithContext(ctx) rather than raw db, and that any
helper functions invoked from RunE that perform I/O accept and propagate this
ctx; specifically update the RunE closure to obtain ctx := cmd.Context(), change
direct db.Exec/raw writes and batch inserts to db.WithContext(ctx).Exec /
db.WithContext(ctx).Create (or equivalent), and if functions called from this
block (including any wrappers around batch inserts) don't accept context, add
context.Context as the first parameter and pass ctx through. Ensure
getCLILoggers() usage remains unchanged but that logger-using calls also take
ctx where applicable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4fbe8e0e-74f6-482a-ba15-ca0ceb03f408

📥 Commits

Reviewing files that changed from the base of the PR and between d6d3981 and da9b8d0.

📒 Files selected for processing (3)
  • Makefile
  • cmd/root.go
  • cmd/seed.go

Comment thread cmd/seed.go
Comment on lines +154 to +156
RunE: func(_ *cobra.Command, _ []string) error {
ctx := context.Background()
logger, gormLogger := getCLILoggers()
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file exists and get its line count
wc -l cmd/seed.go

Repository: traPtitech/traQ

Length of output: 74


🏁 Script executed:

# Now let's look at the specific sections mentioned in the review
# Lines 154-156 (RunE definition)
sed -n '154,156p' cmd/seed.go

Repository: traPtitech/traQ

Length of output: 181


🏁 Script executed:

# Lines around 154-156 for broader context
sed -n '150,165p' cmd/seed.go

Repository: traPtitech/traQ

Length of output: 564


🏁 Script executed:

# Lines 385-417 (first batch of DB operations)
sed -n '385,420p' cmd/seed.go

Repository: traPtitech/traQ

Length of output: 1468


🏁 Script executed:

# Lines 468-481 (second batch of DB operations)
sed -n '465,485p' cmd/seed.go

Repository: traPtitech/traQ

Length of output: 757


🏁 Script executed:

# Verify this is not a test file
file cmd/seed.go | grep -i test

Repository: traPtitech/traQ

Length of output: 101


Propagate the Cobra context into the raw GORM writes.

ctx := context.Background() detaches this command from caller cancellation, and the largest DB operations below use db directly instead of db.WithContext(ctx). If this command is wrapped with ExecuteContext or cancelled by a higher layer, the batch inserts and raw Exec will still run uncancelled.

Suggested shape
- RunE: func(_ *cobra.Command, _ []string) error {
- 	ctx := context.Background()
+ RunE: func(cmd *cobra.Command, _ []string) error {
+ 	ctx := cmd.Context()
  	logger, gormLogger := getCLILoggers()
  	...
+ 	seedDB := db.WithContext(ctx)
  	...
- 	if err := db.Omit(clause.Associations).Create(&batch).Error; err != nil {
+ 	if err := seedDB.Omit(clause.Associations).Create(&batch).Error; err != nil {
  		...
- 	if err := db.Exec(`...`).Error; err != nil {
+ 	if err := seedDB.Exec(`...`).Error; err != nil {
  		...
- 	if err := db.Omit(clause.Associations).Create(&reactionBatch).Error; err != nil {
+ 	if err := seedDB.Omit(clause.Associations).Create(&reactionBatch).Error; err != nil {

Per coding guidelines for **/*.go: Functions performing I/O or network requests must accept context.Context as their first parameter, and the received context must be passed down to all subsequent calls. Applies to lines 155, 385–417, and 468–481.

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

In `@cmd/seed.go` around lines 154 - 156, Replace the detached context creation in
the RunE of the seed command with the Cobra-provided context (use cmd.Context())
and ensure that all GORM operations use db.WithContext(ctx) rather than raw db,
and that any helper functions invoked from RunE that perform I/O accept and
propagate this ctx; specifically update the RunE closure to obtain ctx :=
cmd.Context(), change direct db.Exec/raw writes and batch inserts to
db.WithContext(ctx).Exec / db.WithContext(ctx).Create (or equivalent), and if
functions called from this block (including any wrappers around batch inserts)
don't accept context, add context.Context as the first parameter and pass ctx
through. Ensure getCLILoggers() usage remains unchanged but that logger-using
calls also take ctx where applicable.

Comment thread cmd/seed.go
Comment on lines +191 to +203
// 管理者ユーザー traq/traq の作成
adminIconID, err := file.GenerateIconFile(ctx, fm, "traq")
if err != nil {
return fmt.Errorf("failed to generate admin icon: %w", err)
}
if u, err := repo.CreateUser(ctx, repository.CreateUserArgs{
Name: "traq",
Password: "traq",
Role: role.Admin,
IconFileID: adminIconID,
}); err != nil {
logger.Warn("failed to create traq admin user (may already exist)", zap.Error(err))
} else {
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

Don't hard-code a known admin login in a general-purpose seed command.

This creates traq / traq with role.Admin against whatever database the active config points at. If seed is ever run outside an isolated local DB, it introduces a predictable privileged credential. Please gate this to dev-only environments and require the password from an explicit flag or env var instead of embedding it.

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

In `@cmd/seed.go` around lines 191 - 203, The seed command currently hard-codes
creation of an admin user "traq"/"traq" using file.GenerateIconFile and
repo.CreateUser (CreateUserArgs with role.Admin); change this so the admin user
is only created in non-production/dev environments and the password is not
embedded: add a check for the runtime environment (e.g., config.Environment or
an IsDevelopment/isLocal guard) and skip creating the default admin unless that
check passes OR an explicit admin password is provided via a CLI flag (e.g.,
--admin-password) or env var (e.g., ADMIN_PASSWORD); read the password from that
flag/env var and pass it into repo.CreateUser instead of the hard-coded "traq"
value, and ensure role.Admin is only assigned under the gated condition.

Comment thread cmd/seed.go
Comment on lines +406 to +416
if err := db.Exec(`
INSERT INTO channel_latest_messages (channel_id, message_id, date_time)
SELECT m.channel_id, m.id, m.created_at
FROM messages m
INNER JOIN (
SELECT channel_id, MAX(created_at) AS max_created
FROM messages WHERE deleted_at IS NULL GROUP BY channel_id
) latest ON m.channel_id = latest.channel_id AND m.created_at = latest.max_created
WHERE m.deleted_at IS NULL
ON DUPLICATE KEY UPDATE message_id = VALUES(message_id), date_time = VALUES(date_time)
`).Error; err != nil {
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 | 🟠 Major

Make the channel_latest_messages backfill deterministic.

This query only keys on MAX(created_at). With bulk inserts, multiple messages in a channel can share that max timestamp; then the SELECT returns multiple rows for the same channel_id, and because channel_latest_messages is keyed only by channel_id in model/messages.go:31-41, the final message_id becomes arbitrary. Please add a deterministic tie-breaker so each channel contributes exactly one row.

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

In `@cmd/seed.go` around lines 406 - 416, The backfill can return multiple rows
per channel when several messages share MAX(created_at); change the INSERT
SELECT so each channel yields exactly one row by choosing a deterministic
tie-breaker (e.g., the largest message id among rows with the max created_at).
Replace the SELECT block with a grouped query that joins the max created_at per
channel and then GROUPs BY m.channel_id selecting MAX(m.id) AS message_id and
MAX(m.created_at) AS date_time (so each channel contributes a single
(channel_id, message_id, date_time) tuple), then keep the ON DUPLICATE KEY
UPDATE as-is; refer to the channel_latest_messages table and the messages
table/columns used in this diff and note the primary key on channel_id defined
in model/messages.go for locating where to apply the change.

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

Labels

None yet

Projects

Status: Inbox

Development

Successfully merging this pull request may close these issues.

1 participant