Files
upstream-mirror 93ecc1a6f8
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
snapshot of https://github.com/marmelab/atomic-crm.git (main, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:48:50 +05:00

27 lines
7.5 KiB
Markdown

# Deleting `companies`
A **spine/link** resource: it owns the `companies` table *and* is a `company_id` link on **both** `contacts` and `deals`, its `companies_summary` view aggregates `nb_contacts`/`nb_deals`, and it adds a **denormalized `company_name`** to the `Contact` type. So it fans out far wider than its folder (≈50 frontend files + backend).
## Confirm cascade scope first
**Remove `company_id` fully** — drop the column from the `Contact`/`Deal` types, the CSV import/export, `mergeContacts`, the fakerest generators, and i18n. This full removal is what makes the deletion large.
## Frontend specifics
- **Activity log** — a dedicated `company.created` branch (delete `ActivityLogCompanyCreated.tsx` outright + the branch in `ActivityLogIterator.tsx` + `COMPANY_CREATED` in `consts.ts`/`types.ts`) **and** a `"company"` member in the context union. Narrowing the union turns the `=== "company"` checks in `ActivityLogContactCreated`/`ActivityLogContactNoteCreated`/`ActivityLogDealCreated`/`ActivityLogDealNoteCreated` into type errors — prune those branches (the `company_id` "to/at `<company>`" ReferenceField + the `CompanyAvatar` in the deal-note header). `ActivityLog.tsx` has a `companyId` prop + `company_id` filter; `providers/commons/activity.ts` has a `getNewCompanies` fetcher + `companyId` param.
- **`company_id` link** on contacts (`ContactInputs` selector, `ContactShow`/`ContactListContent` avatar+name, the exporter's `fetchRelatedRecords` + the `company` CSV column, `contactModel.ts`'s vCard `ORG:` line, `ExportVCardButton.tsx`) and on deals (`DealInputs` required selector, `DealCard`/`DealShow`/`DealEdit` avatar, `DealList` filter), plus the note-header `CompanyAvatar` in `notes/Note.tsx`.
- **Denormalized `company_name`** (from `companies_summary`'s `c.name as company_name`) — read in `ContactOption.tsx`, `deals/ContactList.tsx`, `dashboard/HotContacts.tsx`, and the `position_at_company` rendering. **Invisible to a `\bcompan(y|ies)\b` grep** — grep `company_name` separately.
- **`companySectors` config prop** — see SKILL.md "Shapes a resource takes" for the standard config-prop locations. Companies-specific: the `<Card>` holds only a `companySectors` `ArrayInput` (no `validateItemsInUse`), and it's also read in `useImportFromJson.ts` to validate an imported `sector`.
- **Providers** — supabase `getList`/`getOne` route `companies -> companies_summary` (drop both); the contacts FTS list adds `company_name`. FakeRest has `processCompanyLogo` (favicon), `fetchAndUpdateCompanyData` (stamps `company_name` onto contacts, called from the contacts `beforeCreate`/`beforeUpdate`), `updateCompany` (maintains `nb_contacts`/`nb_deals` from the contacts/deals `afterCreate`/`afterDelete`), the whole `companies` callback block, the `companies` arm of the `sales` `beforeDelete` reassignment, and the `getActivityLog(dataProvider, companyId, salesId)` call (drop the `companyId` arg + the `companyId`/`company_id` filter plumbing in `providers/commons/activity.ts`). Delete `providers/commons/getCompanyAvatar.ts` + test.
- **FakeRest generators are deeply company-coupled** — `dataGenerator/companies.ts` deleted outright + dropped from `index.ts` (mind the order: sales → tags → [companies] → contacts → …) and `types.ts` (`Db.companies`). `contacts.ts` *picks a company* to derive `company_id`/`company_name`/`sales_id`/`first_seen` (+ a per-company `maxContacts` cap), and `deals.ts` *picks a company* then filters contacts by `company_id` for `contact_ids` — rewrite both to pick a random `db.sales` + `randomDate()` (and random contacts for deals). The `faker` `company` namespace import is unrelated — keep it.
- **JSON importer** treats `companies` as a top-level type (`importCompany`, `$.companies.*`, `CompanyImport`/`isCompany`, `mapSizeToCategory`, `companySectors` validation, stats/idsMaps keys) + the `company_id` mapping on imported contacts. Mirror in `ImportPage.tsx` + `import-sample.json`. CSV importer (`useContactImport.tsx`) has a `getCompanies` cache + a `company` column → `company_id`.
- **Mislabeled i18n:** `deals/OnlyMineInput.tsx` uses `resources.companies.filters.only_mine` ("Only companies I manage") even though it filters deals — re-point it to a deals key, don't delete the input.
## Backend
- Drop the `companies` table + `companies_id_seq` grant + RLS-enable line + its 4 policies + table grants. Drop `company_id` on **both** `contacts` and `deals` (FKs `contacts_company_id_fkey`/`deals_company_id_fkey` + indexes `contacts_company_id_idx`/`deals_company_id_idx`). Drop the `companies_summary` view (+ grant). Update `contacts_summary`: drop `co.company_id`, the `c.name as company_name` column, the `left join public.companies`, and narrow the `group by` to `co.id`.
- `activity_log` view carries the company pattern (a `company` column on **every** branch **and** a dedicated `company.created` branch) — remove the `company` + `company_id` columns from all branches (the `contactNote`/`dealNote` branches only joined a table to fetch `company_id`, so drop those now-unused joins) and delete the branch.
- Drop the company-only function `handle_company_saved` (favicon-from-website trigger) + its `company_saved` trigger + grant, and the `set_company_sales_id_trigger`. Drop the `company_id` line from `merge_contacts`. **Orphan subtlety:** `handle_company_saved` calls `get_domain_favicon`, but so does `get_avatar_for_email` (contact avatars) — so it is **not** orphaned; **keep** `get_domain_favicon` and the `favicons_excluded_domains` table.
- **Edge functions:** unlike `contacts` (delete the whole function), **keep** `postmark/` and surgically remove the company bits — it auto-creates a company from the sender's email domain (`getOrCreateCompanyFromDomain` in `addNoteToContact.ts`, `extractCompanyName` in `extractMailContactData.ts`) and links the new contact via `company_id`. Delete `getOrCreateCompanyFromDomain`, drop the `domain`/`companyName`/`website` params threaded through `getOrCreateContactFromEmailInfo`/`addNoteToContact`/`index.ts`, drop `company_id` from the contact insert, remove `extractCompanyName` + the `companyName`/`website` output fields + the now-unused `tldts` import from `extractMailContactData.ts`, and update the postmark tests (`addNoteToContact.test.ts`, `extractMailContactData.test.ts`). **Flag that auto-company-creation on inbound email is gone but contact+note creation still works.** Elsewhere: `_shared/db.ts` declares `company_id` on **both** `ContactsTable` and `DealsTable` (no dedicated `CompaniesTable`); `merge_contacts/index.ts` merges `company_id` in `mergeContactData`; `mcp/index.ts` + `mcp/validateSql.test.ts` mention `companies`/`companies_summary` in prompt examples/fixtures (swap for a surviving table). No `config.toml` block changes are needed (postmark + merge_contacts both survive).
## grep — benign matches to leave
- The `faker` `company` namespace import in `dataGenerator/contacts.ts` (used for `bsAdjective()` titles), the `reference="companies"`/`source="company_id"` JSDoc examples in the **mutable** `admin/reference-input.tsx`/`admin/list.tsx`, and email-domain fixtures like `@company.com`/`original.recipient@company.com` in test bodies.
- Dead i18n keys (`resources.companies.*`, `position_at_company`, `you_added_company`/`at_company`, `crm.settings.companies.*`) — flag, don't force (both catalogs or neither). `test-data/contacts.csv` keeps `company_id`/`company_name`/`company` columns — the importer ignores them, so leaving them is harmless; dropping means editing the header **and** all ~500 rows — flag it.