Skip to content

feat: add database seeding command for development onboarding#217

Open
sid3305 wants to merge 4 commits into
roshankumar0036singh:mainfrom
sid3305:feat/database-seeding
Open

feat: add database seeding command for development onboarding#217
sid3305 wants to merge 4 commits into
roshankumar0036singh:mainfrom
sid3305:feat/database-seeding

Conversation

@sid3305

@sid3305 sid3305 commented Jun 22, 2026

Copy link
Copy Markdown

Summary

This PR adds a database seeding utility to improve developer onboarding and local testing.

Changes

  • Added cmd/seed/main.go for development database seeding.

  • Added a seed target to the Makefile:

    • make seed
  • Seeds standardized development data:

    • Admin user (admin@example.com)
    • Demo user (demo@example.com)
    • Pre-configured OAuth client (dev-client)
  • Runs required database migrations before seeding.

  • Implements idempotent behavior so the command can be safely executed multiple times without creating duplicates.

Seeded Data

Admin User

  • Email: admin@example.com
  • Password: Admin123!

Demo User

  • Email: demo@example.com
  • Password: Demo123!

OAuth Client

  • Name: Local Development Client
  • Client ID: dev-client
  • Client Secret: dev-client-secret

Verification

  • go test ./... passes successfully.
  • make seed successfully creates development users and OAuth client.
  • Re-running the command does not create duplicate records.

Problem Solved

New developers can now bootstrap a local environment with ready-to-use users and OAuth credentials instead of manually creating them before testing APIs.

Summary by CodeRabbit

  • New Features
    • Added a seed command to populate development data, including demo/admin users with securely hashed passwords and a pre-configured local OAuth client.
  • Improvements
    • Seeding now runs only in development or local environments and requires SEED_CLIENT_SECRET for OAuth client setup.
    • Startup output no longer prints sensitive client credentials; it logs public identity details instead.

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement.

To sign, please post a comment on this PR with the following exact text:

I have read the CLA and agree to its terms


I have read the CLA and agree to its terms.


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

A new cmd/seed/main.go command is introduced that enforces development/local environment, loads config, auto-migrates schema models, and idempotently seeds two development users (admin and demo) and a local OAuth client using bcrypt-hashed credentials. A seed target is added to the Makefile to invoke this command via go run ./cmd/seed. The OAuth client secret is required via the SEED_CLIENT_SECRET environment variable and is not logged.

Changes

Dev Data Seeder

Layer / File(s) Summary
Makefile seed target
Makefile
Adds seed to .PHONY and defines a seed target that executes go run ./cmd/seed.
Seed entrypoint and schema migration
cmd/seed/main.go
main() enforces development/local environment, loads config, initializes the DB, auto-migrates all required model tables, calls seedUsers and seedOAuthClient, and prints a credential summary banner that logs only fixed user emails and client identity while stating the OAuth client secret is configured via SEED_CLIENT_SECRET and intentionally not printed.
Idempotent user seeding
cmd/seed/main.go
seedUsers calls createUserIfNotExists for an admin and a demo user. createUserIfNotExists looks up each user by email, returns the existing record if found, or bcrypt-hashes the password and creates a new user with name, role, activation, verification, and OAuthProvider: "local" fields set.
Idempotent OAuth client seeding
cmd/seed/main.go
seedOAuthClient requires SEED_CLIENT_SECRET environment variable (returns error if missing), checks for an existing client by fixed client ID, bcrypt-hashes the secret, and creates the client with redirect URIs, scopes, and the admin user ID as owner only when absent.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • Local Development Seeding Script #192: This PR directly implements the make seed command and cmd/seed/main.go seeding script described in the issue, fulfilling the acceptance criteria of seeding dummy users and an OAuth client for developer onboarding.

Poem

🐇 Hop, hop, hooray for the seed command today!
No more empty databases blocking my way.
An admin, a demo, an OAuth client too,
Idempotent magic — run it once or run it two!
The bunny has planted, the garden will grow,
make seed is the shortcut every dev should know. 🌱

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is comprehensive with clear sections covering summary, changes, seeded data, verification, and problem solved, but the required CLA checklist is not completed. Complete the CLA checklist by confirming you have read and signed the CLA, and confirm that your changes follow the project's coding style and have been tested.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a database seeding command for development onboarding.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/seed/main.go`:
- Around line 47-62: The seed output in the main function is logging plaintext
passwords and client secrets directly, which creates a security vulnerability by
exposing sensitive credentials in CI/runtime logs. Remove or redact the lines
that print the actual password values for the Admin User and Demo User, as well
as the line that prints the actual Client Secret for the OAuth Client. Keep the
labels and structure for clarity but do not output the actual sensitive values.
- Around line 14-18: The main function in cmd/seed/main.go allows database
seeding in any environment after calling config.LoadConfig(), which is a
security risk since it inserts known admin credentials. Add an environment
validation check immediately after the config.LoadConfig() call and before
config.InitDatabase() is invoked. This check should verify that the application
is running in a development environment, and if not, log a fatal error message
and exit the process to fail closed. This ensures the seeding command cannot
accidentally run against production or other non-development databases.
- Around line 151-157: The FindByClientID method in the OAuthClientRepository is
returning raw GORM errors without distinguishing between "record not found" and
other database errors, which masks transient failures as missing clients. Define
a sentinel error constant ErrOAuthClientNotFound in the repository package,
update the FindByClientID method to detect gorm.ErrRecordNotFound and return
this sentinel error instead, and then modify the seedOAuthClient function to
explicitly check if the error from FindByClientID is not the sentinel error
(meaning it's an actual database problem) and return that error before
attempting client creation, allowing the code to only proceed with creation when
the client genuinely doesn't exist.
- Around line 119-122: The seedUsers() and seedOAuthClient() functions are
ignoring the configured bcrypt cost from cfg.Security.BcryptRounds and using
bcrypt.DefaultCost instead. Modify both seedUsers() and seedOAuthClient() to
accept a bcryptCost parameter, then update the calls to GenerateFromPassword()
in both functions to use this parameter instead of bcrypt.DefaultCost. Finally,
pass cfg.Security.BcryptRounds as an argument when calling seedUsers() and
seedOAuthClient() from the main() function to ensure the configured security
policy is applied to all seeded password hashes.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b5b104b-4434-44de-b134-c18eebc92deb

📥 Commits

Reviewing files that changed from the base of the PR and between d61168a and cc66fec.

📒 Files selected for processing (2)
  • Makefile
  • cmd/seed/main.go

Comment thread cmd/seed/main.go
Comment thread cmd/seed/main.go
Comment thread cmd/seed/main.go
Comment thread cmd/seed/main.go
Comment on lines +151 to +157
existingClient, err := clientRepo.FindByClientID("dev-client")

if err == nil && existingClient != nil {
log.Println("OAuth client already exists")
return 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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify FindByClientID's not-found/error contract in repository code.
fd -i "oauth*repository*.go" internal/repository
rg -n -C3 'FindByClientID|Err.*NotFound|gorm\.ErrRecordNotFound' internal/repository

Repository: roshankumar0036singh/auth-server

Length of output: 8891


🏁 Script executed:

cat -n internal/repository/oauth_client_repository.go

Repository: roshankumar0036singh/auth-server

Length of output: 2279


🏁 Script executed:

sed -n '140,170p' cmd/seed/main.go

Repository: roshankumar0036singh/auth-server

Length of output: 732


Define sentinel error in repository and handle non-not-found errors before client creation.

The FindByClientID method returns raw GORM errors without distinguishing between "record not found" and other errors, causing transient DB failures to be masked as "client doesn't exist". Follow the pattern established by UserRepository and TokenRepository:

  1. Define var ErrOAuthClientNotFound = errors.New("oauth client not found") in the repository package
  2. Update FindByClientID to check errors.Is(err, gorm.ErrRecordNotFound) and return the sentinel error
  3. In seedOAuthClient, check for non-not-found errors before the creation flow:
    if err != nil && !errors.Is(err, repository.ErrOAuthClientNotFound) {
        return err
    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/seed/main.go` around lines 151 - 157, The FindByClientID method in the
OAuthClientRepository is returning raw GORM errors without distinguishing
between "record not found" and other database errors, which masks transient
failures as missing clients. Define a sentinel error constant
ErrOAuthClientNotFound in the repository package, update the FindByClientID
method to detect gorm.ErrRecordNotFound and return this sentinel error instead,
and then modify the seedOAuthClient function to explicitly check if the error
from FindByClientID is not the sentinel error (meaning it's an actual database
problem) and return that error before attempting client creation, allowing the
code to only proceed with creation when the client genuinely doesn't exist.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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.

♻️ Duplicate comments (1)
cmd/seed/main.go (1)

163-168: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle non-not-found errors before client creation.

The code doesn't handle database errors from FindByClientID. If the lookup fails with a connection error or other database issue, the code silently continues to create the client, which may fail with a duplicate key error (if the client actually exists) or mask the real database problem.

Follow the pattern from createUserIfNotExists (lines 116-125): check for the sentinel error and return other errors immediately.

Run the following script to verify the repository's error handling contract:

#!/bin/bash
# Description: Check if OAuthClientRepository uses sentinel errors like UserRepository

# Check if ErrOAuthClientNotFound sentinel error exists
rg -n 'ErrOAuthClientNotFound' internal/repository/

# Check FindByClientID implementation
ast-grep outline internal/repository/oauth_client_repository.go --match OAuthClientRepository

# Compare error handling patterns between repositories
rg -n -A5 'FindByClientID|FindByEmail' internal/repository/ | grep -A5 'gorm.ErrRecordNotFound'

If ErrOAuthClientNotFound doesn't exist, add it to the repository package and update FindByClientID to return it when the record is not found. Then update the seed code:

🔒 Suggested fix
 existingClient, err := clientRepo.FindByClientID("dev-client")
 
-if err == nil && existingClient != nil {
+if err == nil {
 	log.Println("OAuth client already exists")
 	return nil
 }
+
+if err != repository.ErrOAuthClientNotFound {
+	return err
+}
 
 clientSecret := os.Getenv("SEED_CLIENT_SECRET")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/seed/main.go` around lines 163 - 168, The FindByClientID call in the seed
code doesn't properly handle database errors because it only checks if the error
is nil, causing the code to silently continue if other database errors occur.
First, ensure that the FindByClientID method in the OAuthClientRepository
returns a sentinel error (such as ErrOAuthClientNotFound) when the record is not
found, similar to how UserRepository handles not-found cases. Then update the
error handling logic around the FindByClientID call to follow the pattern from
createUserIfNotExists by checking if the error is the sentinel not-found error
and returning other non-nil errors immediately before attempting to create the
client.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@cmd/seed/main.go`:
- Around line 163-168: The FindByClientID call in the seed code doesn't properly
handle database errors because it only checks if the error is nil, causing the
code to silently continue if other database errors occur. First, ensure that the
FindByClientID method in the OAuthClientRepository returns a sentinel error
(such as ErrOAuthClientNotFound) when the record is not found, similar to how
UserRepository handles not-found cases. Then update the error handling logic
around the FindByClientID call to follow the pattern from createUserIfNotExists
by checking if the error is the sentinel not-found error and returning other
non-nil errors immediately before attempting to create the client.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 59a0a80a-ce18-4e48-8829-bcc8ccf30be2

📥 Commits

Reviewing files that changed from the base of the PR and between cc66fec and c8861be.

📒 Files selected for processing (1)
  • cmd/seed/main.go

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.

1 participant