From 603872ff76243b0fab9b8ece1f365f19761f1296 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Fri, 17 Jul 2026 20:56:41 -0400 Subject: [PATCH] Add Copilot custom instructions Repo-level instructions so GitHub Copilot follows the LOCKED naming rules (lowercase concatenated DB columns, allowed-acronym list, banned shorthand), the ASCII-only style policy, and the plugin/migration/contract architecture. Without this Copilot suggests snake_case columns, em-dashes, and db.create_all(), which the naming hook and CI then reject. Distilled from CONTRIBUTING.md; that file stays the authority. --- .github/copilot-instructions.md | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..fefd16a --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,87 @@ +# Copilot instructions for shopdb-flask + +Follow these when suggesting code. They are enforced by a naming/style hook and +by CI (`.github/workflows/ci.yml`) - suggestions that break them fail the build. +`CONTRIBUTING.md` is the full authority; this is the short version. + +## Naming (LOCKED - the hook rejects violations) + +- **DB tables**: lowercase, concatenated, plural. No underscores, no dashes. + `machines`, `networkdevices`, `businessunits` - NOT `machine_types`, `BusinessUnits`. +- **DB columns**: lowercase, concatenated, singular. No underscores. + `machineid`, `lastzabbixsync`, `isactive` - NOT `machine_id`, `last_zabbix_sync`. +- **Foreign keys**: referenced table (singular) + `id`: `locationid`, `vendorid`. +- **Booleans**: `is`/`has` prefix: `isactive`, `isshopfloor`. +- **Index names**: `idx__` (underscores allowed here only). + +### Python + +- A variable, attribute, function, or dict key that holds a DB value MUST match + the column name exactly - do NOT convert to snake_case. + Column `machineid` -> `Machine.machineid`, `{"machineid": 1}`, local `machineid`. +- Pure code that does NOT mirror a DB field uses normal snake_case (PEP 8): + `loop_count`, `current_user`, `validate_input()`. +- Classes: PascalCase, spelled out (`NetworkDevice`, `AssetType`). + +### JavaScript / Vue + +- A JS variable holding an API field value matches the API key exactly - do NOT + camelCase it. API `{"machineid": 1}` -> `response.machineid`, never `machineId`. +- Components: PascalCase (`AssetDetail.vue`). CSS classes: lowercase-with-dashes. + +### API + +- Endpoints: lowercase plural nouns, no underscores/dashes: `/api/networkdevices`. +- Query params + response keys match column names: `?locationid=5`, + `{"machineid": 1, "lastzabbixsync": "..."}`. + +### Allowed acronyms only + +Universal: id url api http https json jwt sql os ip dns csv pdf cors ttl uuid +html css orm. Domain: cmm cnc pc usb vnc winrm ssh ssl tls tcp udp smtp ldap +vlan sso dnc focas clm mtconnect. Anything else: spell it out. + +### Banned shorthand + +Never use `cfg ctx mgr req res env util helper` or `db` as a standalone variable +name. Spell out: `config context manager request response environment utilities`. +`_bp` is fine only as a suffix with a meaningful prefix (`printers_bp`). + +## Style (ASCII only) + +- NO emojis anywhere - code, comments, strings, UI. +- NO em-dashes, en-dashes, Unicode arrows, or smart quotes. Plain ASCII only. +- Comments default to NONE. Add one only when the WHY is non-obvious; keep inline + `#`/`//` comments terse. Docstrings stay normal English. +- Dark theme is the default; keep UI functional and professional. + +## Architecture (do not violate) + +- **Plugins are the product.** Plugin code lives in `plugins//{models,api,services,schemas}/` + with a `manifest.json` (single source of truth: name, version, dependencies, + api_prefix) and a `BasePlugin` subclass in `plugin.py`. +- **Plugins never import core internals.** Use the contract surface `shopdb.api` + (e.g. `from shopdb.api import db, Asset, success_response`). Adding to that + surface is a contract-version bump + a `docs/PLUGIN-HOOKS` update in the same PR. +- **Migrations, never `db.create_all()`.** The core Alembic chain is in + `migrations/versions/`; each plugin owns its own chain under + `plugins//migrations/`. New schema = a new migration with an idempotent + guard and a real downgrade. Migrations must run clean on strict MySQL 8. +- **Asset model is the platform contract.** Physical things are an `Asset` plus a + plugin subtype row linked by `assetid` (FK, `ON DELETE CASCADE`). Consumables + with quantities are standalone tables, not assets. +- **Ledger pattern**: a cached `quantityonhand` moves in the SAME commit as the + signed transaction row it reflects. + +## Before you finish a change + +Run the three gates (CI runs the same): + +``` +python -m pytest tests/ -q +cd frontend && npx vitest run && npm run build && cd .. +bash scripts/check-naming-and-style.sh +``` + +Commits: short present-tense subject, body says WHY. No AI/tool attribution in +commit messages, code comments, or docs.