Files
innovatieplatform/database/seeders/DatabaseSeeder.php
znetsixe 6711cd01a3 Replace demo data with 2026 R&D planning, fix zoom and dimension-aware creation
Seeder: Replace 12 demo projects with 6 real 2026 projects from Planning PPTX:
- BRIDGE (Pilot Klundert), CRISP (Compressor Aanbesteding), WISE (Monsternamekast),
  Gemaal 3.0, Afvlakkingsregeling, Structuur & Borging
- 4 strategic themes: Architectuur, Productiewaardig, Lab, Governance
- Real team members, commitments, documents, and dependencies

MetroCanvas: Fix zoom-out scaling
- Wider transition range (0.6→0.25 instead of 0.5→0.1) for smoother feel
- Animated zoom reset on dimension commit (400ms ease) instead of jarring snap
- Guard against re-entry during transitions with isCommitting flag
- Expose dimension metadata (parentEntityType/Id/Name) for parent components

FloatingActions: Dimension-aware creation
- Shows "Nieuw commitment/document" when inside a project dimension
- Shows "Nieuw project/thema" at root level
- Receives depth and parentEntityType props from MetroMap

MetroMap: Wire dimension tracking
- Tracks canvasDepth/canvasDimension from MetroCanvas dimension-change events
- Updates breadcrumb for both page-level and canvas-level navigation
- Passes dimension context to FloatingActions and CommitmentForm

MapDataService: Add parent metadata to buildProjectChildren output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 08:50:51 +02:00

515 lines
25 KiB
PHP
Raw 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.
<?php
namespace Database\Seeders;
use App\Enums\CommitmentStatus;
use App\Enums\FaseStatus;
use App\Enums\FaseType;
use App\Enums\Prioriteit;
use App\Enums\ProjectRol;
use App\Enums\ProjectStatus;
use App\Enums\SpeerpuntStatus;
use App\Models\Afhankelijkheid;
use App\Models\Commitment;
use App\Models\Document;
use App\Models\Fase;
use App\Models\Project;
use App\Models\Role;
use App\Models\Speerpunt;
use App\Models\Thema;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* Planning 2026 R&D Lab Waterschap Brabantse Delta
* Source: Planning 2026.pptx
*/
public function run(): void
{
// ──────────────────────────────────────────────────────────────
// 1. System roles
// ──────────────────────────────────────────────────────────────
$roleAdmin = Role::create([
'naam' => 'admin',
'beschrijving' => 'Volledige toegang tot het platform',
'permissies' => ['*'],
]);
$roleProjectOwner = Role::create([
'naam' => 'project_owner',
'beschrijving' => 'Kan projecten beheren en bewerken',
'permissies' => ['projects.manage', 'commitments.manage', 'documents.manage'],
]);
$roleTeamMember = Role::create([
'naam' => 'team_member',
'beschrijving' => 'Kan bijdragen aan toegewezen projecten',
'permissies' => ['projects.view', 'commitments.edit', 'documents.upload'],
]);
Role::create([
'naam' => 'viewer',
'beschrijving' => 'Alleen-lezen toegang',
'permissies' => ['projects.view', 'documents.view'],
]);
// ──────────────────────────────────────────────────────────────
// 2. Users (R&D team)
// ──────────────────────────────────────────────────────────────
$admin = User::create([
'name' => 'Admin',
'email' => 'admin@innovatieplatform.nl',
'password' => Hash::make('password'),
'functie' => 'Platform Beheerder',
'afdeling' => 'R&D Lab',
'email_verified_at' => now(),
]);
$admin->roles()->attach($roleAdmin);
$rene = User::create([
'name' => 'Rene de Ren',
'email' => 'rene@wbd-rd.nl',
'password' => Hash::make('password'),
'functie' => 'R&D Engineer / Teamlead',
'afdeling' => 'R&D Lab',
'email_verified_at' => now(),
]);
$rene->roles()->attach($roleProjectOwner);
$pim = User::create([
'name' => 'Pim Moerman',
'email' => 'p.moerman@wbd-rd.nl',
'password' => Hash::make('password'),
'functie' => 'Technisch Adviseur OT/IT',
'afdeling' => 'R&D Lab',
'email_verified_at' => now(),
]);
$pim->roles()->attach($roleTeamMember);
$sjoerd = User::create([
'name' => 'Sjoerd Fijnje',
'email' => 's.fijnje@wbd-rd.nl',
'password' => Hash::make('password'),
'functie' => 'Werktuigbouwkundige / Elektro',
'afdeling' => 'R&D Lab',
'email_verified_at' => now(),
]);
$sjoerd->roles()->attach($roleTeamMember);
// ──────────────────────────────────────────────────────────────
// 3. Themas 2026 strategic themes
//
// Kaders: geen nieuwe ML-modellen, geen nieuwe digital twins,
// focus op werkend krijgen, architectuur aantonen, overdragen.
// ──────────────────────────────────────────────────────────────
$themaArchitectuur = Thema::create([
'naam' => 'Architectuur & Veiligheid',
'beschrijving' => 'Aantonen dat de EDGE-laag architectuur veilig, betrouwbaar en schaalbaar is. OT/IT-scheiding, Siemens-koppeling, CI/CD implementatie.',
'prioriteit' => Prioriteit::Hoog,
'periode_start' => '2026-01-01',
'periode_eind' => '2026-12-31',
]);
$themaProductie = Thema::create([
'naam' => 'Productiewaardig Maken',
'beschrijving' => 'Bestaande innovaties werkend, overdraagbaar en schaalbaar maken. Begeleiding van aanbestedingen en overdracht naar Bouwen/Beheer.',
'prioriteit' => Prioriteit::Hoog,
'periode_start' => '2026-01-01',
'periode_eind' => '2026-12-31',
]);
$themaLab = Thema::create([
'naam' => 'Lab & Prototyping',
'beschrijving' => 'Fysieke opstellingen valideren, uitbreiden en koppelen tot een realistische testomgeving voor afvlakkingsregelingen.',
'prioriteit' => Prioriteit::Midden,
'periode_start' => '2026-01-01',
'periode_eind' => '2026-12-31',
]);
$themaGovernance = Thema::create([
'naam' => 'Governance & Teamborging',
'beschrijving' => 'R&D minder persoonsafhankelijk maken. Projectstructuur, documentatie, besluitvorming en rolafbakening vastleggen.',
'prioriteit' => Prioriteit::Midden,
'periode_start' => '2026-01-01',
'periode_eind' => '2026-12-31',
]);
// ──────────────────────────────────────────────────────────────
// 4. Speerpunten (2 per thema)
// ──────────────────────────────────────────────────────────────
// Architectuur & Veiligheid
$spEdge = Speerpunt::create([
'thema_id' => $themaArchitectuur->id,
'naam' => 'EDGE-laag & OT/IT-scheiding',
'beschrijving' => 'Implementatie en validatie van de EDGE-architectuur met beveiligde OT/IT-scheiding op pilotlocatie.',
'eigenaar_id' => $rene->id,
'status' => SpeerpuntStatus::Actief,
]);
$spCicd = Speerpunt::create([
'thema_id' => $themaArchitectuur->id,
'naam' => 'CI/CD & DevOps R&D-stack',
'beschrijving' => 'Continuous Integration en Deployment implementeren in de R&D-stack voor maximale efficiëntie en herhaalbaarheid.',
'eigenaar_id' => $rene->id,
'status' => SpeerpuntStatus::Concept,
]);
// Productiewaardig Maken
$spOverdracht = Speerpunt::create([
'thema_id' => $themaProductie->id,
'naam' => 'Overdracht naar Bouwen/Beheer',
'beschrijving' => 'Innovaties begeleiden van R&D naar productie: documentatie, oplevering, kennisoverdracht.',
'eigenaar_id' => $rene->id,
'status' => SpeerpuntStatus::Actief,
]);
$spAanbesteding = Speerpunt::create([
'thema_id' => $themaProductie->id,
'naam' => 'Aanbesteding & TCO-toetsing',
'beschrijving' => 'Technische toetsing van aanbestedingen op prestatie-eisen, energie-efficiëntie en inpasbaarheid.',
'eigenaar_id' => $pim->id,
'status' => SpeerpuntStatus::Actief,
]);
// Lab & Prototyping
$spDtValidatie = Speerpunt::create([
'thema_id' => $themaLab->id,
'naam' => 'Digital Twin Validatie',
'beschrijving' => 'Valideren van 2025-ontwikkelingen (Measurement, Rotating Machine, Aeration Tank, MGC, Diffuser) op het fysieke prototype.',
'eigenaar_id' => $rene->id,
'status' => SpeerpuntStatus::Actief,
]);
$spGemalenketen = Speerpunt::create([
'thema_id' => $themaLab->id,
'naam' => 'Gemalenketen Testomgeving',
'beschrijving' => 'Realiseren van een volledige gemalenketen in het lab voor experimentele afvlakkingsregelingen.',
'eigenaar_id' => $sjoerd->id,
'status' => SpeerpuntStatus::Concept,
]);
// Governance & Teamborging
$spProjectstructuur = Speerpunt::create([
'thema_id' => $themaGovernance->id,
'naam' => 'Projectstructuur & Documentatie',
'beschrijving' => 'Afspraken vastleggen over projectstructuur, documentatie, besluitvorming en beleid.',
'eigenaar_id' => $rene->id,
'status' => SpeerpuntStatus::Actief,
]);
$spRolafbakening = Speerpunt::create([
'thema_id' => $themaGovernance->id,
'naam' => 'Rolafbakening R&D ↔ Organisatie',
'beschrijving' => 'Verduidelijken wat R&D wel en niet doet. Afbakening richting Beheer, Bouwen, ICT en Datalab.',
'eigenaar_id' => $rene->id,
'status' => SpeerpuntStatus::Concept,
]);
// ──────────────────────────────────────────────────────────────
// 5. Projects 2026 planning (6 projects from the presentation)
// ──────────────────────────────────────────────────────────────
// --- B.R.I.D.G.E (Bidirectional Real-time Interface for Data & Grid Exchange) ---
$bridge = $this->createProject([
'speerpunt_id' => $spEdge->id,
'naam' => 'B.R.I.D.G.E Pilot Klundert',
'beschrijving' => 'Aantonen dat de nieuwe EDGE-laag veilig en betrouwbaar assets kan uitlezen en aansturen, en correct kan koppelen met Siemens-omgevingen. Implementatie Ubuntu LTS, Node-RED orkestratie, OPC UA communicatie met Siemens PLC (T-serie).',
'eigenaar_id' => $rene->id,
'status' => ProjectStatus::Pilot,
'prioriteit' => Prioriteit::Hoog,
'startdatum' => '2026-01-15',
'streef_einddatum' => '2026-09-30',
], [FaseType::Signaal, FaseType::Verkenning, FaseType::Concept, FaseType::Experiment, FaseType::Pilot]);
// --- C.R.I.S.P (Compressor Replacement for Immediate System Performance) ---
$crisp = $this->createProject([
'speerpunt_id' => $spAanbesteding->id,
'naam' => 'C.R.I.S.P Compressor Aanbesteding',
'beschrijving' => 'Technische toetsing van aanbestedingsmethodiek voor compressorvervanging Nieuwveer. Prestatie-eisen, energie-efficiëntie, inpasbaarheid in procesautomatisering. R&D als inhoudelijke sparringpartner voor Bouwen.',
'eigenaar_id' => $pim->id,
'status' => ProjectStatus::Verkenning,
'prioriteit' => Prioriteit::Hoog,
'startdatum' => '2026-02-01',
'streef_einddatum' => '2026-08-31',
], [FaseType::Signaal, FaseType::Verkenning]);
// --- W.I.S.E (Weather and Influent Sampling Engine) ---
$wise = $this->createProject([
'speerpunt_id' => $spOverdracht->id,
'naam' => 'W.I.S.E Monsternamekast Overdracht',
'beschrijving' => 'Overdracht monsternamekast naar Bouwen. Opleveren Node-RED flows, documentatie, afbakening R&D vs beheer. Samenwerking met Datalab (data & integratie voorspellend model) en Beheer/Operatie.',
'eigenaar_id' => $rene->id,
'status' => ProjectStatus::OverdrachtBouwen,
'prioriteit' => Prioriteit::Hoog,
'startdatum' => '2025-06-01',
'streef_einddatum' => '2026-06-30',
], [FaseType::Signaal, FaseType::Verkenning, FaseType::Concept, FaseType::Experiment, FaseType::Pilot, FaseType::Besluitvorming, FaseType::OverdrachtBouwen]);
// --- Gemaal 3.0 Prototype Validatie ---
$gemaal = $this->createProject([
'speerpunt_id' => $spDtValidatie->id,
'naam' => 'Gemaal 3.0 Prototype Validatie',
'beschrijving' => 'Valideren dat het recent gebouwde prototype functioneel correct is. Testen van alle elektrische aansluitingen, I/O-functionaliteit en randapparatuur. Go/no-go voor verdere uitrol naar 2 kopieën.',
'eigenaar_id' => $sjoerd->id,
'status' => ProjectStatus::Experiment,
'prioriteit' => Prioriteit::Midden,
'startdatum' => '2026-03-01',
'streef_einddatum' => '2026-07-31',
], [FaseType::Signaal, FaseType::Verkenning, FaseType::Concept, FaseType::Experiment]);
// --- Afvlakkingsregeling Lab Gemalenketen ---
$afvlak = $this->createProject([
'speerpunt_id' => $spGemalenketen->id,
'naam' => 'Afvlakkingsregeling Lab Keten',
'beschrijving' => 'Nabootsen van een volledige gemalenketen in het lab, klaarstomen voor afvlakkingsregeling. Realiseren 2 extra opstellingen, koppelen tot keten, basissoftware testen op ketengedrag.',
'eigenaar_id' => $sjoerd->id,
'status' => ProjectStatus::Concept,
'prioriteit' => Prioriteit::Midden,
'startdatum' => '2026-06-01',
'streef_einddatum' => '2026-12-31',
], [FaseType::Signaal, FaseType::Verkenning, FaseType::Concept]);
// --- Structuur & Borging R&D-team ---
$governance = $this->createProject([
'speerpunt_id' => $spProjectstructuur->id,
'naam' => 'Structuur & Borging R&D',
'beschrijving' => 'R&D minder persoonsafhankelijk en beter voorspelbaar maken. Afspraken over projectstructuur, documentatie, besluitvorming, beleid. Inrichten ICT in Bouvigne voor R&D en Datanetwerkteam.',
'eigenaar_id' => $rene->id,
'status' => ProjectStatus::Verkenning,
'prioriteit' => Prioriteit::Midden,
'startdatum' => '2026-01-01',
'streef_einddatum' => '2026-12-31',
], [FaseType::Signaal, FaseType::Verkenning]);
// ──────────────────────────────────────────────────────────────
// 6. Assign team members
// ──────────────────────────────────────────────────────────────
$bridge->teamleden()->attach($pim->id, ['rol' => ProjectRol::Lid->value]);
$bridge->teamleden()->attach($sjoerd->id, ['rol' => ProjectRol::Lid->value]);
$crisp->teamleden()->attach($rene->id, ['rol' => ProjectRol::Reviewer->value]);
$wise->teamleden()->attach($pim->id, ['rol' => ProjectRol::Lid->value]);
$gemaal->teamleden()->attach($rene->id, ['rol' => ProjectRol::Reviewer->value]);
$afvlak->teamleden()->attach($rene->id, ['rol' => ProjectRol::Reviewer->value]);
$governance->teamleden()->attach($pim->id, ['rol' => ProjectRol::Lid->value]);
$governance->teamleden()->attach($sjoerd->id, ['rol' => ProjectRol::Lid->value]);
// ──────────────────────────────────────────────────────────────
// 7. Commitments
// ──────────────────────────────────────────────────────────────
// BRIDGE
Commitment::create([
'project_id' => $bridge->id,
'beschrijving' => 'Architectuur validatiedocument opleveren conform stackKlundertPilot.pdf',
'eigenaar_id' => $rene->id,
'deadline' => '2026-04-30',
'status' => CommitmentStatus::InUitvoering,
'bron' => 'Planning 2026 slide 3',
]);
Commitment::create([
'project_id' => $bridge->id,
'beschrijving' => 'OT/IT beveiligingsassessment en scheidingsrapport',
'eigenaar_id' => $pim->id,
'deadline' => '2026-06-30',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 3',
]);
Commitment::create([
'project_id' => $bridge->id,
'beschrijving' => 'Beslisdocument voor opschaling EDGE-laag naar andere locaties',
'eigenaar_id' => $rene->id,
'deadline' => '2026-09-30',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 3',
]);
// CRISP
Commitment::create([
'project_id' => $crisp->id,
'beschrijving' => 'TCO-onderbouwde aanbestedingsdocumenten technisch getoetst vóór marktgang',
'eigenaar_id' => $pim->id,
'deadline' => '2026-05-31',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 4',
]);
// WISE
Commitment::create([
'project_id' => $wise->id,
'beschrijving' => 'Node-RED flows opleveren aan Bouwen / uitvoerende partij',
'eigenaar_id' => $rene->id,
'deadline' => '2026-03-31',
'status' => CommitmentStatus::InUitvoering,
'bron' => 'Planning 2026 slide 5',
]);
Commitment::create([
'project_id' => $wise->id,
'beschrijving' => 'Overdracht- en documentatiepakket compleet (afbakening R&D vs beheer)',
'eigenaar_id' => $rene->id,
'deadline' => '2026-06-30',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 5',
]);
// Gemaal 3.0
Commitment::create([
'project_id' => $gemaal->id,
'beschrijving' => 'Go/no-go besluit voor uitrol naar 2 kopieën op basis van testresultaten',
'eigenaar_id' => $sjoerd->id,
'deadline' => '2026-06-30',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 6',
]);
Commitment::create([
'project_id' => $gemaal->id,
'beschrijving' => 'Overzicht software/hardware functionaliteiten en validatie digital twins',
'eigenaar_id' => $rene->id,
'deadline' => '2026-07-31',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 6',
]);
// Afvlakkingsregeling
Commitment::create([
'project_id' => $afvlak->id,
'beschrijving' => '2 extra opstellingen gerealiseerd en gekoppeld tot keten',
'eigenaar_id' => $sjoerd->id,
'deadline' => '2026-10-31',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 7',
]);
// Governance
Commitment::create([
'project_id' => $governance->id,
'beschrijving' => 'Projectstructuur- en documentatieafspraken vastgelegd',
'eigenaar_id' => $rene->id,
'deadline' => '2026-03-31',
'status' => CommitmentStatus::InUitvoering,
'bron' => 'Planning 2026 slide 8',
]);
Commitment::create([
'project_id' => $governance->id,
'beschrijving' => 'Rolafbakening R&D ↔ Beheer ↔ Bouwen vastgelegd en gecommuniceerd',
'eigenaar_id' => $rene->id,
'deadline' => '2026-06-30',
'status' => CommitmentStatus::Open,
'bron' => 'Planning 2026 slide 8',
]);
// ──────────────────────────────────────────────────────────────
// 8. Documents
// ──────────────────────────────────────────────────────────────
Document::create([
'project_id' => $bridge->id,
'titel' => 'Stack Architectuur Klundert Pilot',
'type' => 'technisch_ontwerp',
'inhoud' => 'Systeemarchitectuur EDGE-laag: Ubuntu LTS, Node-RED orkestratie, OPC UA communicatie met Siemens PLC T-serie, InfluxDB/Grafana datastromen.',
'versie' => 1,
'auteur_id' => $rene->id,
]);
Document::create([
'project_id' => $wise->id,
'titel' => 'Overdrachtsprotocol Monsternamekast',
'type' => 'protocol',
'inhoud' => 'Opleverdocument voor de overdracht van de monsternamekast naar Bouwen. Bevat: Node-RED flow specificaties, integratie voorspellend model, afbakening verantwoordelijkheden.',
'versie' => 1,
'auteur_id' => $rene->id,
]);
Document::create([
'project_id' => $crisp->id,
'titel' => 'Technische Toetsing Aanbesteding Compressoren',
'type' => 'technisch_rapport',
'inhoud' => 'Q&A en technische beoordeling van aanbestedingsdocumenten voor compressorvervanging Nieuwveer. TCO-analyse, prestatie-eisen, energie-efficiëntie.',
'versie' => 1,
'auteur_id' => $pim->id,
]);
Document::create([
'project_id' => $gemaal->id,
'titel' => 'Testrapport Prototype Gemaal 3.0',
'type' => 'technisch_rapport',
'inhoud' => 'Bevindingen en verbeterpunten uit validatie van het prototype: elektrische aansluitingen, I/O-functionaliteit, randapparatuur, digital twin koppelingen.',
'versie' => 1,
'auteur_id' => $sjoerd->id,
]);
Document::create([
'project_id' => $governance->id,
'titel' => 'R&D Projectstructuur & Beleidskader',
'type' => 'projectplan',
'inhoud' => 'Afspraken over projectstructuur, documentatiestandaarden, besluitvormingsproces en beleid voor het R&D-lab.',
'versie' => 1,
'auteur_id' => $rene->id,
]);
// ──────────────────────────────────────────────────────────────
// 9. Dependencies between projects
// ──────────────────────────────────────────────────────────────
// Afvlakkingsregeling hangt af van Gemaal 3.0 (prototype moet gevalideerd zijn)
Afhankelijkheid::create([
'project_id' => $afvlak->id,
'afhankelijk_van_project_id' => $gemaal->id,
'type' => 'technisch',
'beschrijving' => 'De afvlakkingsregeling vereist gevalideerde prototypes van Gemaal 3.0 (× 2 kopieën) als basis voor de ketenopstelling.',
'status' => 'open',
]);
// WISE overdracht profiteert van BRIDGE architectuur (gedeelde EDGE-infrastructuur)
Afhankelijkheid::create([
'project_id' => $wise->id,
'afhankelijk_van_project_id' => $bridge->id,
'type' => 'infrastructuur',
'beschrijving' => 'De monsternamekast draait op dezelfde EDGE-architectuur die BRIDGE valideert.',
'status' => 'open',
]);
// Gemaal 3.0 validatie van digital twins hangt samen met BRIDGE architectuur
Afhankelijkheid::create([
'project_id' => $gemaal->id,
'afhankelijk_van_project_id' => $bridge->id,
'type' => 'technisch',
'beschrijving' => 'Digital twin validatie in Gemaal 3.0 gebruikt dezelfde EDGE-laag als bewezen in BRIDGE.',
'status' => 'open',
]);
}
/**
* Helper: create a project with its completed and active phases.
*/
private function createProject(array $attributes, array $faseTypes): Project
{
$project = Project::create($attributes);
$project->teamleden()->attach($attributes['eigenaar_id'], ['rol' => ProjectRol::Eigenaar->value]);
foreach ($faseTypes as $index => $faseType) {
$isLast = $index === count($faseTypes) - 1;
Fase::create([
'project_id' => $project->id,
'type' => $faseType,
'status' => $isLast ? FaseStatus::Actief : FaseStatus::Afgerond,
'startdatum' => now()->subMonths(count($faseTypes) - 1 - $index),
'einddatum' => $isLast ? null : now()->subMonths(count($faseTypes) - 2 - $index),
]);
}
return $project;
}
}