Communitygithub.com

EgoDZB/claude-skills

Convenciones de nomenclatura y esquemas para PostgreSQL (tablas, columnas, claves, restricciones, índices, relaciones, tipos) para .NET/EF Core, Node.js (Drizzle, Prisma, TypeORM, Knex) y Go (sqlc). Úsalo al diseñar o revisar esquemas, escribir migraciones, configuraciones de entidades, consultas sqlc o SQL, o cuando te pregunten cómo nombrar objetos de base de datos. Reporta las desviaciones al usuario en lugar de cambiarlas silenciosamente.

¿Qué es claude-skills?

Esta habilidad define un conjunto completo de convenciones de nomenclatura y esquemas para PostgreSQL, diseñado para ser utilizado al diseñar o revisar bases de datos, escribir migraciones, configuraciones de entidades (EF Core, Prisma, TypeORM, Drizzle, Knex), consultas sqlc o SQL puro. El objetivo principal es garantizar consistencia, legibilidad y evitar errores comunes relacionados con nombres entrecomillados, identificadores reservados, tipos de datos incorrectos o problemas de concurrencia. Funciona en dos modos: A (aplica las convenciones directamente) y B (reporta desviaciones al usuario sin cambios silenciosos). Es compatible con los stacks .NET/EF Core, Node.js (Drizzle, Prisma, TypeORM, Knex) y Go (sqlc), proporcionando configuraciones específicas para cada ORM. La habilidad prioriza la corrección sobre el estilo, distinguiendo entre violaciones 'Must fix' (que causan errores) y 'Recommended' (de estilo).

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/EgoDZB/claude-skills/tree/HEAD/skills/postgres-conventions

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Convenciones de PostgreSQL

Cómo aplicar

Hay dos modos. Decide cuál aplica antes de escribir nada.

Modo A — tú eliges los nombres. El usuario pidió un esquema, entidad o migración y no dictó nombres. Aplica las convenciones siguientes directamente.

Modo B — los nombres ya existen o fueron dictados. El usuario especificó nombres, o el código, las migraciones o la base de datos existentes contienen nombres que se desvían de estas convenciones. Nunca renombres silenciosamente. Reporta y pregunta.

Formato del reporte, en el idioma del usuario, antes de hacer cambios:

Nombramiento:
Debe corregirse
- `"UserProfile"` (tabla) → `user_profiles` — PascalCase entrecomillado debe estar entrecomillado en cada consulta para siempre
- `created` timestamp DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') → `created_at timestamptz DEFAULT now()` — el valor cambia cuando la zona horaria de la sesión no es UTC
Recomendado
- `users.user_email` → `users.email` — el nombre de la tabla ya es el contexto

Luego pregunta una pregunta: aplicar todo, aplicar solo "Debe corregirse", o mantener como está. Espera la respuesta.

Reglas para reportar:

  • Debe corregirse = causa errores, rompe consultas o herramientas: identificadores entrecomillados mixtos, palabras reservadas, nombres de más de 63 bytes, timestamp sin zona horaria, valores predeterminados incorrectos de tiempo, json/float/money para datos que necesitan jsonb/numeric, falta de índice FK, bloqueos fuera de una transacción.
  • Recomendado = estilo y consistencia.
  • Reporta solo objetos tocados por la tarea actual. Si notaste otras desviaciones en otro lugar, agrega una línea: "¿También N desviaciones similares en ? ¿Las listo?"
  • Objetos en migraciones aplicadas o una base de datos activa: un cambio de nombre es un cambio destructivo. Solo sugiérelo; si se aprueba, impleméntalo como una nueva migración. Nunca edites una migración aplicada.
  • Si el código usa consistentemente una convención diferente, esa gana. Menciona la diferencia una vez, luego sigue la convención del proyecto sin marcar cada ocurrencia.
  • Los nombres producidos por la convención de nomenclatura del ORM (por ejemplo, EFCore.NamingConventions) se aceptan tal cual.
  • Una vez que el usuario confirma un nombre no conforme, úsalo y no lo menciones de nuevo en esta sesión.

Reglas generales

  • snake_case, minúsculas, nunca identificadores entrecomillados.
  • Máximo 63 bytes por identificador; los nombres más largos se truncan silenciosamente. Acorta de forma significativa, no cortando.
  • Tablas en plural: users, orders, order_items.
  • Columnas en singular, sin prefijo de tabla: users.email, no users.user_email.
  • Palabras completas excepto abreviaturas comunes: id, url, ip, sku.
  • Nunca uses palabras reservadas o ambiguas como nombres: user, order, group, table, limit, offset, desc, end, date, time, timestamp.
  • Sin prefijos de tipo u objeto: no tbl_users, str_name.
  • Los booleanos son positivos: is_deleted, nunca is_not_deleted.

Columnas estándar

PropósitoNombreTipo
Clave primariaidbigint generated always as identity o uuid v7
Creado / actualizadocreated_at, updated_attimestamptz not null default now()
Borrado suavedeleted_attimestamptz null
Auditoríacreated_by, updated_byFK a users.id
Banderasis_active, is_verified, has_children, can_editboolean not null default false
Estadostatustext + check, enum, o tabla de búsqueda
Solo fechabirth_date, due_ondate
Validezexpires_at, valid_from, valid_totimestamptz
Dineroamount, unit_price, total_amount + currency_codenumeric(19,4) + char(3), o amount_minor bigint
Contadoresitems_count, retry_countinteger / bigint
Ordenamientosort_orderinteger
Clave de negociocode, slug, external_idtext + único
Inquilinotenant_idFK
Concurrenciaversion o sistema xmininteger / xid
Datos libresmetadata, payload, settingsjsonb

Los sufijos tienen significado: _at instante, _on/_date fecha calendario, _id referencia, _count contador, _url, _path, _hash.

Claves y restricciones

ObjetoPatrónEjemplo
Clave primariapk_<tabla>pk_orders
Clave foráneafk_<tabla>_<ref_tabla>_<columna>fk_orders_customers_customer_id
Restricción únicauq_<tabla>_<cols>uq_users_email
Clave alternativa (EF Core)ak_<tabla>_<cols>ak_products_sku
Checkck_<tabla>_<regla>ck_orders_amount_positive
Exclusiónex_<tabla>_<cols>ex_bookings_room_id_period
Índiceix_<tabla>_<cols>ix_orders_customer_id_created_at
Índice únicoux_<tabla>_<cols>ux_users_email
Índice parcialix_<tabla>_<cols>_<condición>ix_users_email_not_deleted
Índice por métodoix_<tabla>_<col>_<método>ix_products_tags_gin
Disparadortrg_<tabla>_<acción>trg_orders_set_updated_at
Función de disparadorverbo + objetoset_updated_at()
SecuenciaPredeterminado de PostgreSQLorders_id_seq
  • Columna FK: <tabla referenciada, singular>_id, o un nombre de rol cuando el rol importa: author_id, sender_id, recipient_id, parent_id.
  • El patrón FK incluye la columna, por lo que varias FK a una misma tabla siguen siendo únicas: fk_messages_users_sender_id, fk_messages_users_recipient_id.
  • PostgreSQL no indexa las columnas FK. Cada FK necesita un índice a menos que un índice compuesto ya comience con él. EF Core los crea por convención; Drizzle, Prisma, TypeORM, Knex y sqlc no.

Relaciones

TipoFormaEjemplo
Uno a muchosFK en el hijoorder_items.order_id → orders.id
Uno a unoFK + única, o PK = FKuser_profiles.user_id
Muchos a muchosUnión <a>_<b>, PK compuestauser_roles (user_id, role_id), pk_user_roles
Muchos a muchos con atributosNombre de entidad significativomemberships, enrollments
Autorreferenciaparent_id o rolcategories.parent_id, employees.manager_id

Los pares polimórficos (commentable_type + commentable_id) no pueden tener FK. Prefiere columnas FK separadas anulables con un check que exactamente una esté establecida, o tablas separadas.

Esquemas, vistas, funciones, tipos

ObjetoPatrónEjemplo
Esquemadominio o móduloauth, billing, catalog, audit
Vistav_<nombre>v_active_users
Vista materializadamv_<nombre>mv_daily_sales
Función / procedimientoverbo + objetoget_user_balance, calculate_order_total
Tipo enum<entidad>_<atributo>order_status
Valores del enumsnake_case minúsculapending, paid, refunded
Rol de base de datos<app>_<acceso>shop_app_rw, shop_app_ro, shop_migrator

Los valores del enum no se pueden eliminar sin recrear el tipo. Para conjuntos que cambian, prefiere text + check o una tabla de búsqueda.

Tipos y valores predeterminados

  • timestamptz para instantes, predeterminado now(). CURRENT_TIMESTAMP AT TIME ZONE 'UTC' en una columna timestamptz es un error.
  • text en lugar de varchar(n) a menos que la longitud sea una regla de negocio; prefiere check (char_length(col) <= n) para eso.
  • jsonb, nunca json.
  • numeric para dinero; nunca real, double precision o money.
  • Nuevas columnas de identidad usan generated always as identity, no serial/bigserial.
  • Las claves primarias UUID usan v7: PostgreSQL 18 uuidv7(), .NET 9 Guid.CreateVersion7(), paquete Node uuid v7(), Go github.com/google/uuid uuid.NewV7(). Las claves v4 aleatorias fragmentan los índices B-tree.
  • gen_random_uuid() está integrado desde PostgreSQL 13; uuid-ossp y pgcrypto no son necesarios para ello.
  • citext o un índice único lower(email) para unicidad sin distinción de mayúsculas y minúsculas.

Patrones de concurrencia y consultas

  • Concurrencia optimista, EF Core + Npgsql: una propiedad uint configurada con IsRowVersion() se asigna a xmin.
  • Concurrencia optimista, Node y Go: version integer not null default 0, actualizado con where id = $1 and version = $2 y version = version + 1; cero filas afectadas significa un conflicto. En sqlc usa :execrows para obtener el número de filas afectadas.
  • select ... for update y for update skip locked solo dentro de una transacción explícita; en autocommit el bloqueo se libera inmediatamente.
  • Bloqueos asesores: pg_try_advisory_xact_lock dentro de una transacción. pg_advisory_lock a nivel de sesión solo en una conexión dedicada mantenida abierta hasta desbloquear; con pooling, el bloqueo y desbloqueo pueden caer en diferentes conexiones.
  • Las listas grandes o infinitas usan paginación por conjunto de claves: where (created_at, id) < ($1, $2) order by created_at desc, id desc limit $3. offset solo para listas pequeñas y acotadas.
  • Los permisos para tablas futuras necesitan alter default privileges, no solo grant ... on all tables.

Configuración de ORM para snake_case

StackSetup
EF Core + NpgsqlEFCore.NamingConventions, UseSnakeCaseNamingConvention()
Drizzlecasing: 'snake_case'
Prisma@map en campos, @@map en modelos
TypeORMSnakeNamingStrategy de typeorm-naming-strategies
Knex / ObjectionknexSnakeCaseMappers()
Go + sqlcninguno; los nombres de Go se generan desde snake_case automáticamente

Si un proyecto usa un ORM sin snake_case configurado, repórtalo como Debe corregirse antes de la primera migración; después de que existan migraciones, repórtalo como Recomendado con el costo de la migración.

Go + sqlc

sqlc es primero SQL: el esquema proviene de los archivos de migración, por lo que cada regla anterior se aplica directamente a ellos.

  • Apunta schema en sqlc.yaml al directorio de migraciones (se admiten formatos goose, golang-migrate, dbmate y atlas; las migraciones descendentes se ignoran). Nunca mantengas un archivo de esquema escrito a mano separado junto a las migraciones.
  • Las tablas en snake_case plural dan estructuras Go singulares: order_items → OrderItem. Enum order_status → tipo OrderStatus con constantes OrderStatusPending.
  • Usa sql_package: pgx/v5. Sobrescribe uuid → github.com/google/uuid.UUID y, si se desea, timestamptz → time.Time en lugar de los envoltorios pgtype.
  • Corrige inicialismos con rename (url: URL, ip: IP) en lugar de renombrar columnas.
  • Los nombres de las consultas son PascalCase verbo + objeto, con el tipo de resultado:
PropósitoEjemplo
Una fila-- name: GetUserByEmail :one
Muchas filas-- name: ListOrdersByCustomer :many
Insertar-- name: CreateOrder :one + returning *
Actualizar-- name: UpdateOrderStatus :execrows
Eliminar-- name: DeleteSession :exec
Carga masiva-- name: CreateOrderItems :copyfrom
  • Nombra los parámetros con @name o sqlc.arg(name), y sqlc.narg(name) para los anulables; los posicionales $1 producen campos Go del estilo Column1.
  • Usa sqlc.embed(table) para uniones en lugar de seleccionar columnas con alias ad-hoc.
  • Nunca uses select * en consultas que deban sobrevivir a cambios de esquema, excepto returning * en escrituras.

Skills relacionados