feat: centralized Notion-style taxonomy management in settings

Single persistent option pool per taxonomy (7 fields: offer
categoria/ticket/tipo/obiettivo + catalog fase/offerta/pacchetto),
stored as JSON in the settings table (no DB migration).

- src/lib/taxonomy.ts: pools with lazy seed from in-use values,
  add/remove(cascade)/rename helpers
- Inline creation anywhere registers into the pool (save offer,
  addServiceOption, updateServiceField fase, quickAdd, create macro)
- Deselecting on a row never touches the pool; global delete only
  from settings (cascade-strips tags / nulls columns)
- getOfferFieldOptions + getCatalogFieldOptions read from pools
- Settings: TaxonomyManager (offer + catalog groups), confirm on delete

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 14:24:47 +02:00
parent 320827e13a
commit e80c95f838
11 changed files with 363 additions and 161 deletions
+5 -13
View File
@@ -1,15 +1,11 @@
import { getTargetHourlyRate, getJsonPool, updateSetting, SETTINGS_KEYS } from "@/lib/settings";
import { OfferPoolsSection } from "@/components/admin/impostazioni/OfferPoolsSection";
import { getTargetHourlyRate, updateSetting, SETTINGS_KEYS } from "@/lib/settings";
import { getAllPools } from "@/lib/taxonomy";
import { TaxonomyManager } from "@/components/admin/impostazioni/TaxonomyManager";
export const revalidate = 0;
export default async function ImpostazioniPage() {
const [targetRate, tipoPool, obiettivoPool, categoriaPool] = await Promise.all([
getTargetHourlyRate(),
getJsonPool(SETTINGS_KEYS.OFFER_TIPO_POOL),
getJsonPool(SETTINGS_KEYS.OFFER_OBIETTIVO_POOL),
getJsonPool(SETTINGS_KEYS.OFFER_CATEGORIA_POOL),
]);
const [targetRate, pools] = await Promise.all([getTargetHourlyRate(), getAllPools()]);
async function handleSave(fd: FormData) {
"use server";
@@ -62,11 +58,7 @@ export default async function ImpostazioniPage() {
</form>
</div>
<OfferPoolsSection
tipoPool={tipoPool}
obiettivoPool={obiettivoPool}
categoriaPool={categoriaPool}
/>
<TaxonomyManager pools={pools} />
</div>
</div>
);