Communitygithub.com

EgoDZB/claude-skills

Namens- und Schema-Konventionen für PostgreSQL (Tabellen, Spalten, Schlüssel, Constraints, Indizes, Beziehungen, Typen) für .NET/EF Core, Node.js (Drizzle, Prisma, TypeORM, Knex) und Go (sqlc). Verwenden Sie dies beim Entwerfen oder Überprüfen von Schemata, beim Schreiben von Migrationen, Entitätskonfigurationen, sqlc-Abfragen oder SQL oder wenn Sie gefragt werden, wie Datenbankobjekte benannt werden sollen. Meldet Abweichungen dem Benutzer, anstatt sie stillschweigend zu ändern.

Was ist claude-skills?

Diese Skill-Definition beschreibt ein umfassendes Regelwerk für PostgreSQL-Namens- und Schema-Konventionen, das für die Arbeit mit .NET/EF Core, Node.js (Drizzle, Prisma, TypeORM, Knex) und Go (sqlc) optimiert ist. Es hilft Entwicklern und KI-Agenten, konsistente, lesbare und robuste Datenbankstrukturen zu erstellen, indem es detaillierte Vorgaben für Tabellen, Spalten, Constraints, Indizes, Beziehungen und Typen macht. Der Skill unterstützt zwei Modi: Entweder er generiert direkt konforme Namen (Modus A) oder er erkennt Abweichungen von bestehenden Namenskonventionen und meldet diese dem Benutzer mit einer klaren Einteilung in „Must fix“ (muss korrigiert werden) und „Recommended“ (empfohlen) (Modus B). Dabei werden Breaking Changes (z. B. Umbenennungen in einer Live-Datenbank) nur als Vorschlag markiert. Die Skill-Dokumentation enthält zudem ORM-spezifische Setup-Anleitungen für snake_case, Concurrency-Muster, Paginierung und detaillierte Konventionen für sqlc-Abfragen. Es ist eine wertvolle Ressource für alle, die PostgreSQL-Schemata entwerfen, Migrationen schreiben oder Code-Reviews durchführen.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

PostgreSQL-Konventionen

Anwendung

Es gibt zwei Modi. Entscheiden Sie, welcher gilt, bevor Sie etwas schreiben.

Modus A — Sie wählen die Namen. Der Benutzer hat nach einem Schema, einer Entität oder einer Migration gefragt und keine Namen vorgegeben. Wenden Sie die untenstehenden Konventionen direkt an.

Modus B — Die Namen existieren bereits oder wurden vorgegeben. Der Benutzer hat Namen vorgegeben, oder vorhandener Code, Migrationen oder die Datenbank enthalten Namen, die von diesen Konventionen abweichen. Benennen Sie niemals stillschweigend um. Melden Sie die Abweichungen und fragen Sie nach.

Meldeformat in der Sprache des Benutzers, bevor Änderungen vorgenommen werden:

Naming:
Must fix (Muss korrigiert werden)
- `"UserProfile"` (Tabelle) → `user_profiles` — zitierte PascalCase-Namen müssen in jeder Abfrage für immer zitiert werden
- `created` timestamp DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') → `created_at timestamptz DEFAULT now()` — Der Wert verschiebt sich, wenn die Sitzung TimeZone nicht UTC ist
Empfohlen
- `users.user_email` → `users.email` — Der Tabellenname liefert bereits den Kontext

Stellen Sie dann eine Frage: Alle anwenden, nur "Must fix" anwenden oder so belassen. Warten Sie auf die Antwort.

Regeln für die Meldung:

  • Must fix (Muss korrigiert werden) = verursacht Fehler, bricht Abfragen oder Tooling: zitierte gemischte Bezeichner, reservierte Wörter, Namen über 63 Bytes, timestamp ohne Zeitzone, falsche Zeitstandards, json/float/money für Daten, die jsonb/numeric benötigen, fehlender FK-Index, Sperren außerhalb einer Transaktion.
  • Recommended (Empfohlen) = Stil und Konsistenz.
  • Melden Sie nur Objekte, die von der aktuellen Aufgabe betroffen sind. Wenn Sie andere Abweichungen an anderer Stelle bemerkt haben, fügen Sie eine Zeile hinzu: "Auch N ähnliche Abweichungen in — auflisten?"
  • Objekte in angewendeten Migrationen oder einer Live-Datenbank: Eine Umbenennung ist eine Breaking Change. Schlagen Sie es nur vor; wenn genehmigt, implementieren Sie es als neue Migration. Bearbeiten Sie niemals eine angewendete Migration.
  • Wenn die Codebasis konsistent eine andere Konvention verwendet, gewinnt diese. Erwähnen Sie den Unterschied einmal, folgen Sie dann der Projektkonvention, ohne jedes Vorkommen zu markieren.
  • Namen, die von der ORM-Namenskonvention erzeugt werden (z. B. EFCore.NamingConventions), werden akzeptiert.
  • Sobald der Benutzer einen nicht konformen Namen bestätigt hat, verwenden Sie ihn und erwähnen Sie ihn in dieser Sitzung nicht erneut.

Allgemeine Regeln

  • snake_case, Kleinbuchstaben, niemals zitierte Bezeichner.
  • Maximal 63 Bytes pro Bezeichner; längere Namen werden stillschweigend abgeschnitten. Sinnvoll kürzen, nicht durch Abschneiden.
  • Tabellen im Plural: users, orders, order_items.
  • Spalten im Singular, kein Tabellenpräfix: users.email, nicht users.user_email.
  • Ganze Wörter, außer gebräuchliche Abkürzungen: id, url, ip, sku.
  • Verwenden Sie niemals reservierte oder mehrdeutige Wörter als Namen: user, order, group, table, limit, offset, desc, end, date, time, timestamp.
  • Keine Typ- oder Objektpräfixe: kein tbl_users, str_name.
  • Booleans sind positiv: is_deleted, niemals is_not_deleted.

Standardspalten

ZweckNameTyp
Primärschlüsselidbigint generated always as identity oder uuid v7
Erstellt / Aktualisiertcreated_at, updated_attimestamptz not null default now()
Soft Deletedeleted_attimestamptz null
Auditcreated_by, updated_byFK zu users.id
Flagsis_active, is_verified, has_children, can_editboolean not null default false
Statusstatustext + Check, Enum oder Lookup-Tabelle
Nur Datumbirth_date, due_ondate
Gültigkeitexpires_at, valid_from, valid_totimestamptz
Geldamount, unit_price, total_amount + currency_codenumeric(19,4) + char(3), oder amount_minor bigint
Zähleritems_count, retry_countinteger / bigint
Sortierungsort_orderinteger
Geschäftsschlüsselcode, slug, external_idtext + unique
Mandanttenant_idFK
Nebenläufigkeitversion oder System xmininteger / xid
Freie Datenmetadata, payload, settingsjsonb

Suffixe haben eine Bedeutung: _at Zeitpunkt, _on/_date Kalenderdatum, _id Referenz, _count Zähler, _url, _path, _hash.

Schlüssel und Constraints

ObjektMusterBeispiel
Primärschlüsselpk_<table>pk_orders
Fremdschlüsselfk_<table>_<ref_table>_<column>fk_orders_customers_customer_id
Unique-Constraintuq_<table>_<cols>uq_users_email
Alternativschlüssel (EF Core)ak_<table>_<cols>ak_products_sku
Checkck_<table>_<rule>ck_orders_amount_positive
Ausschlussex_<table>_<cols>ex_bookings_room_id_period
Indexix_<table>_<cols>ix_orders_customer_id_created_at
Unique-Indexux_<table>_<cols>ux_users_email
Partieller Indexix_<table>_<cols>_<condition>ix_users_email_not_deleted
Index nach Methodeix_<table>_<col>_<method>ix_products_tags_gin
Triggertrg_<table>_<action>trg_orders_set_updated_at
Trigger-FunktionVerb + Objektset_updated_at()
SequenzPostgreSQL-Standardorders_id_seq
  • FK-Spalte: <referenzierte Tabelle, Singular>_id, oder ein Rollenname, wenn die Rolle wichtig ist: author_id, sender_id, recipient_id, parent_id.
  • Das FK-Muster enthält die Spalte, sodass mehrere FKs zu einer Tabelle eindeutig bleiben: fk_messages_users_sender_id, fk_messages_users_recipient_id.
  • PostgreSQL indiziert FK-Spalten nicht. Jeder FK benötigt einen Index, es sei denn, ein zusammengesetzter Index beginnt bereits damit. EF Core erstellt diese per Konvention; Drizzle, Prisma, TypeORM, Knex und sqlc tun dies nicht.

Beziehungen

ArtFormBeispiel
Eins-zu-VieleFK auf dem Kindorder_items.order_id → orders.id
Eins-zu-EinsFK + Unique, oder PK = FKuser_profiles.user_id
Viele-zu-VieleJunction <a>_<b>, zusammengesetzter PKuser_roles (user_id, role_id), pk_user_roles
Viele-zu-Viele mit AttributenAussagekräftiger Entitätsnamememberships, enrollments
Selbstreferenzparent_id oder Rollecategories.parent_id, employees.manager_id

Polymorphe Paare (commentable_type + commentable_id) können keine FKs haben. Bevorzugen Sie separate nullable FK-Spalten mit einem Check, dass genau eine gesetzt ist, oder separate Tabellen.

Schemata, Views, Funktionen, Typen

ObjektMusterBeispiel
SchemaDomäne oder Modulauth, billing, catalog, audit
Viewv_<name>v_active_users
Materialisierte Viewmv_<name>mv_daily_sales
Funktion / ProzedurVerb + Objektget_user_balance, calculate_order_total
Enum-Typ<entity>_<attribute>order_status
Enum-Wertesnake_case (Kleinbuchstaben)pending, paid, refunded
Datenbank-Rolle<app>_<access>shop_app_rw, shop_app_ro, shop_migrator

Enum-Werte können nicht gelöscht werden, ohne den Typ neu zu erstellen. Für Sätze, die sich ändern, bevorzugen Sie text + Check oder eine Lookup- Tabelle.

Typen und Standardwerte

  • timestamptz für Zeitpunkte, Standard now(). CURRENT_TIMESTAMP AT TIME ZONE 'UTC' auf einer timestamptz-Spalte ist ein Fehler.
  • text anstelle von varchar(n), es sei denn, die Länge ist eine Geschäftsregel; bevorzugen Sie dafür check (char_length(col) <= n).
  • jsonb, niemals json.
  • numeric für Geld; niemals real, double precision oder money.
  • Neue Identity-Spalten verwenden generated always as identity, nicht serial/bigserial.
  • UUID-Primärschlüssel verwenden v7: PostgreSQL 18 uuidv7(), .NET 9 Guid.CreateVersion7(), Node uuid-Paket v7(), Go github.com/google/uuid uuid.NewV7(). Zufällige v4-Schlüssel fragmentieren B-Tree-Indizes.
  • gen_random_uuid() ist seit PostgreSQL 13 eingebaut; uuid-ossp und pgcrypto werden dafür nicht benötigt.
  • citext oder ein lower(email) Unique-Index für Groß-/Kleinschreibungs-unabhängige Eindeutigkeit.

Nebenläufigkeit und Abfragemuster

  • Optimistische Nebenläufigkeit, EF Core + Npgsql: Eine uint-Eigenschaft, konfiguriert mit IsRowVersion(), wird auf xmin abgebildet.
  • Optimistische Nebenläufigkeit, Node und Go: version integer not null default 0, aktualisiert mit where id = $1 and version = $2 und version = version + 1; null betroffene Zeilen bedeuten einen Konflikt. Verwenden Sie in sqlc :execrows, um die Anzahl der betroffenen Zeilen zu erhalten.
  • select ... for update und for update skip locked nur innerhalb einer expliziten Transaktion; im Autocommit-Modus wird die Sperre sofort freigegeben.
  • Advisory Locks: pg_try_advisory_xact_lock innerhalb einer Transaktion. Session-Level pg_advisory_lock nur auf einer dedizierten Verbindung, die bis zum Entsperren offen gehalten wird; bei Pooling können Sperre und Entsperren auf verschiedenen Verbindungen landen.
  • Große oder unendliche Listen verwenden Keyset-Paginierung: where (created_at, id) < ($1, $2) order by created_at desc, id desc limit $3. offset nur für kleine begrenzte Listen.
  • Grants für zukünftige Tabellen benötigen alter default privileges, nicht nur grant ... on all tables.

ORM-Einrichtung für snake_case

StackEinrichtung
EF Core + NpgsqlEFCore.NamingConventions, UseSnakeCaseNamingConvention()
Drizzlecasing: 'snake_case'
Prisma@map auf Feldern, @@map auf Modellen
TypeORMSnakeNamingStrategy aus typeorm-naming-strategies
Knex / ObjectionknexSnakeCaseMappers()
Go + sqlckeine; Go-Namen werden automatisch aus snake_case generiert

Wenn ein Projekt ein ORM ohne snake_case-Konfiguration verwendet, melden Sie es als Must fix vor der ersten Migration; nachdem Migrationen existieren, melden Sie es als Recommended mit den Migrationskosten.

Go + sqlc

sqlc ist SQL-first: Das Schema stammt aus Migrationsdateien, daher gelten alle obigen Regeln direkt für diese.

  • Richten Sie schema in sqlc.yaml auf das Migrationsverzeichnis aus (goose, golang-migrate, dbmate und atlas-Formate werden unterstützt; Down-Migrationen werden ignoriert). Halten Sie niemals eine separate handgeschriebene Schema-Datei neben Migrationen.
  • Plural-Snake_case-Tabellen ergeben singuläre Go-Strukturen: order_items → OrderItem. Enum order_status → Typ OrderStatus mit Konstanten OrderStatusPending.
  • Verwenden Sie sql_package: pgx/v5. Überschreiben Sie uuid → github.com/google/uuid.UUID und, falls gewünscht, timestamptz → time.Time anstelle der pgtype-Wrapper.
  • Beheben Sie Initialismen mit rename (url: URL, ip: IP) anstatt Spalten umzubenennen.
  • Abfragenamen sind PascalCase Verb + Objekt, mit dem Ergebnis-Typ:
ZweckBeispiel
Eine Zeile-- name: GetUserByEmail :one
Viele Zeilen-- name: ListOrdersByCustomer :many
Einfügen-- name: CreateOrder :one + returning *
Aktualisieren-- name: UpdateOrderStatus :execrows
Löschen-- name: DeleteSession :exec
Bulk-Laden-- name: CreateOrderItems :copyfrom
  • Benennen Sie Parameter mit @name oder sqlc.arg(name) und sqlc.narg(name) für nullable; positionsbasiertes $1 erzeugt Column1-artige Go-Felder.
  • Verwenden Sie sqlc.embed(table) für Joins anstatt Spalten mit Ad-hoc-Aliasen auszuwählen.
  • Verwenden Sie niemals select * in Abfragen, die Schemaänderungen überstehen sollen, außer returning * bei Schreibvorgängen.

Verwandte Skills