-
Notifications
You must be signed in to change notification settings - Fork 0
Create admin user on startup #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Issues: The ADMIN_EMAIL, LL_ADMIN_ORG, and LL_ADMIN_PASSWORD needs to be read from environment
# Conflicts: # compose.yaml
Makes more sense outside of testing.
Summary by CodeRabbit
WalkthroughRemoves the admin Taskfile task, adds executable scripts for migrations and seeds, restructures compose.yaml to add migrations/seeds services, swaps API/UI roles and ports, adds health-based depends_on and LL_ADMIN_* env vars, and enables strict shell handling in several bin/* scripts. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Compose as Docker Compose
participant Mongo as mongo
participant Migrate as migrations
participant Seeds as seeds
participant API as api
participant Worker as worker
participant CLI as cli
Compose->>Mongo: start (healthcheck)
Mongo-->>Compose: healthy
Compose->>Migrate: start (depends_on: Mongo healthy)
Migrate-->>Compose: completed_successfully
Compose->>Seeds: start (depends_on: Migrate success)
Seeds-->>Compose: completed_successfully (creates admin via LL_ADMIN_*)
Compose->>API: start (depends_on: Mongo healthy, Seeds success, Redis healthy)
Compose->>Worker: start (depends_on: Mongo/Redis healthy)
Compose->>CLI: available (tty, no depends_on)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
Taskfile.docker.yaml(1 hunks)bin/migrations(1 hunks)bin/seeds(1 hunks)compose.yaml(1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
Taskfile.docker.yaml
[error] 41-41: too many spaces inside brackets
(brackets)
[error] 41-41: too many spaces inside brackets
(brackets)
compose.yaml
[error] 40-40: wrong indentation: expected 6 but found 4
(indentation)
[error] 42-42: wrong indentation: expected 6 but found 4
(indentation)
[error] 45-45: wrong indentation: expected 8 but found 6
(indentation)
[error] 51-51: too many spaces inside brackets
(brackets)
[error] 51-51: too many spaces inside brackets
(brackets)
[error] 63-63: wrong indentation: expected 8 but found 6
(indentation)
[error] 78-78: wrong indentation: expected 8 but found 6
(indentation)
[error] 88-88: wrong indentation: expected 8 but found 6
(indentation)
[error] 111-111: too many spaces inside brackets
(brackets)
[error] 111-111: too many spaces inside brackets
(brackets)
[error] 113-113: wrong indentation: expected 6 but found 4
(indentation)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build container image
🔇 Additional comments (4)
Taskfile.docker.yaml (1)
41-41: Fix flow-sequence bracket spacing and quote the commandYamllint’s E211 rule flags the extra spaces after
[and before]. Quoting the entire invocation also ensures$COMPOSE_CMD run cliis treated as a single list item.
- File: Taskfile.docker.yaml, line 41
- cmds: [ $COMPOSE_CMD run cli ] + cmds: ["$COMPOSE_CMD run cli"](Optional: to launch an interactive shell instead, you could use:
cmds: ["$COMPOSE_CMD run --rm --service-ports cli sh"] ```) </details> <details> <summary>compose.yaml (3)</summary> `39-46`: **Normalize `ports` list indentation** To satisfy yamllint’s indentation rules for YAML lists, update the `ports` entry in compose.yaml (lines 39–46) to use an inline list or correctly indent the block style. For example: ```diff - ports: - - "3000:3000" + ports: ["3000:3000"]After applying this change, please re-run yamllint to confirm that the indentation warning for
portsis resolved.
109-116: MongoDB downgrade to 4.4: confirm driver/migrations compatibility & streamline healthcheck
- package.json shows
• “mongodb”: “^2.1.4”
• “mongoose”: “^5.4.0”
These client versions predate MongoDB 4.x—please verify they fully support server 4.4 APIs and wire protocols.- Migrations live under cli/src/commands/v1-migrations/ and cli/src/commands/v2-migrations/ – review them for any commands or operators introduced after 4.4.
- Replace the healthcheck with a simpler, deterministic command:
- test: "mongo --nodb --eval 'disableTelemetry()'; echo 'db.runCommand({ping: 1}).ok' | mongo localhost:27017/test --quiet" + test: ["CMD-SHELL", "echo 'db.runCommand({ ping: 1 }).ok' | mongo localhost:27017/test --quiet"]Let me know if you’d like an automated scan of your migration scripts.
93-93: Explicit command invocation confirmed
- Dockerfile (lines 4, 20): WORKDIR is set to
/opt/learninglocker- Dockerfile (line 36):
COPY bin ./binensures thebin/directory is included- File
bin/seedsexists and is executable (-rwxr-xr-x)- command: seeds + command: ["bin/seeds"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🔭 Outside diff range comments (1)
bin/entrypoint (1)
2-10: Avoid CWD-dependent PATH by deriving bin dir from script locationUsing ./bin assumes the entrypoint’s working directory. Derive the bin dir from the script’s directory so PATH is correct regardless of CWD.
#!/usr/bin/env sh set -eu MONGO_HOST="${MONGO_HOST:-localhost}" MONGO_PORT="${MONGO_PORT:-27017}" MONGO_DATABASE="${MONGO_DATABASE:-learninglocker_v2}" export MONGODB_PATH="mongodb://${MONGO_HOST}:${MONGO_PORT}/${MONGO_DATABASE}" -export PATH=./bin:$PATH +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +export PATH="$SCRIPT_DIR:$PATH" exec "$@"
♻️ Duplicate comments (3)
bin/migrations (1)
1-5: Follow-up: resolve CLI path relative to script and exec itGood addition of strict mode. As previously noted, using a relative path for the CLI couples this script to the working directory. Resolve the path relative to this script and exec to propagate signals/exit codes cleanly.
#!/usr/bin/env sh set -eu echo "Executing database migrations ..." -node cli/dist/server migrateMongo --up +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +TARGET="$SCRIPT_DIR/../cli/dist/server" +if [ ! -f "$TARGET" ]; then + echo "CLI entry not found at $TARGET (did you build the CLI?)" >&2 + exit 1 +fi +exec node "$TARGET" migrateMongo --upbin/seeds (2)
5-5: Don’t pass secrets via argv; use stdin or env consumption in the CLIPassword on the command line is visible in process lists and logs. Prefer stdin or environment-based consumption by the CLI.
If the CLI can read the password from stdin, switch to a flag like --password-stdin and pipe the secret:
-echo "Setting up seed data ..." -node cli/dist/server createSiteAdmin "${LL_ADMIN_EMAIL:?}" "${LL_ADMIN_ORG:?}" "${LL_ADMIN_PASSWORD:?}" +echo "Setting up seed data ..." +# Avoid leaking the password via argv; feed it on stdin if supported by the CLI: +printf '%s' "${LL_ADMIN_PASSWORD:?}" | node cli/dist/server createSiteAdmin --email "${LL_ADMIN_EMAIL:?}" --org "${LL_ADMIN_ORG:?}" --password-stdinIf stdin is not yet supported, I can update the CLI to accept env/flags for non-interactive secrets (e.g., LL_ADMIN_PASSWORD or --password-env). Want me to open a follow-up PR?
5-5: Decouple from working directory for robust executionUse a script-relative path so the seeds job works regardless of cwd/ENTRYPOINT.
echo "Setting up seed data ..." -node cli/dist/server createSiteAdmin "${LL_ADMIN_EMAIL:?}" "${LL_ADMIN_ORG:?}" "${LL_ADMIN_PASSWORD:?}" +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +exec node "$SCRIPT_DIR/../cli/dist/server" createSiteAdmin "${LL_ADMIN_EMAIL:?}" "${LL_ADMIN_ORG:?}" "${LL_ADMIN_PASSWORD:?}"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
bin/api(1 hunks)bin/cli(1 hunks)bin/entrypoint(1 hunks)bin/migrations(1 hunks)bin/seeds(1 hunks)bin/ui(1 hunks)bin/worker(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build container image
🔇 Additional comments (3)
bin/migrations (1)
4-5: Migrations and seeds are idempotent and correctly wired– compose.yaml ensures the migrations service only starts after Mongo is healthy and the seeds service only runs once migrations complete successfully.
– bin/seeds invokescreateSiteAdminwithLL_ADMIN_*vars, andcreateSiteAdminuses find-or-create logic (with duplicate-key checks) to avoid recreating users or orgs.
– ThemigrateMongoCLI command delegates to the custom migrator (tested in migrateMongo-test.js), which records applied migrations and only runs outstanding ones, making it safe to re-run.No further changes required.
bin/worker (1)
2-2: Good addition: enable strict mode earlyset -eu is appropriate here and will fail fast on errors/unset vars.
bin/seeds (1)
1-2: Solid hardening: strict mode enabledset -eu and the use of ${VAR:?} are good choices to fail fast and catch unset envs.
| set -eu | ||
|
|
||
| echo "Setting up seed data ..." | ||
| node cli/dist/server createSiteAdmin "${LL_ADMIN_EMAIL:?}" "${LL_ADMIN_ORG:?}" "${LL_ADMIN_PASSWORD:?}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify idempotency/upsert semantics of createSiteAdmin
The PR objective requires creating or upserting an admin on startup. Please confirm the CLI operation is idempotent (no duplicate users, safe on re-runs).
Run this script to locate the implementation and check for upsert/exists handling:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for CLI command createSiteAdmin definition and usage..."
rg -n -C3 -S '\bcreateSiteAdmin\b'
echo
echo "Scanning for idempotent patterns near user creation (upsert/exists/unique)..."
rg -n -C3 -iP 'upsert|onConflict|unique|ensureIndex|already exists|duplicate key|findOne|findUnique|findFirst'
echo
echo "If Prisma is used, look for upsert calls:"
rg -n -C3 -iP '\bupsert\s*\('
echo
echo "If Mongoose is used, check for findOneAndUpdate with upsert: true:"
rg -n -C3 -iP 'findOneAndUpdate\s*\(.*upsert\s*:\s*true'Length of output: 133165
🏁 Script executed:
#!/bin/bash
# Display the key parts of createSiteAdmin implementation to verify idempotency
sed -n '1,200p' cli/src/commands/createSiteAdmin.jsLength of output: 3909
Fix idempotency in createSiteAdmin
The current implementation of createSiteAdmin is not idempotent because:
- Organisation assignment always pushes a duplicate entry on every run.
- Password‐force update silently fails to persist when the user is already a SITE_ADMIN.
Please update cli/src/commands/createSiteAdmin.js:
- In
ensureUserHasOrg(≈line 39), compare IDs—not name—to detect an existing org:
- const foundOrg = _.find(user.organisations, org => org.toString() === organisation.name);
+ const foundOrg = _.find(
+ user.organisations,
+ orgId => orgId.toString() === organisation._id.toString()
+ );- In
ensureSiteAdmin(≈line 23), always save when forcing a password update (even if the SITE_ADMIN scope already exists):
- async function ensureSiteAdmin(user, password, forceUpdatePassword) {
- if (forceUpdatePassword) user.password = password;
- if (!_.includes(user.scopes, scopes.SITE_ADMIN)) {
- user.scopes.push(scopes.SITE_ADMIN);
- return await user.save();
- }
- return user;
- }
+ async function ensureSiteAdmin(user, password, forceUpdatePassword) {
+ let modified = false;
+ if (forceUpdatePassword) {
+ user.password = password;
+ modified = true;
+ }
+ if (!_.includes(user.scopes, scopes.SITE_ADMIN)) {
+ user.scopes.push(scopes.SITE_ADMIN);
+ modified = true;
+ }
+ if (modified) {
+ await user.save();
+ }
+ return user;
+ }With these changes, rerunning bin/seeds will no longer accumulate duplicate organisations or drop intended password updates.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In cli/src/commands/createSiteAdmin.js around lines 23 and 39, fix idempotency:
in ensureUserHasOrg (≈line 39) check existing user.organisations by
organisation.id (not by name) and only push the org object if no matching id
exists to avoid duplicate entries; in ensureSiteAdmin (≈line 23) when
force-password is requested, always assign the new password and call await
user.save() even if the SITE_ADMIN scope is already present so the password
change persists. Ensure both checks use strict ID comparison and await any save
calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Duplicate organisation: Probably bad, should be investigated
- Not updating password: Actually the intended behaviour once the account exists
+ formatting
|
@coderabbitai Recreate the sequence diagram, but include the redis service |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainI'll recreate the sequence diagram including the Redis service. Let me first examine the current system architecture to understand all service interactions. Now I'll create a comprehensive sequence diagram that includes Redis and shows the complete startup orchestration: @ralf-berger Here's the updated sequence diagram that includes the Redis service and shows the complete startup orchestration: sequenceDiagram
participant User as User/Docker Compose
participant Mongo as MongoDB
participant Redis as Redis
participant Migrations as Migrations Service
participant Seeds as Seeds Service
participant API as API Service
participant UI as UI Service
participant Worker as Worker Service
participant XAPI as xAPI Service
User->>Mongo: Start MongoDB
User->>Redis: Start Redis
Note over Mongo: Health check: mongo --nodb --eval<br/>Waits until healthy
Note over Redis: Health check: redis-cli ping<br/>Waits until healthy
Mongo-->>User: MongoDB healthy ✓
Redis-->>User: Redis healthy ✓
User->>Migrations: Start migrations service
Migrations->>Mongo: Wait for healthy condition
Mongo-->>Migrations: Healthy ✓
Migrations->>Migrations: Execute: node cli/dist/server migrateMongo --up
Note over Migrations: Database migrations completed
Migrations-->>User: Service completed successfully ✓
User->>Seeds: Start seeds service
Seeds->>Migrations: Wait for completion
Migrations-->>Seeds: Completed successfully ✓
Seeds->>Seeds: Execute: node cli/dist/server createSiteAdmin<br/>with LL_ADMIN_EMAIL, LL_ADMIN_ORG, LL_ADMIN_PASSWORD
Note over Seeds: Admin user created/upserted
Seeds-->>User: Service completed (restart: on-failure) ✓
User->>API: Start API service
API->>Mongo: Wait for healthy condition
API->>Redis: Wait for healthy condition
API->>Seeds: Wait for successful completion
Mongo-->>API: Healthy ✓
Redis-->>API: Healthy ✓
Seeds-->>API: Completed successfully ✓
API->>API: Execute: node api/dist/server
Note over API: API server running on port 8080<br/>Connected to MongoDB and Redis
API-->>User: API service ready ✓
User->>Worker: Start worker service
Worker->>Mongo: Wait for healthy condition
Worker->>Redis: Wait for healthy condition
Mongo-->>Worker: Healthy ✓
Redis-->>Worker: Healthy ✓
Worker->>Worker: Execute: node worker/dist/server
Note over Worker: Background worker running<br/>Connected to MongoDB and Redis
Worker-->>User: Worker service ready ✓
User->>UI: Start UI service
UI->>API: Wait for API service
API-->>UI: API ready ✓
UI->>UI: Execute: node ui/dist/server
Note over UI: Frontend running on port 3000<br/>Proxies to API service
UI-->>User: UI service ready ✓
User->>XAPI: Start xAPI service
XAPI->>XAPI: Execute: node xapi/dist/server
Note over XAPI: xAPI service running independently
XAPI-->>User: xAPI service ready ✓
Note over User,XAPI: All services operational with admin user created<br/>MongoDB and Redis provide data persistence and caching
This sequence diagram now includes:
The Redis service provides caching and session management capabilities to both the API and Worker services, ensuring they don't start until Redis is fully operational. 🏁 Script executed: Length of output: 3450 🏁 Script executed: Length of output: 412 @ralf-berger Here's the updated sequence diagram that accurately reflects the Redis service integration based on the actual sequenceDiagram
participant User as User/Docker Compose
participant Mongo as MongoDB
participant Redis as Redis
participant Migrations as Migrations Service
participant Seeds as Seeds Service
participant API as API Service
participant UI as UI Service
participant Worker as Worker Service
participant XAPI as xAPI Service
User->>Mongo: Start MongoDB (mongo:4.4)
User->>Redis: Start Redis (redis:7)
Note over Mongo: Health check: mongo --nodb --eval<br/>+ ping command via mongo CLI
Note over Redis: Health check: redis-cli ping<br/>Every 10s, start period 2s
Mongo-->>User: MongoDB healthy ✓
Redis-->>User: Redis healthy ✓
User->>Migrations: Start migrations service
Migrations->>Mongo: Wait for healthy condition (restart: true)
Mongo-->>Migrations: Healthy ✓
Migrations->>Migrations: Execute: node cli/dist/server migrateMongo --up
Note over Migrations: "Executing database migrations ..."
Migrations-->>User: Service completed successfully ✓
User->>Seeds: Start seeds service
Seeds->>Migrations: Wait for completion
Migrations-->>Seeds: Completed successfully ✓
Seeds->>Seeds: Execute: node cli/dist/server createSiteAdmin<br/>"${LL_ADMIN_EMAIL:?}" "${LL_ADMIN_ORG:?}" "${LL_ADMIN_PASSWORD:?}"
Note over Seeds: "Setting up seed data ..."<br/>Admin: admin@mail.com, Org: soco<br/>(restart: on-failure)
Seeds-->>User: Service completed successfully ✓
User->>API: Start API service
API->>Mongo: Wait for healthy condition (restart: true)
API->>Redis: Wait for healthy condition (restart: true)
API->>Seeds: Wait for successful completion
Mongo-->>API: Healthy ✓
Redis-->>API: Healthy ✓
Seeds-->>API: Completed successfully ✓
API->>API: Execute: node api/dist/server
Note over API: API server on port 8080<br/>Health check via HTTP fetch<br/>QUEUE_PROVIDER: REDIS
API-->>User: API service healthy ✓
User->>Worker: Start worker service
Worker->>Mongo: Wait for healthy condition (restart: true)
Worker->>Redis: Wait for healthy condition (restart: true)
Mongo-->>Worker: Healthy ✓
Redis-->>Worker: Healthy ✓
Worker->>Worker: Execute: node worker/dist/server
Note over Worker: Background worker<br/>Uses Redis for queue processing
Worker-->>User: Worker service ready ✓
User->>UI: Start UI service
UI->>API: Wait for API healthy condition
API-->>UI: API healthy ✓
UI->>UI: Execute: node ui/dist/server
Note over UI: Frontend on port 3000<br/>Connects to API service
UI-->>User: UI service ready ✓
User->>XAPI: Start xAPI service
XAPI->>Mongo: Wait for healthy condition
XAPI->>Redis: Wait for healthy condition
Mongo-->>XAPI: Healthy ✓
Redis-->>XAPI: Healthy ✓
XAPI->>XAPI: Execute xAPI service
Note over XAPI: xAPI service on port 8081<br/>REDIS_URL: redis://redis:6379/0<br/>Platform: linux/amd64
XAPI-->>User: xAPI service ready ✓
Note over User,XAPI: Complete Learning Locker deployment<br/>✓ Admin user created (admin@mail.com)<br/>✓ Redis provides queuing and caching<br/>✓ All services connected to Redis cluster
Key Redis integrations shown in this diagram:
The Redis service is critical infrastructure - without it being healthy, the core application services (API, Worker, xAPI) won't start, ensuring the system has proper queuing and caching capabilities before handling requests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
♻️ Duplicate comments (2)
compose.yaml (2)
31-33: Remove LL_ADMIN_ from global env; scope to seeds and source from secrets/.env*Leaking admin creds via x-common propagates them to all services and into VCS. Scope strictly to the seeds service and require them at runtime.
Apply:
environment: QUEUE_PROVIDER: REDIS @@ APP_SECRET: "i-am-not-secure-please-change-me" - LL_ADMIN_EMAIL: "admin@mail.com" - LL_ADMIN_ORG: "soco" - LL_ADMIN_PASSWORD: "1234qweR"Then add under seeds (see lines 95-102):
seeds: <<: *common - command: seeds + command: seeds depends_on: migrations: condition: service_completed_successfully restart: on-failure + environment: + LL_ADMIN_EMAIL: ${LL_ADMIN_EMAIL:?} + LL_ADMIN_ORG: ${LL_ADMIN_ORG:?} + LL_ADMIN_PASSWORD: ${LL_ADMIN_PASSWORD:?}Optional: I can wire Docker secrets (LL_ADMIN_PASSWORD_FILE) if you prefer not to use env vars. Want me to open a follow-up PR for that?
95-97: Make commands explicit to the intended scripts (avoid PATH ambiguity)Be explicit about the executable to reduce surprises from PATH/env differences.
seeds: <<: *common - command: seeds + command: ["bin/seeds"] @@ migrations: <<: *common - command: migrations + command: ["bin/migrations"]Also applies to: 103-105
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
compose.yaml(2 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
compose.yaml
[error] 45-45: wrong indentation: expected 8 but found 6
(indentation)
[error] 67-67: wrong indentation: expected 8 but found 6
(indentation)
[error] 82-82: wrong indentation: expected 8 but found 6
(indentation)
[error] 92-92: wrong indentation: expected 8 but found 6
(indentation)
[error] 117-117: wrong indentation: expected 6 but found 4
(indentation)
🔇 Additional comments (1)
compose.yaml (1)
95-106: Seeds/migrations orchestration aligns with startup admin creation goalIntroducing dedicated migrations and seeds services with health/ordering semantics is a good approach and matches the PR objective.
Which issue does this close?
Closes #4 and #7