Files
cad-data-router/sop.md

340 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SOP CadRoute MVP
## Obiettivo
Realizzare un'app desktop (.exe) che:
- accetti una cartella o uno ZIP
- legga file CAD (.prt .asm .dwr)
- analizzi nome file ed estensione
- applichi regole di routing
- copi i file verso destinazioni configurate (anche share di rete)
Tecnologie:
- Node.js
- Electron
- unzipper
- fs-extra
---
## 1. Prerequisiti
Installare:
- Node.js LTS
- Git
- Visual Studio Code / VSCodium
Verifica:
```
node -v
npm -v
```
---
## 2. Creazione progetto
```
mkdir cadroute
cd cadroute
npm init -y
```
Installare dipendenze:
```
npm install electron unzipper fs-extra
npm install electron-builder --save-dev
```
---
## 3. Struttura progetto
```
cadroute
├── package.json
├── main.js
├── preload.js
├── renderer
│ ├── index.html
│ └── renderer.js
├── services
│ ├── router.js
│ ├── zipProcessor.js
│ └── folderProcessor.js
```
---
## 4. Configurazione runtime
La destinazione viene gestita in memoria in `main.js` e modificata dalla UI durante l'esecuzione.
---
## 5. Motore di routing
`services/router.js`
```
const path = require("path")
function findDestination(filename, config){
const ext = path.extname(filename).slice(1)
for(const rule of config.rules){
if(rule.ext !== ext)
continue
if(!rule.pattern)
return rule.destination
const regex = new RegExp(rule.pattern)
if(regex.test(filename))
return rule.destination
}
return null
}
module.exports = { findDestination }
```
---
## 7. Processare una cartella
`services/folderProcessor.js`
```
const fs = require("fs-extra")
const path = require("path")
const { findDestination } = require("./router")
async function processFolder(folder, config){
const files = await fs.readdir(folder)
for(const file of files){
const src = path.join(folder,file)
const destDir = findDestination(file, config)
if(!destDir) continue
const dest = path.join(destDir,file)
await fs.copy(src,dest)
}
}
module.exports = { processFolder }
```
---
## 8. Processare ZIP
`services/zipProcessor.js`
```
const unzipper = require("unzipper")
const fs = require("fs-extra")
const path = require("path")
const { findDestination } = require("./router")
async function processZip(zipPath, config){
const stream = fs.createReadStream(zipPath)
.pipe(unzipper.Parse())
for await (const entry of stream){
const file = entry.path
const destDir = findDestination(file, config)
if(!destDir){
entry.autodrain()
continue
}
const dest = path.join(destDir,path.basename(file))
entry.pipe(fs.createWriteStream(dest))
}
}
module.exports = { processZip }
```
---
## 9. Main Electron
`main.js`
```
const { app, BrowserWindow, dialog, ipcMain } = require("electron")
const path = require("path")
const { processFolder } = require("./services/folderProcessor")
const { processZip } = require("./services/zipProcessor")
const CAD_EXTENSIONS = ["prt", "asm", "dwr"]
const DEFAULT_DESTINATION = "./output/cad"
let config = {
destination: DEFAULT_DESTINATION,
rules: CAD_EXTENSIONS.map((ext) => ({ ext, destination: DEFAULT_DESTINATION }))
}
function createWindow(){
const win = new BrowserWindow({
width:800,
height:600,
webPreferences:{
preload: path.join(__dirname,"preload.js")
}
})
win.loadFile("renderer/index.html")
}
app.whenReady().then(createWindow)
ipcMain.handle("select-folder", async () => {
const result = await dialog.showOpenDialog({
properties:["openDirectory"]
})
if(result.canceled) return
await processFolder(result.filePaths[0], config)
})
ipcMain.handle("select-zip", async () => {
const result = await dialog.showOpenDialog({
filters:[{ name:"Zip", extensions:["zip"] }]
})
if(result.canceled) return
await processZip(result.filePaths[0], config)
})
```
---
## 10. Preload
`preload.js`
```
const { contextBridge, ipcRenderer } = require("electron")
contextBridge.exposeInMainWorld("api", {
selectFolder: () => ipcRenderer.invoke("select-folder"),
selectZip: () => ipcRenderer.invoke("select-zip")
})
```
---
## 11. UI minima
`renderer/index.html`
```
<h2>CadRoute</h2>
<button onclick="window.api.selectFolder()">
Process Folder
</button>
<button onclick="window.api.selectZip()">
Process ZIP
</button>
```
---
## 12. Avvio applicazione
Nel package.json aggiungere:
```
"scripts": {
"start": "electron ."
}
```
Avviare:
```
npm start
```
---
## 13. Build .exe
Aggiungere nel package.json:
```
"build": {
"appId": "com.cadroute",
"win": {
"target": "nsis"
}
}
```
Build:
```
npx electron-builder
```
Output:
```
dist/
CadRoute Setup.exe
```
---
## MVP completato quando
- l'app si avvia
- si seleziona ZIP o cartella
- i file .prt .asm .dwr vengono analizzati
- i file vengono copiati nelle destinazioni configurate
---
## Migliorie future
- progress bar
- drag and drop ZIP
- modifica regole avanzate da UI
- logging operazioni
- parallelismo file
- watch folder automatico