@primocaredentgroup/dental-digital-intake
v0.1.1
Published
Convex Component per intake digitale odontoiatrico (scanner intraorali e da banco).
Readme
Convex Component Template
This is a Convex component, ready to be published on npm.
To create your own component:
- Write code in src/component for your component. Component-specific tables, queries, mutations, and actions go here.
- Write code in src/client for the Class that interfaces with the component. This is the bridge your users will access to get information into and out of your component
- Write example usage in example/convex/example.ts.
- Delete the text in this readme until
---and flesh out the README. - Publish to npm with
npm run alphaornpm run release.
To develop your component run a dev process in the example project:
npm i
npm run devnpm run dev will start a file watcher to re-build the component, as well as
the example project backend, which installs and uses the component. Run
npm run dev:frontend to interact with it through a Vite app.
Modify the schema and index files in src/component/ to define your component.
Write a client for using this component in src/client/index.ts.
If you won't be adding frontend code (e.g. React components) to this component you can delete "./react" references in package.json and "src/react/" directory. If you will be adding frontend code, add a peer dependency on React in package.json.
Component Directory structure
.
├── README.md documentation of your component
├── package.json component name, version number, other metadata
├── package-lock.json Components are like libraries, package-lock.json
│ is .gitignored and ignored by consumers.
├── src
│ ├── component/
│ │ ├── _generated/ Files here are generated for the component.
│ │ ├── convex.config.ts Name your component here and use other components
│ │ ├── lib.ts Define functions here and in new files in this directory
│ │ └── schema.ts schema specific to this component
│ ├── client/
│ │ └── index.ts Code that needs to run in the app that uses the
│ │ component. Generally the app interacts directly with
│ │ the component's exposed API (src/component/*).
│ └── react/ Code intended to be used on the frontend goes here.
│ │ Your are free to delete this if this component
│ │ does not provide code.
│ └── index.ts
├── example/ example Convex app that uses this component
│ └── convex/
│ ├── _generated/ Files here are generated for the example app.
│ ├── convex.config.ts Imports and uses this component
│ ├── myFunctions.ts Functions that use the component
│ └── schema.ts Example app schema
└── dist/ Publishing artifacts will be created here.Dental Digital Intake — struttura repository
Monorepo pensato per PrimoCore / PrimoLabCore: backend Convex isolato, pacchetto UI pubblicabile su npm, contratti TypeScript condivisi e un’app Vite + React di esempio.
Cosa c’è in ogni cartella
| Percorso | Rolo |
|----------|------|
| component/ | Solo Convex Component: convex.config.ts, funzioni, schema, _generated. Nessun React. |
| packages/shared | @primocaredentgroup/dental-digital-intake-shared: tipi (HostApp, stati acquisizione, enum, NormalizedManifest), estrazione ZIP lato client sicura (fflate). |
| packages/ui | @primocaredentgroup/dental-digital-intake-ui: componenti React riutilizzabili + bridge (UploadBridge, PipelineBridge, ReviewBridge). Non importa il codegen Convex: l’host fornisce URL/query/mutation tramite props. |
| example/ | App Vite che usa davvero ui e shared e contiene solo il wire Convex (ConnectedAcquisitionDetail, FileDownloadLink, bridge). |
| src/client | Tipi / entry-point npm del componente (ComponentApi) per chi pubblica il pacchetto root @primocaredentgroup/dental-digital-intake. |
Differenza: componente Convex vs pacchetto UI
- Componente Convex (
npm install @primocaredentgroup/dental-digital-intakeo path locale): installi il backend inconvex/conapp.use(dentalDigitalIntake)inconvex.config.ts. Le tabelle e le API vivono nel componente; l’app host espone bridge sottili (comeexample/convex/intake.ts). - Pacchetto UI (
@primocaredentgroup/dental-digital-intake-ui): solo React. Va collegato al tuoConvexReactCliente alle tue query/mutation tramite bridge e props (nessun accoppiamento ai file_generateddella UI).
Peer dependency UI (Three / R3F)
Nel package UI, react e react-dom sono peerDependencies. Anche three è peer. Il package include three-stdlib come dependency (OrbitControls / viewer DentalGeom-style). Il package shared è una dependency normale (tipi + ZIP).
Sviluppo in locale
npm install
# Backend Convex + watcher codegen (da root)
npx convex dev
# In un altro terminale: solo frontend example (Vite)
npm run dev:frontendLa prima volta: npx convex dev dalla root esegue anche il codegen del componente in ./component. Assicurati che packages/shared sia buildato prima del bundler Convex (npm run build:shared o usa npm run build:codegen che lo include).
Comandi utili
| Script | Significato |
|--------|-------------|
| npm run build:shared | Compila @primocaredentgroup/dental-digital-intake-shared (tsup → dist/). |
| npm run build:ui | Compila @primocaredentgroup/dental-digital-intake-ui. |
| npm run build:packages | Entrambi i pacchetti workspace. |
| npm run build:codegen | build:shared + convex codegen --component-dir ./component + build npm root. |
| npm run typecheck | tutti i workspace + example/convex. |
| npm run dev:frontend | Solo Vite dell’example (dental-digital-intake-example). |
Architettura adapter ingestion (FASE 2)
Il dominio intake è diviso tra core neutrale e adapters:
- Il core conosce solo: acquisizioni (
digitalAcquisitions), manifest normalizzato, file scans, validazione, workflow, review e readiness. Non ha logica tipo “ZIP vs 3Shape vs upload manuale” sparsa nei moduli centrali. - Gli adapters traducono sorgenti esterne in
PartialNormalizedManifest, metadata, hint su entità collegate e riferimenti vendor (AdapterExecutionResult). Il core poi consolida, valida, persiste e avvia la pipeline.
Struttura nel component Convex:
component/convex/adapters/
base/ # contratto `IngestionAdapter`, tipi di contesto
manualUpload/ # riusa upload manuale esistente
zipUpload/ # riusa parser ZIP esistente
threeShape/ # mock WS (senza HTTP reale)
itero/ # mock cloud
shared/ # fallback `unknown`
registry.ts # registrazione centrale degli adapter (`getIngestionAdapter`)
lib/
ingestionOrchestrator.ts # sceglie adapter dal registry, sincronizza, import mock, append eventi, crea acquisitionRegistry: nessuno switch (vendor) nei file core fuori dall’implementazione degli adapter — il sistema chiede al registry “adapter per tipo” (manual_upload, zip_upload, three_shape_web_service, itero_cloud, …).
Dati: tabelle ingestionProviders (connessione, sync, capability, credential placeholder/mock, cache casi remoti dopo sync simulato) e ingestionSyncEvents append-only per audit/simulazioni. Sulle acquisizioni: sourceAdapterType, sourceProviderId, externalCaseId / externalPatientId e externalReferences, oggetto JSON opaco (validator Convex v.any()) aggiornato da adapter/host; una copia compare anche nel manifest.normalized (externalReferences) per consultazione stabile.
Come aggiungere un nuovo vendor
- Estendi
IngestionAdapterTypeinpackages/sharede i validator Convex coerenti. - Aggiungi un modulo adapter sotto
component/convex/adapters/<vendor>/che implementaIngestionAdapter. - Registra l’istanza in
adapters/registry.ts. - Opzionale: capability e UI host per quel provider — il core dovrebbe continuare a chiamare solo orchestratore + mutations esposte.
Roadmap integrazione reale (non ancora in scope)
- 3Shape: OAuth verso WS, webhook o polling ordini casi.
- iTero: iTero Cloud REST + token refresh.
- Notifiche push, polling schedulati, import automatico da code/worker dopo sync.
In Example Vite, la vista Provider integrations mostra lista provider, sync simulato, cache “casi remoti” mock e import che crea una DigitalAcquisition collegando riferimenti esterni.
Viewer 3D (DentalGeom-style) e segmentazione (MeshSegNet)
- La UI pack
@primocaredentgroup/dental-digital-intake-uiusa un motore Three.js camera ortografica e luci analoghe al progetto open-source DentalGeom (dipendenzathree-stdlib; niente React Three Fiber nel viewer). - Il pulsante Segmenta denti applica per default una colorazione demo (bande lungo l’asse, non clinica). Per usare il modello MeshSegNet occorre un servizio Python (PyTorch) esterno che esponga i colori per vertice (
Float32Arraylungo (3n) vertici) e collegarlo dalla app host con la propmeshSegmentationBridgesuDigitalAcquisitionDetail.
Example: import UI e stili
import {
DigitalIntakeDashboard,
DigitalAcquisitionDetail,
} from "@primocaredentgroup/dental-digital-intake-ui";
import "@primocaredentgroup/dental-digital-intake-ui/styles/intake.css";Tipi condivisi:
import type { NormalizedManifest } from "@primocaredentgroup/dental-digital-intake-shared";Installazione componente backend (host)
Vedi example/convex/convex.config.ts:
import dentalDigitalIntake from "@primocaredentgroup/dental-digital-intake/convex.config.js";
// oppure path file: ../../component/convex.config.jsPubblicazione
- Pacchetto root (
@primocaredentgroup/dental-digital-intake): Convex component + client types (files:dist,src,component). @primocaredentgroup/dental-digital-intake-uie@primocaredentgroup/dental-digital-intake-shared: pubblicati come workspace npm (stesso scope@primocaredentgroup). Ordine di pubblicazione: shared → ui → root (la UI dipende dalla shared; il root dipende dalla shared).
Per dettagli release, vedi PUBLISHING.md.
