# Extrudex

> Filament inventory and print tracking system for CubeCraft Creations.

Extrudex replaces Spoolman with a fully custom solution built for Joshua's 7-printer fleet. It tracks spool stock, per-print material consumption, and cost-of-goods — with a touch-optimized kiosk interface on a Raspberry Pi 5.

---

## Tech Stack

| Layer | Technology |
|---|---|
| Backend | ASP.NET Core Web API (.NET 8) |
| Database | PostgreSQL (snake_case via EF Core) |
| ORM | Entity Framework Core |
| Real-time | SignalR (`PrinterHub`) |
| Printer integration | Moonraker REST/WebSocket (Elegoo) · MQTTnet + TLS (Bambu Lab) |
| Frontend | Angular 17+, Angular Material |
| Deployment | Docker · Docker Compose |

---

## Project Structure

```
Extrudex/
├── backend/
│   ├── Domain/
│   │   ├── Base/                   # BaseEntity, AuditableEntity
│   │   ├── Entities/               # Spool, Printer, PrintJob, FilamentUsage,
│   │   │                           #   AmsUnit, AmsSlot, MaterialBase,
│   │   │                           #   MaterialFinish, MaterialModifier
│   │   ├── Enums/                  # ConnectionType, DataSource, JobStatus,
│   │   │                           #   PrinterStatus, PrinterType, QrResourceType
│   │   └── Interfaces/             # ICostPerPrintService, IFilamentUsageSyncService,
│   │                               #   IMoonrakerClient, IQrCodeService
│   ├── Infrastructure/
│   │   ├── Configuration/          # FilamentUsageSyncOptions
│   │   ├── Data/
│   │   │   ├── Configurations/     # EF Core fluent configs (snake_case)
│   │   │   ├── Migrations/         # EF migrations
│   │   │   ├── Seed/               # SeedData.cs
│   │   │   └── ExtrudexDbContext.cs
│   │   └── Services/               # CostPerPrintService, FilamentUsageSyncService,
│   │                               #   MoonrakerClient, QrCodeService
│   └── API/
│       ├── Controllers/            # Filaments, Spools, Printers, PrintJobs,
│       │                           #   MaterialBases, MaterialFinishes,
│       │                           #   MaterialModifiers, MaterialLookups,
│       │                           #   CostAnalysis, QR
│       ├── DTOs/                   # Request/response shapes per domain
│       ├── Filters/                # FluentValidationFilter
│       ├── Hubs/                   # PrinterHub, IPrinterClient
│       ├── Jobs/                   # FilamentUsageSyncJob (background)
│       ├── Validators/             # FluentValidation validators
│       ├── Program.cs
│       └── appsettings.json
├── frontend/
│   └── src/app/
│       ├── components/             # DashboardSummary, FilamentFilter, FilamentTable
│       ├── models/                 # Filament, Agent model types
│       └── app.routes.ts
├── design/                         # UX specs and mockups (kiosk + mobile)
├── docker-compose.dev.yml
├── deploy.sh
└── README.md
```

---

## Domain Model

### Materials (normalized taxonomy)

| Entity | Description |
|---|---|
| `MaterialBase` | The base material type — PLA, PETG, ABS, ASA, TPU, etc. |
| `MaterialFinish` | Required. Surface finish — Basic (default), Matte, Silk, Sparkle, etc. |
| `MaterialModifier` | Optional. Composite fill — Carbon Fiber, Glass Fiber, Wood, etc. |

**Rules:**
- `MaterialFinish` is required — every spool must have one. Default is `"Basic"`.
- `MaterialModifier` is optional — plain PLA has no modifier.

### Consumption calculation

```
grams_used = mm_extruded × filament_cross_section_area × material_density
```

Grams are always derived, never assumed from printer telemetry directly.

### Printers

| Type | Integration |
|---|---|
| Bambu Lab (×5) | MQTTnet with TLS |
| Elegoo Centauri Carbon | Moonraker REST + WebSocket |
| Elegoo Saturn (resin ×2) | Manual / future |

AMS units and slots are modelled as `AmsUnit` → `AmsSlot[]` → `Spool`.

---

## Key Design Decisions

1. **Spoolman rejected** — Full custom system for data model control and workflow flexibility.
2. **`"Basic"` not `"Standard"`** — Default `MaterialFinish` value is `Basic`.
3. **`MaterialFinish` is required** — No null/optional finish state allowed.
4. **`MaterialModifier` is optional** — Not every spool has a modifier.
5. **Derived consumption** — Grams calculated from mm × density, never assumed.
6. **Push over poll** — SignalR and MQTT preferred over periodic polling.
7. **Snake_case PostgreSQL** — All database identifiers follow this convention via EF Core.

---

## Getting Started

### Prerequisites

- .NET 8 SDK
- Node.js 20+
- Docker + Docker Compose
- PostgreSQL (or use the dev compose stack)

### Backend

```bash
cd backend

# Restore and build
dotnet restore
dotnet build

# Apply migrations
dotnet ef database update

# Run API (dev)
dotnet run --project API
```

API runs at `http://localhost:5000` · Swagger at `http://localhost:5000/swagger`

### Frontend

```bash
cd frontend
npm install
ng serve
```

Frontend runs at `http://localhost:4200`

### Docker (dev stack)

```bash
docker-compose -f docker-compose.dev.yml up
```

---

## Configuration

`backend/appsettings.json` — override in `appsettings.Development.json` or environment variables:

| Key | Default | Description |
|---|---|---|
| `ConnectionStrings:ExtrudexDb` | `Host=localhost;...` | PostgreSQL connection string |
| `FilamentUsageSync:PollingInterval` | `00:05:00` | Sync job interval |
| `FilamentUsageSync:RequestTimeout` | `00:00:30` | Moonraker request timeout |
| `FilamentUsageSync:Enabled` | `true` | Enable/disable background sync |

---

## Real-Time Events

SignalR hub endpoint: `/hubs/printer`

Clients receive `PrinterHub` events for live printer status, job progress, and spool consumption updates.

---

## API Overview

| Route prefix | Resource |
|---|---|
| `/api/filaments` | Filament catalog |
| `/api/spools` | Spool inventory |
| `/api/printers` | Printer registry |
| `/api/print-jobs` | Print job tracking |
| `/api/material-bases` | Material base types |
| `/api/material-finishes` | Material finishes |
| `/api/material-modifiers` | Material modifiers |
| `/api/material-lookups` | Combined material lookup |
| `/api/cost-analysis` | Cost-per-print and COGS |
| `/api/qr` | QR code generation |

Full schema available at `/swagger` when running in dev.

---

## CI

Gitea Actions pipeline (`.gitea/workflows/dev.yml`) runs on every push to `dev`:

- `dotnet build`
- Frontend `ng build`

---

## Branch & PR Rules

- All feature branches target `dev` — **never `main`**
- Branch naming: `agent/<agent>/CUB-N-short-description`
- PR titles: `CUB-N: short description`
- PRs require Otto review before Joshua merges

---

*Built by CubeCraft Creations · Orchestrated by Otto*
