Skip to content

Conversation

@KATO-Hiro
Copy link
Collaborator

@KATO-Hiro KATO-Hiro commented Jun 15, 2025

close #1124

Summary by CodeRabbit

  • New Features
    • Added support for seeding workbook data, including a variety of curated programming workbooks with associated tasks.
  • Refactor
    • Improved the database seeding process with controlled concurrency, enhanced error handling, and detailed progress logging.
  • Chores
    • Updated dependencies to include concurrency management library for more reliable data processing during seeding.
    • Added a default password constant for seed users.

@coderabbitai
Copy link

coderabbitai bot commented Jun 15, 2025

Warning

Rate limit exceeded

@KATO-Hiro has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 14 minutes and 56 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 11b6f1d and 712c309.

📒 Files selected for processing (1)
  • prisma/seed.ts (6 hunks)

"""

Walkthrough

The seeding script was refactored to improve concurrency control and error handling by making all seeding functions async and using PQueue for controlled parallelism. Workbook seeding was added with validation and duplicate checks. A new module provides comprehensive workbook data. Logging was enhanced throughout the seeding process.

Changes

File(s) Change Summary
prisma/seed.ts Converted seeding functions to async, added PQueue for concurrency control, improved error handling/logging, added workbook seeding with validation and duplicate checks.
prisma/workbooks.ts Added new module exporting static workbook data array and helper function for creating workbook base objects.
package.json Added "p-queue" dependency for concurrency control in seeding script.
prisma/users.ts Added exported constant USER_PASSWORD_FOR_SEED for seeding user passwords.

Sequence Diagram(s)

sequenceDiagram
    participant Main as main()
    participant DB as Database (Prisma)
    participant Workbooks as workbooks.ts

    Main->>DB: addUsers()
    Main->>DB: addTasks()
    Main->>DB: addTags()
    Main->>DB: addTaskTags()
    Main->>DB: addSubmissionStatuses()
    Main->>DB: addAnswers()
    Main->>Workbooks: import workbooks
    Main->>DB: addWorkBooks(workbooks)
    DB-->>Main: Logging and error reporting for each step
Loading

Assessment against linked issues

Objective Addressed Explanation
Add helper functions to seed.ts: addWorkBooks, addWorkBook (#1124)
Refactoring of seed script (#1124)
Add error handling to seed script (#1124)
Prepare seed data: curriculum, 10Q-6Q, solution-based workbooks (#1124)
動作確認 (manual verification of operation) (#1124) Manual verification is not represented in code changes.

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes were found.

Poem

In the garden of code, where the carrots grow bright,
Rabbits have seeded, with joy and delight.
Workbooks now flourish, async and strong,
Errors are handled, the process hums along.
With logs and with care, each task finds its place—
A hop, and the database blooms with grace!
🥕✨
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 4

🧹 Nitpick comments (2)
prisma/seed.ts (2)

41-51: Sequential seeding order is clear but not crash-proof

If addTasks() (≈5 k records) throws, subsequent stages never run and the DB is left half-seeded. Consider wrapping each stage in its own try/catch and continuing, or running the whole pipeline inside a single SQL transaction that can be rolled back atomically.

No code change required right now, but worth revisiting.


205-220: Foreign-key risk: workbook tasks are inserted blindly

workBookFactory.create({ workBookTasks: { create: workbook.workBookTasks } }) assumes every taskId exists.
If a task is missing, the whole workbook creation fails and the catch just logs the error, silently skipping the workbook.

Mitigation options:

  1. Validate task existence beforehand and filter out missing ones.
  2. Wrap the nested create in connectOrCreate with graceful fallback.
  3. Abort early with an explicit error message listing the missing taskIds.
for (const { taskId } of workbook.workBookTasks) {
  const exists = await prisma.task.count({ where: { task_id: taskId } });
  if (!exists) missing.push(taskId);
}
if (missing.length) {
  console.warn('Skip workbook', workbook.title, 'missing tasks:', missing);
  continue;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between d4530f2 and ffaf2de.

📒 Files selected for processing (2)
  • prisma/seed.ts (8 hunks)
  • prisma/workbooks.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
prisma/workbooks.ts (1)
src/lib/types/workbook.ts (2)
  • WorkBook (15-18)
  • WorkBookTasksBase (56-56)
prisma/seed.ts (2)
prisma/tasks.ts (1)
  • tasks (3-4831)
prisma/workbooks.ts (1)
  • workbooks (24-624)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (1)
prisma/workbooks.ts (1)

3-18:

Details

❌ Incorrect review comment

id is hard-coded to 100000 – very likely to break the PK constraint on insertion

createWorkBookBase() always returns { id: 100000, ... }.
Because addWorkBook() never uses/overrides this field, Prisma will still attempt to insert that literal value and the second workbook will violate the unique constraint on workBook.id.

   return {
-    id: 100000,
+    // Let Prisma auto-increment unless an explicit id is really needed
+    // id is omitted on purpose. Specify through overrides only when required.

🏁 Script executed:

#!/bin/bash
# Search for createWorkBookBase usage and addWorkBook references
rg -n 'createWorkBookBase' .
rg -n 'addWorkBook' .

Length of output: 5959


🏁 Script executed:

#!/bin/bash
# Display the implementation of addWorkBook for inspection
rg -n -B3 -A15 'async function addWorkBook' prisma/seed.ts

Length of output: 1346


Ignore hard-coded id in createWorkBookBase – it isn’t used on insert
The seeding logic in prisma/seed.ts builds its create call manually (via workBookFactory.create) and does not include the id field, so Prisma’s auto-increment will apply. The id: 100000 in createWorkBookBase never makes it into the INSERT and won’t cause a PK collision.

Likely an incorrect or invalid review comment.

Copy link

@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: 1

🧹 Nitpick comments (3)
prisma/seed.ts (3)

46-56: Redundant master PQueue

mainQueue is created with concurrency: 1, yet each step is awaited immediately.
The queue adds no ordering or throttling benefits and just adds overhead.

-const mainQueue = new PQueue({ concurrency: 1 });
-await mainQueue.add(() => addUsers());
-
+await addUsers();
+

(Or drop the queue but keep the try/catch if you need the grouping.)


70-95: Promise.all + PQueue = needless duplication

After enqueuing every user you still collect all returned promises and
await Promise.all(userPromises).
queue.onIdle() is simpler, avoids creating an array the size of users, and
keeps the pattern consistent across the file.

-const userPromises = users.map((u) => userQueue.add(() => …));
-await Promise.all(userPromises);
+for (const u of users) userQueue.add(() => …);
+await userQueue.onIdle();

(This comment applies to every similar block: tasks, tags, task-tags, submission
statuses, answers.)


196-215: Duplicate check still case-sensitive

When urlSlug is empty you fall back to title + authorId, but the title
comparison is case-sensitive. Two workbooks whose titles differ only in case
(e.g. “DP-Workbook” vs “dp-workbook”) will bypass the duplicate guard.

Consider normalising titles (lower-case + trim) before querying.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between ffaf2de and c996d61.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • package.json (1 hunks)
  • prisma/seed.ts (8 hunks)
  • prisma/workbooks.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • package.json
  • prisma/workbooks.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: preview
🔇 Additional comments (2)
prisma/seed.ts (2)

264-280: 👍 normalizeUrlSlug looks good

The helper cleanly handles '' | null | undefined and aligns the duplicate
check with the create call.


455-492: FK integrity checks missing for Task & Status

addAnswers guards against missing users but not against missing tasks or
submission statuses. A stale ID will make taskAnswerFactory.create fail and
abort the worker.

Add similar existence checks (or surround the create with try/catch and log)
to keep seeding resilient.

Copy link

@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: 0

🔭 Outside diff range comments (1)
prisma/seed.ts (1)

325-333: ⚠️ Potential issue

Incorrect field when linking a Task from inside addTag

Here you attempt to connect a Task via tag_id, which does not exist on the
Task model. It should connect via task_id (or another real PK).

-              connect: { tag_id: tag.id },
+              connect: { task_id: tag.id },

Without this fix the seed will throw a Prisma validation error at runtime.

♻️ Duplicate comments (1)
prisma/seed.ts (1)

160-167: ⚠️ Potential issue

tag connection still targets task_id instead of id

Previous feedback pointed out the mismatch; the code now does
connect: { task_id: task.id }, but the tag model’s primary key is id.
Use connect: { id: /* tag id */ } to avoid relation errors.

-              connect: { task_id: task.id },
+              connect: { id: task.id },
🧹 Nitpick comments (3)
prisma/seed.ts (3)

46-55: Sequential await negates the purpose of mainQueue

mainQueue is configured with concurrency: 1, yet every add() call is awaited immediately.
The result is strictly serial execution with the extra overhead of the queue. Either:

  1. Keep the queue but enqueue all jobs at once and await mainQueue.onIdle(), or
  2. Drop the queue and call the seeding functions directly in the desired order.

Both variants achieve the same ordering with less noise.


58-60: Minor wording issue in error log

console.error('Failed to seeding:', e); should read “Failed to seed” or “Seeding failed” for clarity.

-    console.error('Failed to seeding:', e);
+    console.error('Failed to seed:', e);

76-77: Hard-coded password will leak into every seeded user

All users receive the same literal password 'Ch0kuda1'.
Even in non-production environments this is brittle and encourages unsafe habits.

Consider moving the seed password to an env variable or deriving it from the username (e.g. "password-" + user.name) so it’s obvious it is dummy data.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c996d61 and 08d8232.

📒 Files selected for processing (1)
  • prisma/seed.ts (9 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: preview
🔇 Additional comments (1)
prisma/seed.ts (1)

264-280: Slug normalisation looks solid

normalizeUrlSlug correctly converts empty strings and null to undefined
and lower-cases meaningful slugs. 👍

Copy link

@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: 1

🧹 Nitpick comments (4)
prisma/seed.ts (4)

46-56: PQueue with concurrency = 1 adds needless complexity

mainQueue is configured with concurrency: 1, yet every seeding step is already awaited in order.
Using the queue here adds a library hop without any functional gain and slightly obscures stack-traces.

-// Create a queue to ensure sequential execution
-const mainQueue = new PQueue({ concurrency: 1 });
-
-await mainQueue.add(() => addUsers());
-
-await mainQueue.add(() => addAnswers());
+await addUsers();
+await addTasks();
+await addWorkBooks();
+await addTags();
+await addTaskTags();
+await addSubmissionStatuses();
+await addAnswers();

Simpler, clearer, and one fewer dependency instance.


70-92: Avoid Array.map for side-effects – use for…of or queue.addAll

users.map is only used to enqueue tasks; the produced array is discarded.
for…of (or userQueue.addAll) signals intent, avoids an intermediate array and scales better for very large datasets.

-users.map((user) =>
-  userQueue.add(async () => {
+for (const user of users) {
+  userQueue.add(async () => {-  ),
-);
-
-await userQueue.onIdle();
+  });
+}
+
+await userQueue.onIdle();

172-183: Use findUnique/findFirst for single-row checks

Duplicate detection issues a findMany, loads all matches and allocates an array just to test length.
A single‐row query is cheaper and expresses intent more clearly:

-registeredWorkBook = await prisma.workBook.findMany({
-  where: { urlSlug: normalizedUrlSlug },
-});
+registeredWorkBook = await prisma.workBook.findFirst({
+  where: { urlSlug: normalizedUrlSlug },
+});

(Adjust the later length check accordingly.)


254-256: toLocaleLowerCase risks locale surprises – prefer toLowerCase

Slug normalisation should be deterministic regardless of the server’s locale.
toLocaleLowerCase() can change behaviour (e.g., Turkish “İ”).
Using toLowerCase() avoids this.

-return urlSlug && urlSlug !== '' ? urlSlug.toLocaleLowerCase() : undefined;
+return urlSlug && urlSlug !== '' ? urlSlug.toLowerCase() : undefined;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 08d8232 and 732c3d7.

📒 Files selected for processing (1)
  • prisma/seed.ts (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
prisma/seed.ts (2)
prisma/tasks.ts (1)
  • tasks (3-4831)
src/lib/utils/contest.ts (1)
  • classifyContest (5-93)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: preview
🔇 Additional comments (1)
prisma/seed.ts (1)

148-154: contest_type may get null – verify schema allows it

classifyContest() returns null for unknown patterns; that value is written to contest_type.

If the Task model declares contest_type as a non-nullable enum, this will throw at seed time.
Please confirm the Prisma schema or add a fallback.

Copy link

@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: 0

🧹 Nitpick comments (4)
prisma/seed.ts (4)

67-71: Extract concurrency settings into a single constant / env var

new PQueue({ concurrency: 2 }) (and 3, 2, … further down) is hard-coded multiple times. Centralising the value(s) makes tuning for different DB sizes trivial and avoids magic numbers scattered through the file.
A tiny helper such as const CONCURRENCY = Number(process.env.SEED_CONCURRENCY ?? 3); would do.


155-214: Consider parallelising workbook seeding too

addWorkBooks processes items sequentially with plain for … of, unlike the other seeders that use a queue.
If the workbook list grows, this will be the new bottleneck. Re-using PQueue here (or at least batching) keeps throughput consistent.


173-179: Use findUnique for slug look-ups

urlSlug is presumably declared @unique in the Prisma schema. findUnique({ where: { urlSlug } }) is cheaper and conveys intent better than findFirst.
(Same for the title + author composite if there’s a corresponding unique constraint.)


251-253: Trim whitespace when normalising slugs

Edge cases like " union-find " pass the non-empty check yet keep stray spaces.

-return urlSlug && urlSlug !== '' ? urlSlug.toLowerCase() : undefined;
+return urlSlug && urlSlug.trim() !== ''
+  ? urlSlug.trim().toLowerCase()
+  : undefined;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 732c3d7 and bbdf75f.

📒 Files selected for processing (1)
  • prisma/seed.ts (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: preview
🔇 Additional comments (1)
prisma/seed.ts (1)

169-189: 👍 Duplicate-slug check now normalises before lookup

The earlier bug allowing multiple NULL/empty slugs is resolved by calling normalizeUrlSlug ahead of the query. Looks good!

Copy link

@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: 1

🔭 Outside diff range comments (1)
prisma/seed.ts (1)

96-110: 🛠️ Refactor suggestion

Missing parameter types violate noImplicitAny

Functions like addUser, addTask, addWorkBook, … declare parameters without types (user, task, workbook).
With noImplicitAny enabled this is a compile-error; without it you still lose all type safety & IntelliSense.

Define explicit interfaces or import the DTO types used in your fixtures:

-async function addUser(user, password: string, userFactory, keyFactory) {
+async function addUser(
+  user: SeedUser,
+  password: string,
+  userFactory: ReturnType<typeof defineUserFactory>,
+  keyFactory: ReturnType<typeof defineKeyFactory>
+) {

Repeat for the other helpers.

🧹 Nitpick comments (1)
prisma/seed.ts (1)

154-214: Workbook seeding is strictly sequential – consider PQueue for parity

All other entities enjoy controlled parallelism, but workbooks are processed one-by-one.
If the dataset grows (e.g. hundreds of workbooks) this becomes a bottleneck.

Re-use the same queued pattern:

const wbQueue = new PQueue({ concurrency: 2 });
for (const wb of workbooks) {
  wbQueue.add(() => processWorkBook(wb));
}
await wbQueue.onIdle();

(Where processWorkBook contains the current try/catch logic.)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between bbdf75f and 69c24d0.

📒 Files selected for processing (1)
  • prisma/seed.ts (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: preview
🔇 Additional comments (2)
prisma/seed.ts (2)

251-253: normalizeUrlSlug lower-cases the slug – ensure DB index is case-insensitive

You normalise to .toLowerCase() before findUnique, but the column might be case-sensitive (depending on collation).
Double-check that the DB uses a case-insensitive unique index or store the slug exactly as normalised to avoid “phantom duplicates”.


70-88:

Details

❌ Incorrect review comment

Duplicate check + concurrent inserts → race condition

findUnique is executed before the create runs in another queue worker.
With concurrency > 1, two workers can both observe “not found” and then attempt create, racing into a P2002 (unique-constraint) error.

Mitigations:

  1. Reduce the queue to concurrency: 1 for entities whose uniqueness you probe first, or
  2. Skip the pre-check and catch the P2002 error:
try {
  await userFactory.create(/* … */);
} catch (e) {
  if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
    // duplicate -> ignore
  } else {
    throw e;
  }
}

🏁 Script executed:

#!/bin/bash
set -e

# Find where userQueue is defined or configured
rg "userQueue" -n -C3 || echo "No direct references to userQueue found."

# Check for queue instantiation to see default concurrency
rg "new .*Queue" -n -C3 || echo "No queue instantiation patterns found."

Length of output: 3125


🏁 Script executed:

#!/bin/bash
set -e

# Show import section and initial factory definitions in prisma/seed.ts
sed -n '1,80p' prisma/seed.ts

# Locate defineUserFactory in seed.ts
rg "defineUserFactory" -n -C3 prisma/seed.ts || echo "defineUserFactory not in seed.ts"

# Search for addUser definition or import across the repo
rg "addUser" -n -C5 .

Length of output: 7300


No inherent race on distinct users—concurrency = 2 is safe
The users array contains unique entries and each queue task handles a different username. Since you call await userQueue.onIdle() before moving on, there’s no scenario where two workers race to insert the same user. You can safely keep concurrency: 2.

If you still want to simplify or guard against accidental duplicates, consider one of the following instead of a pre-check:

  • Use a single atomic upsert:
- const registeredUser = await prisma.user.findUnique({
-   where: { username: user.name },
- });
- if (!registeredUser) {
-   await addUser(user, password, userFactory, keyFactory);
- }
+ await prisma.user.upsert({
+   where: { username: user.name },
+   create: { id: user.id, username: user.name, role: user.role /* … */ },
+   update: {}, // no-op if already exists
+ });
  • Or catch the unique-constraint error on create:
try {
  await userFactory.create({ /* … */ });
} catch (e) {
  if (
    e instanceof Prisma.PrismaClientKnownRequestError &&
    e.code === 'P2002'
  ) {
    // already exists, ignore
  } else {
    throw e;
  }
}

Likely an incorrect or invalid review comment.

Copy link

@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: 0

♻️ Duplicate comments (1)
prisma/seed.ts (1)

25-25: ⚠️ Potential issue

Single shared password still present – risk of credential reuse

USER_PASSWORD_FOR_SEED is injected from ./users, but the variable name strongly hints it is still a fixed constant. If the same value is written to every user, the original leakage problem remains.

Move the value to an environment variable (or generate a per-user random password) to avoid shipping a credential in source control.

🧹 Nitpick comments (3)
prisma/seed.ts (3)

67-69: Factor queue concurrency into a central constant

Concurrency levels (2, 3, …) are hard-coded here and in every other queue.
Extract them into a small const QUEUE_CONCURRENCY = { users: 2, tasks: 3, … } at the top of the file (or a config file) so that tuning only requires a one-line change.

-  const userQueue = new PQueue({ concurrency: 2 });
+  const userQueue = new PQueue({ concurrency: QUEUE_CONCURRENCY.users });

156-158: userFactory is declared but never used

const userFactory = defineUserFactory(); is created only to be ignored.
Drop the variable or inline the call to keep the function concise.

-  const userFactory = defineUserFactory();
-  const workBookFactory = defineWorkBookFactory({ defaultData: { user: userFactory } });
+  const workBookFactory = defineWorkBookFactory({
+    defaultData: { user: defineUserFactory() },
+  });

311-327: Run the three independent look-ups in parallel

taskTag, task, and tag queries are unrelated; execute them through Promise.all to shave network latency without increasing outer concurrency.

-        const registeredTaskTag = await prisma.taskTag.findUnique({ ... });
-        const registeredTask = await prisma.task.findUnique({ ... });
-        const registeredTag = await prisma.tag.findUnique({ ... });
+        const [registeredTaskTag, registeredTask, registeredTag] = await Promise.all([
+          prisma.taskTag.findUnique({ ... }),
+          prisma.task.findUnique({ ... }),
+          prisma.tag.findUnique({ ... }),
+        ]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 69c24d0 and 11b6f1d.

📒 Files selected for processing (2)
  • prisma/seed.ts (6 hunks)
  • prisma/users.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • prisma/users.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)

@KATO-Hiro
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jun 15, 2025

Tip

For best results, initiate chat on the files or code changes.

@KATO-Hiro Thank you for requesting the review! I'll provide a comprehensive analysis of your workbook seeding implementation.

🌟 Overall Assessment

This is an excellent refactoring that significantly improves the seeding infrastructure. The migration to async functions with concurrency control and the addition of workbook seeding represents a substantial enhancement.

✅ Strengths

1. Robust Concurrency Management

  • PQueue implementation with configurable concurrency limits prevents database overload
  • Proper error handling within concurrent operations ensures partial failures don't halt the entire process

2. Comprehensive Workbook Validation

  • Duplicate detection by both URL slug and title/author combination
  • Author existence validation before workbook creation
  • Proper normalization of URL slugs

3. Enhanced Error Handling & Logging

  • Detailed logging at start/finish of each seeding phase
  • Individual error catching prevents cascade failures
  • Clear warning messages for validation issues

🔍 Observations & Suggestions

1. Database Transaction Considerations

// Consider wrapping large seeding operations in transactions
async function addWorkBooks() {
  // Current implementation processes workbooks individually
  // For better consistency, consider batching in transactions
}

2. Memory Efficiency for Large Datasets
The current approach loads all workbooks into memory. For very large datasets, consider streaming or batching:

// Potential improvement for scalability
const BATCH_SIZE = 50;
for (let i = 0; i < workbooks.length; i += BATCH_SIZE) {
  const batch = workbooks.slice(i, i + BATCH_SIZE);
  await processBatch(batch);
}

3. URL Slug Validation
The normalizeUrlSlug function handles null/undefined cases well, but consider adding format validation:

function normalizeUrlSlug(urlSlug: string | null | undefined): string | undefined {
  if (!urlSlug?.trim()) return undefined;
  const normalized = urlSlug.toLowerCase().trim();
  // Consider adding format validation (e.g., slug pattern)
  return normalized;
}

📋 Minor Recommendations

1. Configuration Externalization
Consider moving concurrency limits to a configuration object:

const SEED_CONFIG = {
  usersConcurrency: 3,
  tasksConcurrency: 2,
  workbooksConcurrency: 2
} as const;

2. Type Safety Enhancement
The workbook data structure is comprehensive, but consider adding runtime validation for critical fields.

3. Performance Monitoring
Consider adding timing logs for performance monitoring:

console.log(`✅ Finished adding ${workbooks.length} workbooks in ${Date.now() - startTime}ms`);

🎯 Workbook Data Quality

The workbook dataset is impressive! The coverage spans from basic I/O to advanced algorithms (Union-Find, ordered sets, etc.). The task organization with priorities and editorial URLs provides excellent learning progression.

🚀 Ready for Production

This implementation is well-architected and production-ready. The combination of:

  • Controlled concurrency
  • Comprehensive validation
  • Robust error handling
  • Detailed logging

Makes this a solid foundation for the seeding infrastructure.

Great work on this substantial improvement to the codebase! The workbook seeding functionality will be a valuable addition to the platform.

@KATO-Hiro KATO-Hiro merged commit 83db9a3 into staging Jun 15, 2025
3 checks passed
@KATO-Hiro KATO-Hiro deleted the #1124 branch June 15, 2025 21:44
Copy link
Collaborator Author

@KATO-Hiro KATO-Hiro left a comment

Choose a reason for hiding this comment

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

LGTM

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.

seed.tsに問題集に関するデータを追加しましょう

2 participants