ring-mapping-service-resources

star 197

Mapping a Go service's Service -> Module -> Resource hierarchy for dispatch-layer registration: detects modules and per-module PostgreSQL/MongoDB/RabbitMQ resources, database names, and shared databases, generates MongoDB index migration pairs (.up.json/.down.json), detects existing Postgres migrations, emits an HTML report, and offers opt-in S3 upload. Use before ring:adding-multi-tenancy on a new service. Skip for non-Go projects.

LerianStudio By LerianStudio schedule Updated 6/6/2026

name: ring:mapping-service-resources description: "Mapping a Go service's Service -> Module -> Resource hierarchy for dispatch-layer registration: detects modules and per-module PostgreSQL/MongoDB/RabbitMQ resources, database names, and shared databases, generates MongoDB index migration pairs (.up.json/.down.json), detects existing Postgres migrations, emits an HTML report, and offers opt-in S3 upload. Use before ring:adding-multi-tenancy on a new service. Skip for non-Go projects."

Service Discovery

When to use

  • User wants to know what to provision in dispatch layer for a service
  • User asks "what services/modules/resources does this project have?"
  • Before running ring:adding-multi-tenancy on a new service
  • User asks about MongoDB indexes in a project

Skip when

  • Not a Go project
  • Task does not involve service discovery, dispatch layer, or resource mapping
  • Project has no external dependencies

Related

Complementary: ring:adding-multi-tenancy, ring:implementing-tasks

Prerequisites

  • Go project with go.mod in the current working directory

Scans Go project to produce dispatch layer registration data. Orchestrator executes all detection phases directly.

Phase 1: Service Detection

# Service name
grep "ApplicationName\|ServiceName" internal/bootstrap/config.go 2>/dev/null | head -5
cat .env.example 2>/dev/null | grep -i "APPLICATION_NAME\|SERVICE_NAME" | head -3

# Service type
test -f go.mod && cat go.mod | head -3  # module path hints service purpose
ls internal/adapters/ 2>/dev/null       # adapters reveal type

# Unified service check
ls components/ 2>/dev/null              # multiple components = unified service

Output:

service_name: "my-service"
is_unified: true | false
components: [{name, path, applicationName}]  # if unified

Phase 2: Module Detection

# Strategy A: Explicit WithModule calls (preferred)
grep -rn "WithModule(" internal/ components/ 2>/dev/null
# Extract string arg: WithModule("onboarding") → module "onboarding"

# Strategy B: Component-based (if no WithModule found)
ls components/  # each component = one module
# module_name = component's ApplicationName

# Strategy C: Single-component fallback
# module_name = service ApplicationName

Merge: Strategy A → B fills gaps → C fallback.

Phase 3: Resource Detection per Module

For each module, scan {component_path}/internal/adapters/:

# PostgreSQL: subdirectory existence
ls {base_path}postgres/ 2>/dev/null

# MongoDB
ls {base_path}mongodb/ 2>/dev/null || ls {base_path}mongo/ 2>/dev/null

# RabbitMQ
ls {base_path}rabbitmq/ 2>/dev/null
grep -l "producer\|Producer" {base_path}rabbitmq/ 2>/dev/null
grep -l "consumer\|Consumer" {base_path}rabbitmq/ 2>/dev/null

# Redis (informational only — NOT a dispatch layer resource)
ls {base_path}redis/ 2>/dev/null

Phase 3.5: Database Name Detection per Module

# From bootstrap config
grep -E 'env:"POSTGRES_NAME|env:"DB_.*_NAME|env:"MONGO_NAME|env:"MONGO_.*_NAME' \
  {component_path}/internal/bootstrap/config.go

# From .env.example (actual values)
grep -E "POSTGRES_NAME=|DB_.*_NAME=|MONGO_NAME=|MONGO_.*_NAME=" {component_path}/.env.example

# External datasources
grep -E "DATASOURCE_.*_DATABASE=" {component_path}/.env.example

Cross-reference across modules: same database name in 2+ modules = shared (provision once).

Phase 4: MongoDB Index Detection & Migration File Generation

Only execute if MongoDB was detected in any module during Phase 3.

Execute the procedure in references/mongodb-index-detection.md — Steps 1, 2, 3, 4 only. (Detection and local generation only; S3 upload is handled in Phase 6.)

  1. Step 1 — Detect in-code index definitions (EnsureIndexes, IndexModel, CreateIndex) per module.
  2. Step 2 — Detect existing local migration files in {component_path}/scripts/mongodb/*.up.json + *.down.json (fallback legacy *.js). LOCAL ONLY — no S3 lookup.
  3. Step 3 — Cross-reference code vs. local migration files, classify each as covered / missing_migration / migration_only.
  4. Step 4 — Generate one .up.json + .down.json file pair per missing index (atomic per index, NOT grouped by collection):
    • Path: {component_path}/scripts/mongodb/{NNNNNN}_{index_name}.up.json / .down.json — per-module directory preserves ownership for Phase 6 upload (single-component services resolve {component_path} to repo root)
    • Naming: idx_{collection}_{fields} (or uniq_* for uniqueness business rules)
    • HARD GATE: every .up.json MUST have explicit "options.name" matching the file name
    • Track per module: populate module.generated_migration_files = [{up_file, down_file, index_name}, ...] so Phase 6 knows exactly which files belong to which module

Format reminder: the dispatch layer reads .up.json / .down.json from S3 and applies indexes on tenant provisioning. The service does NOT execute these files. Legacy .js scripts are NOT uploaded — only JSON migrations.

Phase 4.5: PostgreSQL Migration Detection

Only execute if PostgreSQL was detected in any module during Phase 3.

Detection only — Postgres migrations are written by developers; this skill does NOT generate .sql files.

# Common golang-migrate locations (per module path resolved in Phase 3)
ls {component_path}/scripts/postgres/*.up.sql 2>/dev/null
ls {component_path}/scripts/postgresql/*.up.sql 2>/dev/null
ls {component_path}/db/migrations/*.up.sql 2>/dev/null
ls {component_path}/migrations/*.up.sql 2>/dev/null

For each .up.sql file found:

  • Verify the matching .down.sql exists (golang-migrate convention).
  • Map it to its module (by directory path).
  • Track for the Phase 6 upload.

Store: module.postgres_migrations = [{up_file, down_file, sequence, description}]

If a .up.sql exists without .down.sql → flag in Phase 5 HTML report (golang-migrate requires pairs).

Phase 5: Generate HTML Report

Dispatch ring:visualizing:

Generate HTML report showing:
- Service: {service_name} | Unified: {is_unified}
- For each module:
  - Resources table: type, repositories/collections, has_producer, has_consumer, queues
  - Database names: postgres_db, mongo_db (with env var names)
  - Redis: detected / not detected (note: key prefixing only)
- Shared databases: list with modules that share them
- Dispatch layer registration template (JSON)
- MongoDB index coverage table (collection / keys / code / migration / index name) per `references/mongodb-index-detection.md` "Report Section: MongoDB Index Coverage"
- PostgreSQL migration table per module: file count, missing-pair warnings (`.up.sql` without `.down.sql`)
- Upload-ready summary: total Mongo pairs and Postgres pairs to be offered for upload in Phase 6

Style: clean, data-dense table layout

Phase 6: Optional S3 Upload

Execute after Phase 5. Always opt-in — never upload without explicit user confirmation.

1. Print summary and ask:
   "Ready to upload to S3:
    - MongoDB: {N} index migration pairs (.up.json/.down.json) across {M} modules
    - PostgreSQL: {P} migration pairs (.up.sql/.down.sql) across {Q} modules
    Upload to S3? (y/n)"

2. If user declines → done. Files remain local. Report status: "Upload skipped by user."

3. If user accepts:
   a. Verify AWS CLI: `aws --version`. If absent → abort, report "AWS CLI not installed."
   b. Ask: "Which S3 bucket? (e.g., lerian-development-migrations)"
   c. Ask: "Which environment? (staging / production)"
   d. Verify access: `aws s3 ls s3://{bucket}/{env}/ 2>&1`. If access denied or 404 → abort, report error.

4. Upload Mongo files (per module, best-effort — continue on individual failures):
   for each module with module.generated_migration_files populated in Phase 4:
     for each {up_file, down_file} in module.generated_migration_files:
       aws s3 cp {up_file}   s3://{bucket}/{env}/{service}/{module}/mongodb/$(basename {up_file})   --content-type "application/json"
       aws s3 cp {down_file} s3://{bucket}/{env}/{service}/{module}/mongodb/$(basename {down_file}) --content-type "application/json"

5. Upload Postgres files (per module, best-effort):
   for each module with module.postgres_migrations populated in Phase 4.5:
     for each {up_file, down_file} in module.postgres_migrations:
       aws s3 cp {up_file}   s3://{bucket}/{env}/{service}/{module}/postgresql/$(basename {up_file})   --content-type "application/sql"
       aws s3 cp {down_file} s3://{bucket}/{env}/{service}/{module}/postgresql/$(basename {down_file}) --content-type "application/sql"

6. Verify per module:
   aws s3 ls s3://{bucket}/{env}/{service}/{module}/mongodb/
   aws s3 ls s3://{bucket}/{env}/{service}/{module}/postgresql/

7. Report uploaded files (full s3:// paths) and any errors. Do NOT abort the whole run if a single file fails — list failures at the end.

Path convention (matches actual bucket layout): s3://{bucket}/{env}/{service}/{module}/{mongodb|postgresql}/{filename}

Output: Dispatch Layer Registration Template

{
  "service": "{service_name}",
  "modules": [
    {
      "name": "{module_name}",
      "resources": [
        {
          "type": "postgresql",
          "database": "{db_name}",
          "env_var": "POSTGRES_NAME"
        },
        {
          "type": "mongodb",
          "database": "{db_name}",
          "env_var": "MONGO_NAME"
        },
        {
          "type": "rabbitmq",
          "has_producer": true,
          "has_consumer": true,
          "queues": ["{queue_name}"]
        }
      ]
    }
  ],
  "shared_databases": []
}
Install via CLI
npx skills add https://github.com/LerianStudio/ring --skill ring-mapping-service-resources
Repository Details
star Stars 197
call_split Forks 22
navigation Branch main
article Path SKILL.md
More from Creator
LerianStudio
LerianStudio Explore all skills →