Compare commits

..

10 Commits

Author SHA1 Message Date
mike
f306fa7ffd chore: update 8 file(s) 2025-12-20 18:15:47 +01:00
mike
fec4eab58d typo-fix 2025-12-15 23:02:25 +01:00
Tour
cb277c611d front 2025-12-10 12:08:26 +01:00
Tour
99962251a6 header 2025-12-10 09:22:37 +01:00
Tour
e85412e71f kanban 2025-12-10 09:02:15 +01:00
Tour
683823de6f kanban 2025-12-10 09:01:07 +01:00
Tour
613b6345f2 d2 2025-12-08 22:30:37 +01:00
Tour
7f2c46773e fgdf 2025-12-08 22:08:21 +01:00
Tour
7d5194d6fc fgdf 2025-12-08 21:28:18 +01:00
Tour
3382c5e1cd fgdf 2025-12-08 21:19:34 +01:00
35 changed files with 5567 additions and 2547 deletions

25
.aiignore Normal file
View File

@@ -0,0 +1,25 @@
# An .aiignore file follows the same syntax as a .gitignore file.
# .gitignore documentation: https://git-scm.com/docs/gitignore
# you can ignore files
.DS_Store
*.log
*.tmp
# or folders
dist/
build/
out/
# An .aiignore file follows the same syntax as a .gitignore file.
# .gitignore documentation: https://git-scm.com/docs/gitignore
# you can ignore files
# or folders
.idea
node_modules/
.vscode/
.git
.github
scripts
.pytest_cache/
__pycache__

View File

@@ -16,7 +16,7 @@ __pycache__/
# IDE # IDE
.vscode/ .vscode/
.idea/ ../../dev/pony/app/.idea/
*.swp *.swp
*.swo *.swo
*~ *~

2
.gitignore vendored
View File

@@ -17,7 +17,7 @@ node_modules/
# IDE # IDE
.vscode/ .vscode/
.idea/ ../../dev/pony/app/.idea/
*.swp *.swp
*.swo *.swo
*~ *~

10
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@@ -0,0 +1,621 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AddOperatorModifier" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="AddVarianceModifier" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ArrayInDataClass" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="BintrayPublishingPlugin" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="BooleanLiteralArgument" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="CanBeParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CanBePrimaryConstructorProperty" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CanBeVal" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CanSealedSubClassBeObject" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="CascadeIf" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="CdiAlternativeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiDecoratorInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiDisposerMethodInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiDomBeans" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CdiInjectInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiInjectionPointsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CdiInterceptorInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiManagedBeanInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiNormalScopeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CdiObservesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiScopeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CdiSpecializesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiStereotypeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiStereotypeRestrictionsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiTypedAnnotationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CdiUnknownProducersForDisposerMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CdiUnproxyableBeanTypesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ChangeToMethod" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ChangeToOperator" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ClashingTraitMethods" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ClassCanBeRecord" enabled="false" level="WEAK WARNING" enabled_by_default="false">
<option name="myConversionStrategy" value="SILENTLY" />
</inspection_tool>
<inspection_tool class="ClassName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ComplexRedundantLet" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ComposeUnknownKeys" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ComposeUnknownValues" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ConflictingExtensionProperty" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConstPropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ConstantConditionIf" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ControlFlowWithEmptyBody" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConvertCallChainIntoSequence" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ConvertLambdaToReference" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ConvertNaNEquality" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConvertPairConstructorToToFunction" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ConvertReferenceToLambda" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ConvertSecondaryConstructorToPrimary" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConvertToStringTemplate" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ConvertTryFinallyToUseCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ConvertTwoComparisonsToRangeCheck" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="CopyWithoutNamedArguments" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="CssBrowserCompatibilityForProperties" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssConvertColorToHexInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssConvertColorToRgbInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssMissingSemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CucumberExamplesColon" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CucumberMissedExamples" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CucumberTableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CucumberUndefinedStep" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DataClassPrivateConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DeferredIsResult" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="DeferredResultUnused" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DelegatesTo" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DelegationToVarProperty" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DeprecatedCallableAddReplaceWith" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="DeprecatedGradleDependency" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DeprecatedMavenDependency" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DestructuringWrongName" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DifferentKotlinGradleVersion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DifferentKotlinMavenVersion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DifferentMavenStdlibVersion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DifferentStdlibGradleVersion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DockerFileAddOrCopySemantic" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DockerFileArgumentCount" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="DockerFileAssignments" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="EmptyRange" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EmptyWebServiceClass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EnumEntryName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="EqualsOrHashCode" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ExplicitThis" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="FakeJvmFieldConstant" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="FoldInitializerAndIfToElvis" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ForEachParameterNotUsed" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ForgottenDebugOutputInspection" enabled="true" level="ERROR" enabled_by_default="true">
<option name="configuration">
<list>
<option value="\Codeception\Util\Debug::debug" />
<option value="\Codeception\Util\Debug::pause" />
<option value="\Doctrine\Common\Util\Debug::dump" />
<option value="\Doctrine\Common\Util\Debug::export" />
<option value="\Illuminate\Support\Debug\Dumper::dump" />
<option value="\Symfony\Component\Debug\Debug::enable" />
<option value="\Symfony\Component\Debug\DebugClassLoader::enable" />
<option value="\Symfony\Component\Debug\ErrorHandler::register" />
<option value="\Symfony\Component\Debug\ExceptionHandler::register" />
<option value="\TYPO3\CMS\Core\Utility\DebugUtility::debug" />
<option value="\Zend\Debug\Debug::dump" />
<option value="\Zend\Di\Display\Console::export" />
<option value="dd" />
<option value="debug_print_backtrace" />
<option value="debug_zval_dump" />
<option value="dpm" />
<option value="dpq" />
<option value="dsm" />
<option value="dump" />
<option value="dvm" />
<option value="error_log" />
<option value="kpr" />
<option value="phpinfo" />
<option value="print_r" />
<option value="var_dump" />
<option value="var_export" />
<option value="wp_die" />
<option value="xdebug_break" />
<option value="xdebug_call_class" />
<option value="xdebug_call_file" />
<option value="xdebug_call_function" />
<option value="xdebug_call_line" />
<option value="xdebug_code_coverage_started" />
<option value="xdebug_debug_zval" />
<option value="xdebug_debug_zval_stdout" />
<option value="xdebug_dump_superglobals" />
<option value="xdebug_enable" />
<option value="xdebug_get_code_coverage" />
<option value="xdebug_get_collected_errors" />
<option value="xdebug_get_declared_vars" />
<option value="xdebug_get_function_stack" />
<option value="xdebug_get_headers" />
<option value="xdebug_get_monitored_functions" />
<option value="xdebug_get_profiler_filename" />
<option value="xdebug_get_stack_depth" />
<option value="xdebug_get_tracefile_name" />
<option value="xdebug_is_enabled" />
<option value="xdebug_memory_usage" />
<option value="xdebug_peak_memory_usage" />
<option value="xdebug_print_function_stack" />
<option value="xdebug_start_code_coverage" />
<option value="xdebug_start_error_collection" />
<option value="xdebug_start_function_monitor" />
<option value="xdebug_start_trace" />
<option value="xdebug_stop_code_coverage" />
<option value="xdebug_stop_error_collection" />
<option value="xdebug_stop_function_monitor" />
<option value="xdebug_stop_trace" />
<option value="xdebug_time_index" />
<option value="xdebug_var_dump" />
</list>
</option>
<option name="migratedIntoUserSpace" value="true" />
</inspection_tool>
<inspection_tool class="FunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="FunctionWithLambdaExpressionBody" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="GherkinBrokenTableInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GherkinMisplacedBackground" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GherkinScenarioToScenarioOutline" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GrAnnotationReferencingUnknownIdentifiers" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrDeprecatedAPIUsage" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrEqualsBetweenInconvertibleTypes" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrFinalVariableAccess" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrMethodMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrNamedVariantLabels" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrPackage" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrReassignedInClosureLocalVar" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrUnnecessaryAlias" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="GrUnnecessaryDefModifier" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrUnnecessaryPublicModifier" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrUnnecessarySemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyAccessToStaticFieldLockedOnInstance" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyAccessibility" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyAssignabilityCheck" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyConditionalWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyConstantConditional" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyConstantIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyConstructorNamedArguments" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyDivideByZero" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyDocCheck" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GroovyDoubleNegation" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyDuplicateSwitchBranch" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyEmptyStatementBody" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyFallthrough" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyGStringKey" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyIfStatementWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyImplicitNullArgumentCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyInArgumentCheck" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyInfiniteLoopStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyInfiniteRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyLabeledStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyMissingReturnStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyPointlessBoolean" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyResultOfObjectAllocationIgnored" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovySillyAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovySynchronizationOnNonFinalField" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovySynchronizationOnVariableInitializedWithLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyTrivialConditional" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyTrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUncheckedAssignmentOfMemberOfRawType" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnnecessaryContinue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnnecessaryReturn" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnreachableStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnsynchronizedMethodOverridesSynchronizedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnusedAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnusedCatchParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyUnusedIncOrDec" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyVariableNotAssigned" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HasPlatformType" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="16">
<item index="0" class="java.lang.String" itemvalue="nobr" />
<item index="1" class="java.lang.String" itemvalue="noembed" />
<item index="2" class="java.lang.String" itemvalue="comment" />
<item index="3" class="java.lang.String" itemvalue="noscript" />
<item index="4" class="java.lang.String" itemvalue="embed" />
<item index="5" class="java.lang.String" itemvalue="script" />
<item index="6" class="java.lang.String" itemvalue="style" />
<item index="7" class="java.lang.String" itemvalue="nuxt-img" />
<item index="8" class="java.lang.String" itemvalue="nuxt-picture" />
<item index="9" class="java.lang.String" itemvalue="nuxt-content" />
<item index="10" class="java.lang.String" itemvalue="contentdoc" />
<item index="11" class="java.lang.String" itemvalue="contentquery" />
<item index="12" class="java.lang.String" itemvalue="nuxt" />
<item index="13" class="java.lang.String" itemvalue="ogimagescreenshot" />
<item index="14" class="java.lang.String" itemvalue="seokit" />
<item index="15" class="java.lang.String" itemvalue="nuxtlink" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
<inspection_tool class="HttpRequestContentLengthIsIgnored" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HttpRequestPlaceholder" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="IfThenToElvis" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="IfThenToSafeAccess" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ImplicitNullableNothingType" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ImplicitThis" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ImplicitlyExposedWebServiceMethods" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="IntroduceWhenSubject" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JBoss" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JCenterRepository" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JSConstructorReturnsPrimitive" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JSObsoletePrivateAccessSyntax" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JSUnresolvedReactComponent" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JavaCollectionsStaticMethod" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JavaCollectionsStaticMethodOnImmutableList" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxColorRgb" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxDefaultTag" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxEventHandler" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxRedundantPropertyValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxResourcePropertyValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxUnresolvedFxIdReference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxUnresolvedStyleClassReference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaFxUnusedImports" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaMapForEach" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JavaStylePropertiesInvocation" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="JoinDeclarationAndAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JpaAttributeMemberSignatureInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaAttributeTypeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaConfigDomFacetInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JpaDataSourceORMDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaDataSourceORMInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaEntityListenerInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaEntityListenerWarningsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JpaMissingIdInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaModelReferenceInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaORMDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaObjectClassSignatureInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaQlInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JpaQueryApiInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="KDocUnresolvedReference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinCovariantEquals" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinDeprecation" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinDoubleNegation" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinEqualsBetweenInconvertibleTypes" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinInternalInJava" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="KotlinInvalidBundleOrProperty" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="KotlinMavenPluginPhase" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinRedundantOverride" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinSealedInheritorsInJava" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="KotlinTestJUnit" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinThrowableNotThrown" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="KotlinUnusedImport" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LSPLocalInspectionTool" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LateinitVarOverridesLateinitVar" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LeakingThis" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LessResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="LessUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LessUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LiftReturnOrAssignment" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="LocalVariableName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="LoopToCallChain" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="MainFunctionReturnUnit" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MapGetWithNotNullAssertionOperator" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="MayBeConstant" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MemberVisibilityCanBePrivate" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="MicronautDataMethodInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="MicronautDataRepositoryMethodParametersInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MicronautDataRepositoryMethodReturnTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MigrateDiagnosticSuppression" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoreObjectMethods" value="true" />
<option name="ignoreAnonymousClassMethods" value="false" />
</inspection_tool>
<inspection_tool class="MnProperties" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MnUnresolvedPathVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MnYaml" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MongoJSDeprecationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MongoJSResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MongoJSSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MoveLambdaOutsideParentheses" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MoveSuspiciousCallableReferenceIntoParentheses" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MoveVariableDeclarationIntoWhen" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MsOrderByInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="MultipleMethodDesignatorsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="MultipleRepositoryUrls" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MysqlLoadDataPathInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NestedLambdaShadowedImplicitParameter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="NewInstanceOfSingleton" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NonJaxWsWebServices" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NullChecksToSafeCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="NullableBooleanElvis" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ObjectLiteralToLambda" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ObjectPropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ObsoleteExperimentalCoroutines" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ObsoleteKotlinJsPackages" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="OneWayWebMethod" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="OptionalExpectation" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="OraMissingBodyInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OraOverloadInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OraUnmatchedForwardDeclarationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="OverridingDeprecatedMember" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PackageDirectoryMismatch" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="PackageName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PathAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PgSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PlatformExtensionReceiverOfInline" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PrivatePropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ProtectedInFinal" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PyArgumentEqualDefaultInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PyAugmentAssignmentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PyBehaveInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyClassicStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ourVersions">
<value>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="2.7" />
<item index="1" class="java.lang.String" itemvalue="3.11" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyMandatoryEncodingInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyMissingOrEmptyDocstringInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PyMissingTypeHintsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="RecursiveEqualsCall" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RecursivePropertyAccessor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantAsSequence" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantAsync" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantCompanionReference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantElseInIf" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="RedundantElvisReturnNull" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantEmptyInitializerBlock" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="RedundantEnumConstructorInvocation" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantExplicitType" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantGetter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantIf" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantLambdaArrow" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantLambdaOrAnonymousFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantModalityModifier" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantNullableReturnType" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantObjectTypeCheck" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="RedundantRequireNotNullCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantReturnLabel" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantRunCatching" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantSamConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantSemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantSetter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantSuspendModifier" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantUnitExpression" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantUnitReturnType" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantVisibilityModifier" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantWith" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveCurlyBracesFromTemplate" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveEmptyClassBody" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="RemoveEmptyParenthesesFromAnnotationEntry" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveEmptyParenthesesFromLambdaCall" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="RemoveEmptyPrimaryConstructor" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveEmptySecondaryConstructorBody" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveExplicitSuperQualifier" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveExplicitTypeArguments" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveForLoopIndices" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveRedundantBackticks" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveRedundantCallsOfConversionMethods" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveRedundantQualifierName" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveRedundantSpreadOperator" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveSetterParameterType" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveSingleExpressionStringTemplate" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RemoveToStringInStringTemplate" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceArrayEqualityOpWithArraysEquals" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceArrayOfWithLiteral" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceAssertBooleanWithAssertEquality" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceAssociateFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceCallWithBinaryOperator" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceGetOrSet" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ReplaceGuardClauseWithFunctionCall" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceIsEmptyWithIfEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceJavaStaticMethodWithKotlinAnalog" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceManualRangeWithIndicesCalls" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="ReplaceNegatedIsEmptyWithIsNotEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplacePutWithAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceRangeStartEndInclusiveWithFirstLast" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceRangeToWithUntil" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceSizeCheckWithIsNotEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceSizeZeroCheckWithIsEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceStringFormatWithLiteral" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceSubstringWithDropLast" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceSubstringWithIndexingOperation" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceSubstringWithSubstringAfter" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceSubstringWithSubstringBefore" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceSubstringWithTake" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceToStringWithStringTemplate" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ReplaceToWithInfixForm" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceWithEnumMap" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceWithIgnoreCaseEquals" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="ReplaceWithOperatorAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RestParamTypeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="RestResourceMethodInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="RestWrongDefaultValueInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SafeCastWithReturn" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SassScssResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SassScssUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SassScssUnresolvedPlaceholderSelector" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SassScssUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ScopeFunctionConversion" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="SecondUnsafeCall" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SecurityAdvisoriesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="optionConfiguration">
<list>
<option value="barryvdh/laravel-debugbar" />
<option value="behat/behat" />
<option value="brianium/paratest" />
<option value="codeception/codeception" />
<option value="codedungeon/phpunit-result-printer" />
<option value="composer/composer" />
<option value="doctrine/coding-standard" />
<option value="filp/whoops" />
<option value="friendsofphp/php-cs-fixer" />
<option value="humbug/humbug" />
<option value="infection/infection" />
<option value="jakub-onderka/php-parallel-lint" />
<option value="johnkary/phpunit-speedtrap" />
<option value="kalessil/production-dependencies-guard" />
<option value="mikey179/vfsStream" />
<option value="mockery/mockery" />
<option value="mybuilder/phpunit-accelerator" />
<option value="orchestra/testbench" />
<option value="pdepend/pdepend" />
<option value="phan/phan" />
<option value="phing/phing" />
<option value="phpcompatibility/php-compatibility" />
<option value="phpmd/phpmd" />
<option value="phpro/grumphp" />
<option value="phpspec/phpspec" />
<option value="phpspec/prophecy" />
<option value="phpstan/phpstan" />
<option value="phpunit/phpunit" />
<option value="povils/phpmnd" />
<option value="roave/security-advisories" />
<option value="satooshi/php-coveralls" />
<option value="sebastian/phpcpd" />
<option value="slevomat/coding-standard" />
<option value="spatie/phpunit-watcher" />
<option value="squizlabs/php_codesniffer" />
<option value="sstalle/php7cc" />
<option value="symfony/debug" />
<option value="symfony/maker-bundle" />
<option value="symfony/phpunit-bridge" />
<option value="symfony/var-dumper" />
<option value="vimeo/psalm" />
<option value="wimg/php-compatibility" />
<option value="wp-coding-standards/wpcs" />
<option value="yiisoft/yii2-coding-standards" />
<option value="yiisoft/yii2-debug" />
<option value="yiisoft/yii2-gii" />
<option value="zendframework/zend-coding-standard" />
<option value="zendframework/zend-debug" />
<option value="zendframework/zend-test" />
</list>
</option>
</inspection_tool>
<inspection_tool class="SelfAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SelfReferenceConstructorParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SetterBackingFieldAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SimpleRedundantLet" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifiableCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifiableCallChain" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifyAssertNotNull" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="SimplifyBooleanWithConstants" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifyNegatedBinaryExpression" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifyNestedEachInScopeFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifyWhenWithBooleanConstantCondition" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SingletonConstructor" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SortModifiers" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAggregatesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCallNotationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlCaseVsCoalesceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCaseVsIfInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCurrentSchemaInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDtInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDuplicateColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlErrorHandlingInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlIdentifierLengthInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlIllegalCursorStateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertIntoGeneratedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertNullIntoNotNullInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlJoinWithoutOnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlMisleadingReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlMissingReturnInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlMultipleLimitClausesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantCodeInCoalesceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantElseNullInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantLimitInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlRedundantOrderingDirectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlResolveInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlShadowingAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStringLengthExceededInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTransactionStatementInTriggerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTriggerTransitionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnicodeStringLiteralInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnreachableCodeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedCteInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedSubqueryItemInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlWithoutWhereInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SuspendFunctionOnCoroutineScope" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousAsDynamic" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousCollectionReassignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousEqualsCombination" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousVarProperty" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TestFunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="TrailingComma" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="TypeCustomizer" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TypeScriptUnresolvedFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="TypeScriptUnresolvedReactComponent" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="TypeScriptUnresolvedVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="TypeScriptValidateJSTypes" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="UnlabeledReturnInsideLambda" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="UnnecessaryQualifiedReference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnnecessaryVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="UnresolvedReference" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="UnresolvedRestParam" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="UnsafeCastFromDynamic" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="UnstableApiUsage" enabled="true" level="WARNING" enabled_by_default="true">
<option name="unstableApiAnnotations">
<set>
<option value="io.reactivex.annotations.Beta" />
<option value="io.reactivex.annotations.Experimental" />
<option value="org.apache.http.annotation.Beta" />
<option value="org.gradle.api.Incubating" />
<option value="org.jetbrains.annotations.ApiStatus.Experimental" />
<option value="org.jetbrains.annotations.ApiStatus.Internal" />
<option value="org.jetbrains.annotations.ApiStatus.ScheduledForRemoval" />
<option value="rx.annotations.Beta" />
<option value="rx.annotations.Experimental" />
</set>
</option>
</inspection_tool>
<inspection_tool class="UnusedDataClassCopyResult" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedEquals" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedLambdaExpressionBody" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedReceiverParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedUnaryOperator" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseExpressionBody" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="UsePropertyAccessSyntax" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="UseWithIndex" enabled="false" level="INFO" enabled_by_default="false" />
<inspection_tool class="UselessCallOnCollection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UselessCallOnNotNull" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ValidExternallyBoundObject" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="VoidMethodAnnotatedWithGET" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="W3CssValidation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myCssVersion" value="css3svg" />
<option name="myIgnoreVendorSpecificProperties" value="false" />
</inspection_tool>
<inspection_tool class="WSReferenceInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="WadlDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="WebpackConfigHighlighting" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="WrapUnaryOperator" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="WsdlHighlightingInspection" enabled="false" level="ERROR" enabled_by_default="false" />
</profile>
</component>

17
.idea/material_theme_project_new.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="-15bcdc62:19b114a99b8:-7ffe" />
</MTProjectMetadataState>
</option>
<option name="titleBarState">
<MTProjectTitleBarConfigState>
<option name="overrideColor" value="false" />
</MTProjectTitleBarConfigState>
</option>
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/nex.iml" filepath="$PROJECT_DIR$/.idea/nex.iml" />
</modules>
</component>
</project>

8
.idea/nex.iml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -8,5 +8,5 @@ COPY public/ ./
# If the site references additional resources, copy them too # If the site references additional resources, copy them too
COPY resources/ ./resources COPY resources/ ./resources
# Optional: provide your own nginx.conf for SPA routing # Provide custom nginx.conf for clean URLs
# COPY nginx.conf /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf

View File

@@ -62,7 +62,20 @@ python main.py
Output files will be generated in the current directory as PNG images. Output files will be generated in the current directory as PNG images.
## Available Diagrams ## Available Diagrams
# Network Topology Viewer
A modern, interactive network topology visualization tool built with D2 diagrams.
## Features
- Interactive network diagram with pan/zoom
- Real-time node details and tooltips
- Clean, modern UI with dark theme
- Export capabilities
## Running with Docker
Build and run:
- `lan_architecture.py` - Home Lab / Auction Stack Architecture diagram - `lan_architecture.py` - Home Lab / Auction Stack Architecture diagram
- `main.py` - Network architecture diagram - `main.py` - Network architecture diagram

View File

@@ -17,7 +17,7 @@ services:
- "traefik.http.routers.nex-http.entrypoints=web" - "traefik.http.routers.nex-http.entrypoints=web"
- "traefik.http.routers.nex-http.middlewares=nex-https" - "traefik.http.routers.nex-http.middlewares=nex-https"
- "traefik.http.middlewares.nex-https.redirectscheme.scheme=https" - "traefik.http.middlewares.nex-https.redirectscheme.scheme=https"
- "traefik.http.routers.auction.tls.certresolver=letsencrypt", - "traefik.http.routers.auction.tls.certresolver=letsencrypt"
- "traefik.http.middlewares.nex-https.redirectscheme.permanent=true" - "traefik.http.middlewares.nex-https.redirectscheme.permanent=true"
networks: networks:

9
nex.iml Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

22
nginx.conf Normal file
View File

@@ -0,0 +1,22 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Enable clean URLs without .html extension
location / {
# Try the exact URI, then with .html, then as directory with index.html, then 404
try_files $uri $uri.html $uri/ =404;
}
# Optional: Redirect .html URLs to clean URLs
if ($request_uri ~ ^/(.*)\.html(\?|$)) {
return 301 /$1$2;
}
# Gzip compression for better performance
gzip on;
gzip_vary on;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
}

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
public/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

BIN
public/favicon-256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
public/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

20
public/favicon.svg Normal file
View File

@@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" role="img" aria-label="App.model">
<defs>
<linearGradient id="g" x1="0" x2="1" y1="0" y2="1">
<stop offset="0" stop-color="#60a5fa"/>
<stop offset="1" stop-color="#818cf8"/>
</linearGradient>
<filter id="s" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0f172a" flood-opacity="0.6"/>
</filter>
</defs>
<rect x="2" y="2" width="60" height="60" rx="12" ry="12" fill="url(#g)" filter="url(#s)"/>
<g transform="translate(32,34) scale(0.9)">
<path d="M-12,-8 L0,-22 L12,-8 Z" fill="#0f172a" opacity="0.95"/>
<rect x="-10" y="-8" width="20" height="16" rx="3" ry="3" fill="#0f172a" opacity="0.95"/>
<rect x="-3" y="0" width="6" height="8" rx="1" ry="1" fill="#60a5fa"/>
<circle cx="10" cy="-4" r="3" fill="#fbbf24" stroke="#fff5" stroke-width="0.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 960 B

File diff suppressed because it is too large Load Diff

432
public/kan.html Normal file
View File

@@ -0,0 +1,432 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🎯 Techs</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh; padding: 20px; color: #333;
}
.dashboard {
max-width: 1400px; margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
border-radius: 20px; padding: 30px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
header { text-align: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 3px solid #667eea; }
h1 { font-size: 2.5em; color: #667eea; margin-bottom: 10px; font-weight: 700; }
.date { font-size: 1.2em; color: #666; font-weight: 500; }
.control-panel {
background: #f3f4f6; padding: 20px; border-radius: 15px;
margin-bottom: 30px; border: 2px dashed #9ca3af; position: relative;
}
.control-panel h3 { margin-bottom: 10px; color: #667eea; }
.control-textarea {
width: 100%; min-height: 150px; padding: 15px; border-radius: 8px;
border: 1px solid #d1d5db; font-family: 'Courier New', monospace; font-size: 0.9em;
resize: vertical; margin-bottom: 10px;
}
.control-hint {
font-size: 0.85em; color: #6b7280; font-family: monospace;
background: white; padding: 10px; border-radius: 5px; margin-top: 10px;
}
.save-indicator {
position: absolute; top: 10px; right: 10px;
background: #10b981; color: white; padding: 5px 10px;
border-radius: 5px; font-size: 0.8em; opacity: 0;
transition: opacity 0.3s ease;
}
.save-indicator.show { opacity: 1; }
.progress-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white; padding: 25px; border-radius: 15px;
margin-bottom: 30px; box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
.progress-label { display: flex; justify-content: space-between; margin-bottom: 10px; font-size: 1.1em; font-weight: 500; }
.progress-bar { width: 100%; height: 30px; background: rgba(255, 255, 255, 0.3); border-radius: 15px; overflow: hidden; position: relative; }
.progress-fill { height: 100%; background: linear-gradient(90deg, #4ade80 0%, #22c55e 100%); width: 25%; transition: width 0.5s ease; position: relative; box-shadow: 0 0 20px rgba(74, 222, 128, 0.5); }
.progress-fill::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); animation: shimmer 2s infinite; }
@keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
.projects-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 25px; margin-bottom: 30px; }
.project-card { background: white; border-radius: 15px; padding: 25px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease; border-left: 5px solid; }
.project-card:hover { transform: translateY(-5px); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); }
.project-card.defrag { border-left-color: #667eea; }
.project-card.dual-boot { border-left-color: #f59e0b; }
.project-card.ai { border-left-color: #10b981; }
.project-card.autocomplete { border-left-color: #ef4444; }
.project-card.quick-actions { border-left-color: #8b5cf6; background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); }
.project-header { display: flex; align-items: center; margin-bottom: 20px; }
.project-icon { font-size: 2em; margin-right: 15px; }
h2 { font-size: 1.5em; color: #222; font-weight: 600; }
.task-item { display: flex; align-items: center; padding: 10px 0; border-bottom: 1px solid #e5e7eb; }
.task-item:last-child { border-bottom: none; }
.task-item:hover { background: #f9fafb; border-radius: 5px; margin: 0 -10px; padding: 10px; }
.task-checkbox { width: 18px; height: 18px; margin-right: 12px; cursor: pointer; accent-color: #667eea; }
.task-text { flex: 1; }
.task-text.completed { text-decoration: line-through; opacity: 0.6; }
.task-status { font-size: 0.85em; padding: 3px 10px; border-radius: 12px; margin-left: 10px; font-weight: 500; }
.status-todo { background: #f3f4f6; color: #666; }
.status-progress { background: #dbeafe; color: #1d4ed8; }
.status-completed { background: #dcfce7; color: #166534; }
.priority-badge { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-left: 10px; }
.priority-high { background: #ef4444; }
.priority-medium { background: #f59e0b; }
.priority-low { background: #10b981; }
.action-list { list-style: none; }
.action-list li { padding: 10px 0; display: flex; align-items: center; }
.action-checkbox { margin-right: 12px; width: 18px; height: 18px; cursor: pointer; accent-color: #f59e0b; }
.legend { background: #f9fafb; padding: 20px; border-radius: 15px; margin-bottom: 30px; display: flex; justify-content: space-around; flex-wrap: wrap; gap: 20px; }
.legend-item { display: flex; align-items: center; }
.notes { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); padding: 20px; border-radius: 15px; border-left: 5px solid #f59e0b; }
.notes h3 { margin-bottom: 10px; color: #92400e; }
.notes ul { list-style-position: inside; color: #78350f; }
.footer { text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid #e5e7eb; color: #666; font-size: 0.9em; }
@media (max-width: 768px) { .projects-grid { grid-template-columns: 1fr; } h1 { font-size: 2em; } }
</style>
</head>
<body>
<div class="dashboard">
<header>
<h1>🎯 Interactive Tech Dashboard</h1>
<div class="date">December 10, 2025 | Focus: Infrastructure & AI</div>
</header>
<div class="control-panel">
<h3>🎮 Control Panel - Edit tasks below:</h3>
<div class="save-indicator" id="saveIndicator">✓ Saved to browser</div>
<textarea class="control-textarea" id="taskControl" placeholder="Enter tasks in format: PROJECT|Task description|status|priority|notes
Click 'Update Dashboard' to apply changes..."></textarea>
<button onclick="updateDashboard()" style="background: #667eea; color: white; padding: 10px 20px; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; margin-right: 10px;">🔄 Update Dashboard</button>
<button onclick="resetToDefault()" style="background: #ef4444; color: white; padding: 10px 20px; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; margin-right: 10px;">🔄 Reset to Default</button>
<button onclick="exportTasks()" style="background: #10b981; color: white; padding: 10px 20px; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">📥 Export Tasks</button>
<div class="control-hint">
Format: PROJECT|Task|status|priority|notes<br>
PROJECT: DEFRAG, DUAL_BOOT, AI, AUTOCOMPLETE, QUICK_ACTIONS<br>
Status: todo, progress, completed<br>
Priority: high, medium, low (or blank)
</div>
</div>
<div class="progress-section">
<div class="progress-label">
<span>Overall Progress</span>
<span id="progressText">25% (2 of 8 tasks)</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
</div>
<div class="projects-grid" id="projectsGrid"></div>
<div class="legend">
<div class="legend-item">
<span class="status-badge status-todo">TODO</span>
<span style="margin-left: 10px;">Not started</span>
</div>
<div class="legend-item">
<span class="status-badge status-progress">PROGRESS</span>
<span style="margin-left: 10px;">Active</span>
</div>
<div class="legend-item">
<span class="status-badge status-completed">COMPLETED</span>
<span style="margin-left: 10px;">Done</span>
</div>
<div class="legend-item">
<span class="priority-badge priority-high"></span>
<span>High Priority</span>
</div>
<div class="legend-item">
<span class="priority-badge priority-medium"></span>
<span>Medium Priority</span>
</div>
<div class="legend-item">
<span class="priority-badge priority-low"></span>
<span>Low Priority</span>
</div>
</div>
<div class="notes">
<h3>💡 Notes</h3>
<ul>
<li>Focus on local machine maintenance first</li>
<li>Athena tasks blocked until disk cleanup complete</li>
<li>Mobile scraper requires network performance testing</li>
<li>Object detection model needs GPU verification</li>
</ul>
</div>
<div class="footer">
<p><strong>Next Review:</strong> End of day | <strong>ETA for completion:</strong> 2-3 days</p>
</div>
</div>
<script>
// Default task data
const DEFAULT_TASKS = `DEFRAG|App initialization|todo||local
DEFRAG|In-screen dynamic console|progress||local
DEFRAG|Disk cleanup tool integration|todo||local
DEFRAG|Athena monitoring dashboard|todo||athena
DUAL_BOOT|Partition disk space (50GB+)|todo|high|local
DUAL_BOOT|Install Ubuntu dual boot|todo|high|local
DUAL_BOOT|Configure boot loader|todo|medium|local
AI|Auctiora: Set up object detection pipeline|todo||local
AI|Auctiora: Test model inference|todo||local
AI|Scraper: Configure for mobile network|todo||mobile
AI|Scraper: Test connectivity & performance|todo||mobile
AUTOCOMPLETE|Deploy autocomplete API endpoint|todo||athena
AUTOCOMPLETE|Test integration with existing infrastructure|todo||athena
QUICK_ACTIONS|Free up disk space (50GB+)|todo||local
QUICK_ACTIONS|Install dual boot setup|todo||local
QUICK_ACTIONS|Migrate development environment|todo||local`;
let allTasks = [];
// Load from localStorage or use defaults
function loadTasks() {
const stored = localStorage.getItem('dashboardTasks');
if (stored) {
document.getElementById('taskControl').value = stored;
} else {
document.getElementById('taskControl').value = DEFAULT_TASKS;
saveToLocalStorage(); // Save defaults on first load
}
}
// Save to localStorage with visual feedback
function saveToLocalStorage() {
const value = document.getElementById('taskControl').value;
localStorage.setItem('dashboardTasks', value);
// Show save indicator
const indicator = document.getElementById('saveIndicator');
indicator.classList.add('show');
setTimeout(() => indicator.classList.remove('show'), 2000);
}
// Parse task data from control textarea
function parseTasks() {
const lines = document.getElementById('taskControl').value.trim().split('\n');
allTasks = [];
lines.forEach((line, index) => {
if (!line.trim()) return;
const parts = line.split('|').map(p => p.trim());
allTasks.push({
id: index,
project: parts[0] || 'MISC',
description: parts[1] || '',
status: parts[2] || 'todo',
priority: parts[3] || '',
notes: parts[4] || '',
rawLine: line
});
});
}
// Update progress bar
function updateProgress() {
const completed = allTasks.filter(t => t.status === 'completed').length;
const total = allTasks.length;
const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
document.getElementById('progressText').textContent = `${percentage}% (${completed} of ${total} tasks)`;
document.getElementById('progressFill').style.width = percentage + '%';
}
// Toggle task status
function toggleTask(taskId) {
const task = allTasks.find(t => t.id === taskId);
if (task) {
const statuses = ['todo', 'progress', 'completed'];
const currentIdx = statuses.indexOf(task.status);
task.status = statuses[(currentIdx + 1) % statuses.length];
// Update control textarea
updateControlTextarea();
// Save to localStorage
saveToLocalStorage();
// Re-render dashboard
renderDashboard();
}
}
// Update control textarea from task data
function updateControlTextarea() {
const lines = allTasks.map(task =>
`${task.project}|${task.description}|${task.status}|${task.priority}|${task.notes}`
);
document.getElementById('taskControl').value = lines.join('\n');
}
// Render the dashboard
function renderDashboard() {
parseTasks();
updateProgress();
const grid = document.getElementById('projectsGrid');
grid.innerHTML = '';
// Group tasks by project
const projects = {};
allTasks.forEach(task => {
if (!projects[task.project]) {
projects[task.project] = [];
}
projects[task.project].push(task);
});
// Project configurations
const projectConfig = {
'DEFRAG': { icon: '🔧', title: 'DEFRAG Application', color: 'defrag', subtitle: 'Disk optimization toolkit development' },
'DUAL_BOOT': { icon: '💻', title: 'Dual Boot Setup', color: 'dual-boot', subtitle: 'Unix/Linux workstation configuration' },
'AI': { icon: '🤖', title: 'AI/ML Projects', color: 'ai', subtitle: 'Artificial Intelligence & Machine Learning' },
'AUTOCOMPLETE': { icon: '✅', title: 'Autocomplete Service', color: 'autocomplete', subtitle: 'Athena server configuration' },
'QUICK_ACTIONS': { icon: '⚡', title: 'Quick Actions', color: 'quick-actions', subtitle: 'Immediate priority tasks' }
};
// Render each project
Object.entries(projects).forEach(([projectName, tasks]) => {
if (projectName === 'QUICK_ACTIONS') {
// Render quick actions as a special card
const quickActionsCard = document.createElement('div');
quickActionsCard.className = 'quick-actions';
quickActionsCard.innerHTML = `
<div class="project-header">
<span class="project-icon">⚡</span>
<h2>Quick Actions - Switch to Ubuntu</h2>
</div>
<ul class="action-list">
${tasks.map(task => `
<li>
<input type="checkbox" class="action-checkbox"
${task.status === 'completed' ? 'checked' : ''}
onchange="toggleTask(${task.id})">
<span class="${task.status === 'completed' ? 'task-text completed' : 'task-text'}">${task.description}</span>
</li>
`).join('')}
</ul>
`;
grid.appendChild(quickActionsCard);
} else {
const config = projectConfig[projectName] || { icon: '📌', title: projectName, color: 'misc', subtitle: '' };
const card = document.createElement('div');
card.className = `project-card ${config.color}`;
if (projectName === 'AI') {
// Special handling for AI project with subsections
const auctioraTasks = tasks.filter(t => t.description.includes('Auctiora'));
const scraperTasks = tasks.filter(t => t.description.includes('Scraper'));
card.innerHTML = `
<div class="project-header">
<span class="project-icon">${config.icon}</span>
<h2>${config.title}</h2>
</div>
${config.subtitle ? `<p style="color: #666; margin-bottom: 15px;">${config.subtitle}</p>` : ''}
<h3 style="margin: 15px 0 10px; color: #667eea;">Auctiora - Object Detection</h3>
${auctioraTasks.map(task => `
<div class="task-item">
<input type="checkbox" class="task-checkbox"
${task.status === 'completed' ? 'checked' : ''}
onchange="toggleTask(${task.id})">
<span class="${task.status === 'completed' ? 'task-text completed' : 'task-text'}">${task.description.replace('Auctiora: ', '')}</span>
<span class="task-status status-${task.status}">${task.status.toUpperCase()}</span>
</div>
`).join('')}
<h3 style="margin: 20px 0 10px; color: #667eea;">Mobile Scraper</h3>
${scraperTasks.map(task => `
<div class="task-item">
<input type="checkbox" class="task-checkbox"
${task.status === 'completed' ? 'checked' : ''}
onchange="toggleTask(${task.id})">
<span class="${task.status === 'completed' ? 'task-text completed' : 'task-text'}">${task.description.replace('Scraper: ', '')}</span>
<span class="task-status status-${task.status}">${task.status.toUpperCase()}</span>
</div>
`).join('')}
`;
} else {
// Standard project card
card.innerHTML = `
<div class="project-header">
<span class="project-icon">${config.icon}</span>
<h2>${config.title}</h2>
</div>
${config.subtitle ? `<p style="color: #666; margin-bottom: 15px;">${config.subtitle}</p>` : ''}
${tasks.map(task => `
<div class="task-item">
<input type="checkbox" class="task-checkbox"
${task.status === 'completed' ? 'checked' : ''}
onchange="toggleTask(${task.id})">
<span class="${task.status === 'completed' ? 'task-text completed' : 'task-text'}">${task.description}</span>
<span class="task-status status-${task.status}">${task.status.toUpperCase()}</span>
${task.priority ? `<span class="priority-badge priority-${task.priority}" title="${task.priority} priority"></span>` : ''}
${task.notes ? `<span style="margin-left: 8px; font-size: 0.85em; color: #6b7280;">(${task.notes})</span>` : ''}
</div>
`).join('')}
`;
}
grid.appendChild(card);
}
});
}
// Update dashboard from control textarea
function updateDashboard() {
saveToLocalStorage();
renderDashboard();
}
// Reset to default tasks
function resetToDefault() {
if (confirm('Are you sure you want to reset to default tasks? This will overwrite your current data.')) {
document.getElementById('taskControl').value = DEFAULT_TASKS;
saveToLocalStorage();
renderDashboard();
}
}
// Export tasks to clipboard
function exportTasks() {
const tasks = document.getElementById('taskControl').value;
navigator.clipboard.writeText(tasks).then(() => {
const indicator = document.getElementById('saveIndicator');
indicator.textContent = '✓ Copied to clipboard!';
indicator.classList.add('show');
setTimeout(() => {
indicator.textContent = '✓ Saved to browser';
indicator.classList.remove('show');
}, 2000);
});
}
// Initialize on load
window.onload = function() {
loadTasks();
renderDashboard();
};
</script>
</body>
</html>

80
public/kanban.html Normal file
View File

@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Today Dashboard</title>
<style>
body {
font-family: Arial, sans-serif;
background: #f4f6f8;
margin: 0;
padding: 40px;
color: #222;
}
h1 {
text-align: center;
margin-bottom: 40px;
font-weight: 700;
}
.section {
background: #fff;
border-radius: 12px;
padding: 24px 28px;
margin-bottom: 26px;
box-shadow: 0 4px 12px rgba(0,0,0,0.07);
}
.section h2 {
margin-top: 0;
font-size: 22px;
color: #333;
border-left: 4px solid #4a90e2;
padding-left: 10px;
}
ul {
list-style: none;
padding-left: 0;
margin-top: 14px;
}
li {
background: #f0f3f7;
margin-bottom: 8px;
padding: 10px 14px;
border-radius: 8px;
font-size: 15px;
}
</style>
</head>
<body>
<h1>📌 Today Dashboard</h1>
<div class="section">
<h2>🚀 Core Dev</h2>
<ul>
<li><strong>DEFRAG</strong> — App-init afronden</li>
<li>Live console-updates + progress-bar</li>
<li><strong>Auctiora</strong> — Object-detectie verder brengen</li>
<li><strong>Scraper</strong> — Test via mobiel netwerk</li>
</ul>
</div>
<div class="section">
<h2>💾 System & Ops</h2>
<ul>
<li>Lokale disk opschonen (tool)</li>
<li>Athena disk-usage inzichtelijk maken</li>
<li>Dual-boot Unix/Linux voorbereiden</li>
<li>Ruimte vrijmaken voor Ubuntu</li>
</ul>
</div>
<div class="section">
<h2>🧠 Dev Experience</h2>
<ul>
<li>Athena — Autocomplete/finish verbeteren</li>
<li>Athena — Output inzichtelijker maken</li>
</ul>
</div>
</body>
</html>

266
public/mermaid..html Normal file
View File

@@ -0,0 +1,266 @@
<!-- test321 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Home-Lab diagram live editor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root{--bg:#f7f9fc;--text:#222;--accent:#0d6efd}
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial;font-size:14px;background:var(--bg);color:var(--text)}
header{background:var(--accent);color:#fff;padding:.6rem 1rem;font-weight:600;display:flex;gap:.5rem;align-items:center}
header button{padding:.2rem .6rem;border:none;border-radius:4px;background:#fff;color:var(--accent);cursor:pointer}
.wrap{display:flex;height:calc(100vh - 40px)}
.panel{flex:1;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid #ddd;transition:flex .3s ease}
.panel:last-child{border:none}
h3{margin:.4rem .6rem;font-size:1rem}
#src{flex:1;padding:.5rem;overflow:auto;background:#1e1e1e;color:#d4d4d4;font-family:"Consolas","Monaco",monospace;border:none;outline:none;white-space:pre-wrap}
#preview{flex:1;padding:.5rem;overflow:auto;background:#fff}
/* IMPORTANT: Let the SVG flow naturally and scroll if needed */
#preview svg{display:block;margin:0 auto;max-width:100%;height:auto}
#error{color:#d32f2f;background:#fff3cd;padding:.5rem;margin:.5rem;border-left:4px solid #d32f2f;display:none}
#zoomVal{margin-left:.5rem;font-size:.9rem;color:#fff}
/* collapsed state */
#srcPanel.collapsed{flex:0}
#srcPanel.collapsed #src{display:none}
/* Debug: uncomment to see element bounds */
/* #preview{outline:2px solid red} #preview svg{outline:2px solid blue} */
</style>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
</head>
<body>
<header>
<button id="toggleBtn" onclick="togglePanel()">🗔 Hide source</button>
Home-Lab diagram live Mermaid editor
<button onclick="saveSVG()">💾 SVG</button>
<button onclick="savePNG()">💾 PNG</button>
<button onclick="reset()">🔄 Reset</button>
<label style="margin-left:auto;display:flex;align-items:center;gap:.3rem;color:#fff">
Zoom: <input type="range" id="zoom" min="50" max="300" value="100" style="width:100px"><span id="zoomVal">100%</span>
</label>
</header>
<div class="wrap">
<div class="panel" id="srcPanel">
<h3>Source (edit here)</h3>
<textarea id="src" spellcheck="false"></textarea>
</div>
<div class="panel">
<h3>Live preview</h3>
<div id="preview"></div>
<div id="error"></div>
</div>
</div>
<script>
const DEFAULT = `flowchart TD
%% ---------- styles ----------
classDef internet fill:#e1f5ff,stroke:#007bff
classDef router fill:#fff3cd,stroke:#ffc107
classDef lan fill:#f8f9ff,stroke:#6c757d,stroke-width:2px
classDef core fill:#ffe6e6,stroke:#dc3545
classDef infra fill:#e6ffe6,stroke:#28a745
classDef worker fill:#f0e6ff,stroke:#6f42c1
classDef iot fill:#fff9e6,stroke:#fd7e14
%% ---------- nodes ----------
internet(🌐 Internet / Cloud):::internet
router[🛜 Router\nhub.lan\n192.168.1.1]:::router
subgraph LAN [🏠 LAN 192.168.1.0/24]
subgraph CORE [💻 Core server\n192.168.1.159]
traefik[🚦 Traefik]:::core
gitea[📚 Gitea]:::core
dokku[🐳 Dokku]:::core
auction[🧱 Auction stack]:::core
mi50[🧠 MI50 / Ollama]:::core
end
subgraph INFRA [🧭 Infra & DNS\n192.168.1.163]
adguard[🛡️ AdGuard]:::infra
artifactory[📦 Artifactory]:::infra
end
ha[🏡 Home Assistant\n192.168.1.193]:::infra
atlas[🧱 Atlas\n192.168.1.100]:::worker
iot1[📺 IoT-1]:::iot
iot2[📟 IoT-2]:::iot
end
subgraph TETHER [📶 Tether 192.168.137.0/24]
hermes[🛰️ Hermes]:::worker
plato[🛰️ Plato]:::worker
end
dev[👨‍💻 Dev laptop]:::internet
%% ---------- edges ----------
internet ==> router
router --> CORE
router --> INFRA
router --> ha
router --> atlas
router --> iot1
router --> iot2
dev ==> gitea
dev ==> dokku
dev ==> mi50
traefik --> gitea
traefik --> auction
traefik --> dokku
CORE -.->|DNS| adguard
ha -.->|DNS| adguard
atlas-.->|DNS| adguard
hermes-.->|DNS| adguard
plato-.->|DNS| adguard
CORE === TETHER
`;
function getStorage(key, fallback) {
try { return localStorage.getItem(key) ?? fallback; } catch { return fallback; }
}
function setStorage(key, val) {
try { localStorage.setItem(key, val); } catch {}
}
const srcEl = document.getElementById('src');
const errEl = document.getElementById('error');
const zoomEl = document.getElementById('zoom');
const zoomVal = document.getElementById('zoomVal');
const srcPanel = document.getElementById('srcPanel');
const toggleBtn = document.getElementById('toggleBtn');
srcEl.value = getStorage('labDiagram', DEFAULT);
if (getStorage('panelCollapsed', 'false') === 'true') {
srcPanel.classList.add('collapsed');
toggleBtn.textContent = '🗔 Show source';
}
function togglePanel() {
srcPanel.classList.toggle('collapsed');
const collapsed = srcPanel.classList.contains('collapsed');
toggleBtn.textContent = collapsed ? '🗔 Show source' : '🗔 Hide source';
setStorage('panelCollapsed', collapsed);
}
mermaid.initialize({startOnLoad: false, theme: 'default'});
function render() {
const src = srcEl.value;
setStorage('labDiagram', src);
errEl.style.display = 'none';
const preview = document.getElementById('preview');
preview.innerHTML = '';
const mermaidDiv = document.createElement('div');
mermaidDiv.className = 'mermaid';
mermaidDiv.textContent = src;
preview.appendChild(mermaidDiv);
// Render and fix sizing
mermaid.init(undefined, mermaidDiv).then(() => {
const svg = preview.querySelector('svg');
if (svg) {
// CRITICAL: Ensure SVG has viewBox for proper sizing
if (!svg.hasAttribute('viewBox')) {
const {width, height} = svg.getBBox();
svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
}
svg.style.maxWidth = '100%';
svg.style.height = 'auto';
applyZoom();
}
}).catch(e => {
errEl.textContent = 'Mermaid error: ' + e.message;
errEl.style.display = 'block';
});
}
srcEl.addEventListener('input', () => {
clearTimeout(srcEl._t);
srcEl._t = setTimeout(render, 300);
});
zoomEl.addEventListener('input', () => {
zoomVal.textContent = zoomEl.value + '%';
applyZoom();
});
function applyZoom() {
const svg = document.querySelector('#preview svg');
if (svg) {
svg.style.transform = `scale(${zoomEl.value / 100})`;
}
}
function reset() {
if (confirm('Reset to default diagram?')) {
srcEl.value = DEFAULT;
zoomEl.value = 100;
zoomVal.textContent = '100%';
setStorage('labDiagram', DEFAULT);
render();
}
}
function saveSVG() {
const svg = document.querySelector('#preview svg');
if (!svg) return alert('Nothing to save yet.');
const clone = svg.cloneNode(true);
clone.removeAttribute('style');
clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
const blob = new Blob([clone.outerHTML], {type: 'image/svg+xml'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'home-lab.svg';
a.click();
setTimeout(() => URL.revokeObjectURL(url), 100);
}
function savePNG() {
const svg = document.querySelector('#preview svg');
if (!svg) return alert('Nothing to save yet.');
const {width, height} = svg.getBBox();
const canvasW = Math.max(width, 1200);
const canvasH = Math.max(height, 800);
const svgData = new XMLSerializer().serializeToString(svg);
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = canvasW;
canvas.height = canvasH;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvasW, canvasH);
ctx.drawImage(img, 0, 0, canvasW, canvasH);
canvas.toBlob(blob => {
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'home-lab.png';
a.click();
});
};
img.onerror = () => alert('PNG conversion failed. Try SVG instead.');
img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgData);
}
render();
</script>
</body>
</html>
<!-- Auto-deployed at $(date122`) -->

151
public/network.d2 Normal file
View File

@@ -0,0 +1,151 @@
title: Home Network Topology | font-size: 24
classes: {
router: {
style: {
fill: "#f59e0b"
stroke: "#fbbf24"
stroke-width: 2
shape: rectangle
border-radius: 5
}
}
core: {
style: {
fill: "#ef4444"
stroke: "#f87171"
stroke-width: 2
shape: hexagon
}
}
infra: {
style: {
fill: "#10b981"
stroke: "#34d399"
stroke-width: 2
}
}
worker: {
style: {
fill: "#8b5cf6"
stroke: "#a78bfa"
stroke-width: 2
shape: hexagon
}
}
iot: {
style: {
fill: "#f97316"
stroke: "#fb923c"
stroke-width: 2
shape: rounded-box
}
}
client: {
style: {
fill: "#6b7280"
stroke: "#9ca3af"
stroke-width: 2
shape: rectangle
border-radius: 5
}
}
dns: {
style: {
fill: "#0ea5e9"
stroke: "#38bdf8"
stroke-width: 2
}
}
}
Internet: "☁️ Internet\nCloudflare DNS\n5.132.33.195" {
class: dns
near: top-center
}
Router: "🛜 Zyxel Router\nhub.lan\n192.168.1.1" {
class: router
near: Router.n
}
LAN: {
label: "LAN 192.168.1.0/24"
shape: rectangle
style: {
fill: "#1e293b"
stroke: "#475569"
stroke-width: 2
stroke-dash: 5
opacity: 0.3
}
Traefik: "⚡ Traefik\nReverse Proxy\n192.168.1.159" {class: core}
Dokku: "⚡ Dokku PaaS\n192.168.1.159" {class: core}
Gitea: "⚡ Gitea\ngit.appmodel.nl" {class: core}
Auction: "⚡ Auction\nauction.appmodel.nl" {class: core}
MI50: "⚡ MI50/Ollama\nollama.lan" {class: core}
AdGuard: "🔧 AdGuard\nDNS Filter" {class: infra}
XU4: "🔧 XU4 DNS\n192.168.1.163" {class: infra}
C2: "🔧 C2 DNS\n192.168.1.227" {class: infra}
HA: "🔧 Home Assistant\n192.168.1.193" {class: infra}
Atlas: "💻 Atlas\n192.168.1.100" {class: worker}
TV: "📺 Kamer-TV\n192.168.1.240" {class: iot}
Hue: "💡 Philips Hue\n192.168.1.49" {class: iot}
Eufy: "📹 Eufy S380HB\n192.168.1.59" {class: iot}
IoT: "🔌 IoT Devices\nNest/Roborock/ESP/Printer" {class: iot}
MIKE: "💻 MIKE PC\n192.168.1.100\nLAN + Tether" {class: client}
Lotte: "📱 Lotte\n192.168.1.133" {class: client}
}
Tether: {
label: "Tether 192.168.137.0/24"
shape: rectangle
style: {
fill: "#0f172a"
stroke: "#334155"
stroke-width: 2
stroke-dash: 5
opacity: 0.3
}
Hermes: "💻 Hermes\n192.168.137.239" {class: worker}
Plato: "💻 Plato\n192.168.137.239\nllm.plato.lan" {class: worker}
}
Internet -> Router: provides DNS
Router -> LAN.Traefik: routes
Router -> LAN.Dokku: routes
Router -> LAN.Gitea: routes
Router -> LAN.Auction: routes
Router -> LAN.MI50: routes
Router -> LAN.AdGuard: routes
Router -> LAN.XU4: routes
Router -> LAN.C2: routes
Router -> LAN.HA: routes
Router -> LAN.Atlas: routes
Router -> LAN.TV: routes
Router -> LAN.Hue: routes
Router -> LAN.Eufy: routes
Router -> LAN.IoT: routes
Router -> LAN.MIKE: routes
Router -> LAN.Lotte: routes
LAN.MIKE -> Tether.Hermes: tether bridge
LAN.MIKE -> Tether.Plato: tether bridge
LAN.Traefik -> LAN.Gitea: proxies
LAN.Traefik -> LAN.Dokku: proxies
LAN.Traefik -> LAN.Auction: proxies
LAN.XU4 -.-> LAN.AdGuard: filters
LAN.C2 -.-> LAN.AdGuard: filters
LAN.Atlas -.-> LAN.AdGuard: uses
LAN.HA -.-> LAN.AdGuard: uses
Tether.Hermes -.-> LAN.AdGuard: uses
Tether.Plato -.-> LAN.AdGuard: uses

1295
public/struz.html Normal file

File diff suppressed because it is too large Load Diff

933
public/top.html Normal file
View File

@@ -0,0 +1,933 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Network Topology</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
color: #e2e8f0;
overflow: hidden;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
background: rgba(15, 23, 42, 0.9);
backdrop-filter: blur(10px);
padding: 20px;
border-bottom: 1px solid #334155;
z-index: 10;
}
.header h1 {
font-size: 1.8em;
background: linear-gradient(90deg, #60a5fa 0%, #818cf8 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
display: flex;
align-items: center;
gap: 12px;
}
.controls {
position: absolute;
top: 20px;
right: 20px;
display: flex;
gap: 10px;
z-index: 100;
}
.control-btn {
background: rgba(30, 41, 59, 0.7);
border: 1px solid #475569;
color: #cbd5e1;
padding: 8px 16px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.control-btn:hover {
background: rgba(56, 70, 100, 0.8);
border-color: #60a5fa;
}
.main-svg {
flex: 1;
width: 100%;
height: calc(100% - 80px);
cursor: grab;
}
.main-svg:active {
cursor: grabbing;
}
/* Node Styles */
.node {
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.3));
}
.node:hover {
transform: scale(1.1);
filter: drop-shadow(0 0 15px currentColor);
}
.node.selected {
transform: scale(1.15);
filter: drop-shadow(0 0 20px currentColor);
}
.node-circle {
stroke-width: 2;
transition: stroke-width 0.3s ease;
}
.node:hover .node-circle {
stroke-width: 3;
}
.node-text {
font-size: 12px;
font-weight: 600;
text-anchor: middle;
pointer-events: none;
user-select: none;
}
.node-subtext {
font-size: 10px;
fill: #94a3b8;
text-anchor: middle;
pointer-events: none;
}
/* Connection Styles */
.connection {
fill: none;
stroke: #475569;
stroke-width: 2;
cursor: pointer;
transition: all 0.3s ease;
}
.connection:hover {
stroke: #60a5fa;
stroke-width: 3;
}
.connection.highlighted {
stroke: #818cf8;
stroke-width: 3;
filter: drop-shadow(0 0 5px #818cf8);
}
/* Subnet Containers */
.subnet-container {
fill: none;
stroke: #334155;
stroke-width: 2;
stroke-dasharray: 5,5;
rx: 15;
ry: 15;
}
.subnet-label {
font-size: 14px;
font-weight: bold;
fill: #94a3b8;
text-anchor: middle;
}
/* Legend */
.legend {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(15, 23, 42, 0.8);
padding: 15px;
border-radius: 12px;
backdrop-filter: blur(10px);
border: 1px solid #334155;
font-size: 11px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
cursor: pointer;
transition: opacity 0.3s ease;
}
.legend-item:hover {
opacity: 0.8;
}
.legend-color {
width: 14px;
height: 14px;
border-radius: 50%;
border: 2px solid;
}
/* Tooltip */
.tooltip {
position: fixed;
background: rgba(15, 23, 42, 0.95);
color: #e2e8f0;
padding: 12px 16px;
border-radius: 8px;
font-size: 12px;
pointer-events: none;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease;
border: 1px solid #475569;
backdrop-filter: blur(10px);
max-width: 300px;
}
.tooltip.show {
opacity: 1;
}
/* Detail Panel */
.detail-panel {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.9);
background: rgba(15, 23, 42, 0.98);
border: 1px solid #475569;
border-radius: 16px;
padding: 30px;
min-width: 400px;
max-width: 600px;
z-index: 2000;
opacity: 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
backdrop-filter: blur(20px);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
}
.detail-panel.show {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #334155;
}
.detail-title {
font-size: 1.5em;
color: #60a5fa;
}
.close-btn {
background: none;
border: none;
color: #94a3b8;
font-size: 24px;
cursor: pointer;
transition: color 0.3s ease;
}
.close-btn:hover {
color: #e2e8f0;
}
.detail-content {
line-height: 1.6;
}
.detail-section {
margin-bottom: 20px;
}
.detail-section h3 {
color: #818cf8;
margin-bottom: 10px;
font-size: 1.1em;
}
.tag {
display: inline-block;
background: rgba(96, 165, 250, 0.2);
color: #60a5fa;
padding: 4px 10px;
border-radius: 6px;
font-size: 11px;
margin: 2px;
border: 1px solid rgba(96, 165, 250, 0.3);
}
.warning {
color: #f87171;
border-color: rgba(248, 113, 113, 0.3);
background: rgba(248, 113, 113, 0.1);
}
/* Overlay */
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 1500;
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.overlay.show {
opacity: 1;
pointer-events: all;
}
/* Animation for active nodes */
@keyframes pulse {
0% { r: 15; }
50% { r: 18; opacity: 0.7; }
100% { r: 15; }
}
.node.active .node-circle {
animation: pulse 2s infinite;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🌐 Interactive Network Topology</h1>
</div>
<div class="controls">
<button class="control-btn" onclick="resetView()">🎯 Reset View</button>
<button class="control-btn" onclick="toggleAnimation()">✨ Animate</button>
<button class="control-btn" onclick="exportSVG()">💾 Export</button>
</div>
<svg class="main-svg" id="network-svg" viewBox="0 0 1600 900">
<defs>
<!-- Gradient definitions -->
<linearGradient id="gradient-router" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#f59e0b;stop-opacity:1" />
<stop offset="100%" style="stop-color:#fbbf24;stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-core" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#ef4444;stop-opacity:1" />
<stop offset="100%" style="stop-color:#f87171;stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-infra" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#10b981;stop-opacity:1" />
<stop offset="100%" style="stop-color:#34d399;stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-worker" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#8b5cf6;stop-opacity:1" />
<stop offset="100%" style="stop-color:#a78bfa;stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-iot" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#f97316;stop-opacity:1" />
<stop offset="100%" style="stop-color:#fb923c;stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-client" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#6b7280;stop-opacity:1" />
<stop offset="100%" style="stop-color:#9ca3af;stop-opacity:1" />
</linearGradient>
<linearGradient id="gradient-dns" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#0ea5e9;stop-opacity:1" />
<stop offset="100%" style="stop-color:#38bdf8;stop-opacity:1" />
</linearGradient>
<!-- Filter for glow effects -->
<filter id="glow">
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<!-- Subnet containers -->
<rect class="subnet-container" x="50" y="200" width="1100" height="650" />
<text class="subnet-label" x="600" y="230">LAN 192.168.1.0/24</text>
<rect class="subnet-container" x="1200" y="400" width="350" height="350" />
<text class="subnet-label" x="1375" y="430">Tether_LAN_192.168.137</text>
<!-- Nodes -->
<g class="node" data-id="net" data-type="internet" transform="translate(800, 50)">
<circle class="node-circle" r="30" fill="url(#gradient-dns)" stroke="#0ea5e9" />
<text class="node-text" y="5">☁️ Internet</text>
<text class="node-subtext" y="45">5.132.33.195</text>
</g>
<g class="node" data-id="router" data-type="router" transform="translate(800, 150)">
<rect class="node-circle" x="-35" y="-20" width="70" height="40" rx="5" fill="url(#gradient-router)" stroke="#f59e0b" />
<text class="node-text" y="5">🛜 Router</text>
<text class="node-subtext" y="50">hub.lan</text>
<text class="node-subtext" y="65">192.168.1.1</text>
</g>
<!-- CORE SERVER Group -->
<g class="node-group" data-group="core">
<g class="node" data-id="traefik" data-type="core" transform="translate(200, 300)">
<circle class="node-circle" r="20" fill="url(#gradient-core)" stroke="#ef4444" />
<text class="node-text" y="25">Traefik</text>
<text class="node-subtext" y="38">Reverse Proxy</text>
</g>
<g class="node" data-id="dokku" data-type="core" transform="translate(350, 300)">
<circle class="node-circle" r="20" fill="url(#gradient-core)" stroke="#ef4444" />
<text class="node-text" y="25">Dokku PaaS</text>
</g>
<g class="node" data-id="gitea" data-type="core" transform="translate(275, 380)">
<circle class="node-circle" r="20" fill="url(#gradient-core)" stroke="#ef4444" />
<text class="node-text" y="25">Gitea</text>
<text class="node-subtext" y="38">git.appmodel.nl</text>
</g>
<g class="node" data-id="auction" data-type="core" transform="translate(150, 380)">
<circle class="node-circle" r="20" fill="url(#gradient-core)" stroke="#ef4444" />
<text class="node-text" y="25">Auction Stack</text>
<text class="node-subtext" y="38">auction.appmodel.nl</text>
</g>
<g class="node" data-id="mi50" data-type="core" transform="translate(400, 380)">
<circle class="node-circle" r="20" fill="url(#gradient-core)" stroke="#ef4444" />
<text class="node-text" y="25">MI50 / Ollama</text>
<text class="node-subtext" y="38">ollama.lan</text>
</g>
</g>
<!-- INFRA Group -->
<g class="node-group" data-group="infra">
<g class="node" data-id="xu4" data-type="infra" transform="translate(600, 320)">
<circle class="node-circle" r="25" fill="url(#gradient-infra)" stroke="#10b981" />
<text class="node-text" y="5">XU4 DNS</text>
<text class="node-subtext" y="55">192.168.1.163</text>
</g>
<g class="node" data-id="cu2" data-type="infra" transform="translate(750, 320)">
<circle class="node-circle" r="25" fill="url(#gradient-infra)" stroke="#10b981" />
<text class="node-text" y="5">C2 DNS</text>
<text class="node-subtext" y="55">192.168.1.227</text>
</g>
<g class="node" data-id="adguard" data-type="infra" transform="translate(675, 400)">
<circle class="node-circle" r="25" fill="url(#gradient-infra)" stroke="#10b981" />
<text class="node-text" y="5">AdGuard DNS</text>
</g>
</g>
<!-- Workers -->
<g class="node" data-id="atlas" data-type="worker" transform="translate(900, 320)">
<circle class="node-circle" r="25" fill="url(#gradient-worker)" stroke="#8b5cf6" />
<text class="node-text" y="5">Atlas</text>
<text class="node-subtext" y="55">192.168.1.100</text>
</g>
<g class="node" data-id="ha" data-type="infra" transform="translate(1050, 320)">
<circle class="node-circle" r="25" fill="url(#gradient-infra)" stroke="#10b981" />
<text class="node-text" y="5">Home Assistant</text>
<text class="node-subtext" y="55">192.168.1.193</text>
</g>
<!-- IoT Devices -->
<g class="node" data-id="iot_tv" data-type="iot" transform="translate(200, 550)">
<circle class="node-circle" r="20" fill="url(#gradient-iot)" stroke="#f97316" />
<text class="node-text" y="25">📺 Kamer-TV</text>
<text class="node-subtext" y="38">192.168.1.240</text>
</g>
<g class="node" data-id="iot_hue" data-type="iot" transform="translate(350, 550)">
<circle class="node-circle" r="20" fill="url(#gradient-iot)" stroke="#f97316" />
<text class="node-text" y="25">💡 Philips Hue</text>
<text class="node-subtext" y="38">192.168.1.49</text>
</g>
<g class="node" data-id="iot_eufy" data-type="iot" transform="translate(500, 550)">
<circle class="node-circle" r="20" fill="url(#gradient-iot)" stroke="#f97316" />
<text class="node-text" y="25">📹 Eufy S380HB</text>
<text class="node-subtext" y="38">192.168.1.59</text>
</g>
<g class="node" data-id="iot_misc" data-type="iot" transform="translate(650, 550)">
<circle class="node-circle" r="20" fill="url(#gradient-iot)" stroke="#f97316" />
<text class="node-text" y="25">🔌 IoT Devices</text>
<text class="node-subtext" y="38">Nest / Roborock / ESP / Printer</text>
</g>
<!-- Clients -->
<g class="node" data-id="clientMike" data-type="client" transform="translate(900, 550)">
<rect class="node-circle" x="-40" y="-20" width="80" height="40" rx="5" fill="url(#gradient-client)" stroke="#6b7280" />
<text class="node-text" y="5">💻 MIKE PC</text>
<text class="node-subtext" y="50">192.168.1.100</text>
<text class="node-subtext" y="65">LAN + Tether gateway</text>
</g>
<g class="node" data-id="clientLotte" data-type="client" transform="translate(1100, 550)">
<circle class="node-circle" r="20" fill="url(#gradient-client)" stroke="#6b7280" />
<text class="node-text" y="25">📱 Lotte</text>
<text class="node-subtext" y="38">192.168.1.133</text>
</g>
<!-- Tether Subnet -->
<g class="node" data-id="hermes" data-type="worker" transform="translate(1300, 500)">
<circle class="node-circle" r="20" fill="url(#gradient-worker)" stroke="#8b5cf6" />
<text class="node-text" y="25">Hermes</text>
<text class="node-subtext" y="38">192.168.137.239</text>
</g>
<g class="node" data-id="plato" data-type="worker" transform="translate(1450, 500)">
<circle class="node-circle" r="20" fill="url(#gradient-worker)" stroke="#8b5cf6" />
<text class="node-text" y="25">Plato</text>
<text class="node-subtext" y="38">192.168.137.239</text>
<text class="node-subtext" y="51">llm.plato.lan</text>
</g>
<!-- Connections -->
<g id="connections">
<!-- Main connections -->
<path class="connection" d="M 800 80 L 800 130" marker-end="url(#arrowhead)" />
<path class="connection" d="M 800 190 Q 500 250 200 300" />
<path class="connection" d="M 800 190 Q 700 250 600 320" />
<path class="connection" d="M 800 190 Q 850 250 900 320" />
<path class="connection" d="M 800 190 Q 950 250 1050 320" />
<path class="connection" d="M 800 190 Q 500 400 200 550" />
<path class="connection" d="M 800 190 Q 600 400 350 550" />
<path class="connection" d="M 800 190 Q 700 400 500 550" />
<path class="connection" d="M 800 190 Q 800 400 650 550" />
<path class="connection" d="M 800 190 Q 850 400 900 550" />
<path class="connection" d="M 800 190 Q 950 400 1100 550" />
<!-- Tether bridge -->
<path class="connection" d="M 940 570 L 1300 500" stroke-dasharray="5,5" />
<!-- Internal group connections -->
<path class="connection" d="M 220 320 Q 300 320 330 320" />
<path class="connection" d="M 220 320 Q 240 350 260 380" />
<path class="connection" d="M 220 320 Q 180 350 170 380" />
<path class="connection" d="M 330 320 Q 350 350 370 380" />
<path class="connection" d="M 620 345 Q 640 360 660 375" />
<path class="connection" d="M 730 345 Q 710 360 690 375" />
</g>
<!-- Marker definition for arrows -->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#475569" />
</marker>
</defs>
</svg>
<div class="legend">
<div class="legend-item" data-type="internet">
<div class="legend-color" style="border-color: #0ea5e9; background: linear-gradient(135deg, #0ea5e9 0%, #38bdf8 100%);"></div>
<span>Internet/DNS</span>
</div>
<div class="legend-item" data-type="router">
<div class="legend-color" style="border-color: #f59e0b; background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%);"></div>
<span>Router</span>
</div>
<div class="legend-item" data-type="core">
<div class="legend-color" style="border-color: #ef4444; background: linear-gradient(135deg, #ef4444 0%, #f87171 100%);"></div>
<span>Core Server</span>
</div>
<div class="legend-item" data-type="infra">
<div class="legend-color" style="border-color: #10b981; background: linear-gradient(135deg, #10b981 0%, #34d399 100%);"></div>
<span>Infra/DNS</span>
</div>
<div class="legend-item" data-type="worker">
<div class="legend-color" style="border-color: #8b5cf6; background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%);"></div>
<span>Worker/Edge</span>
</div>
<div class="legend-item" data-type="iot">
<div class="legend-color" style="border-color: #f97316; background: linear-gradient(135deg, #f97316 0%, #fb923c 100%);"></div>
<span>IoT Devices</span>
</div>
<div class="legend-item" data-type="client">
<div class="legend-color" style="border-color: #6b7280; background: linear-gradient(135deg, #6b7280 0%, #9ca3af 100%);"></div>
<span>Clients</span>
</div>
</div>
</div>
<div class="tooltip" id="tooltip"></div>
<div class="overlay" id="overlay" onclick="closePanel()"></div>
<div class="detail-panel" id="detail-panel">
<div class="detail-header">
<div class="detail-title" id="detail-title">Node Details</div>
<button class="close-btn" onclick="closePanel()">×</button>
</div>
<div class="detail-content" id="detail-content"></div>
</div>
<script>
const networkData = {
net: { name: 'Internet / Cloudflare DNS', ip: '5.132.33.195', type: 'internet', desc: 'External network and DNS provider' },
router: { name: 'Zyxel VMG8825-T50', ip: '192.168.1.1', hostname: 'hub.lan', type: 'router', desc: 'Main gateway router' },
// Core Server Group
traefik: { name: 'Traefik', type: 'core', desc: 'Reverse Proxy', services: ['Reverse Proxy', 'Load Balancer'] },
dokku: { name: 'Dokku PaaS', type: 'core', desc: 'Platform as a Service', services: ['Docker Management', 'App Deployment'] },
gitea: { name: 'Gitea', ip: '192.168.1.159', type: 'core', desc: 'Self-hosted Git service', hostname: 'git.appmodel.nl' },
auction: { name: 'Auction Stack', ip: '192.168.1.159', type: 'core', desc: 'Auction application', hostname: 'auction.appmodel.nl' },
mi50: { name: 'MI50 / Ollama', ip: '192.168.1.159', type: 'core', desc: 'AI/ML inference server', hostname: 'ollama.lan' },
// Infra Group
xu4: { name: 'XU4 DNS', ip: '192.168.1.163', type: 'infra', desc: 'Primary DNS server (Odroid XU4)', services: ['DNS', 'Pi-hole/AdGuard'] },
cu2: { name: 'C2 DNS', ip: '192.168.1.227', type: 'infra', desc: 'Secondary DNS server (Odroid C2)', services: ['DNS'] },
adguard: { name: 'AdGuard DNS', type: 'infra', desc: 'Network-wide ad blocking', services: ['DNS Filtering', 'Ad Blocking'] },
// Workers
atlas: { name: 'Atlas', ip: '192.168.1.100', type: 'worker', desc: 'Worker node', services: ['Docker', 'Portainer'] },
ha: { name: 'Home Assistant', ip: '192.168.1.193', type: 'infra', desc: 'Home automation platform', services: ['Automation', 'IoT Control'] },
// IoT Devices
iot_tv: { name: 'Kamer-TV', ip: '192.168.1.240', type: 'iot', desc: 'Chromecast/Smart TV', device: 'Smart TV' },
iot_hue: { name: 'Philips Hue', ip: '192.168.1.49', type: 'iot', desc: 'Smart lighting bridge' },
iot_eufy: { name: 'Eufy S380HB', ip: '192.168.1.59', type: 'iot', desc: 'Security camera', device: 'Beveiligingscamera' },
iot_misc: { name: 'IoT Devices', type: 'iot', desc: 'Various IoT devices', devices: ['Nest Mini', 'Roborock Vacuum', 'ESP devices', 'HP Printer'] },
// Clients
clientMike: { name: 'MIKE PC', ip: '192.168.1.100', type: 'client', desc: 'Workstation with tether gateway', interfaces: ['LAN', 'Tether Bridge'] },
clientLotte: { name: 'Lotte', ip: '192.168.1.133', type: 'client', desc: 'Mobile device' },
// Tether
hermes: { name: 'Hermes', ip: '192.168.137.239', type: 'worker', desc: 'Tether network node' },
plato: { name: 'Plato', ip: '192.168.137.239', type: 'worker', desc: 'LLM server', hostname: 'llm.plato.lan' }
};
let selectedNode = null;
let isAnimating = true;
let svgPanZoom;
// Initialize
document.addEventListener('DOMContentLoaded', function() {
initializeSVG();
setupEventListeners();
startAnimation();
});
function initializeSVG() {
const svg = document.getElementById('network-svg');
// Add pan and zoom
svgPanZoom = svgPanZoomInstance(svg, {
zoomEnabled: true,
controlIconsEnabled: false,
fit: true,
center: true,
minZoom: 0.5,
maxZoom: 3
});
}
function setupEventListeners() {
// Node click events
document.querySelectorAll('.node').forEach(node => {
node.addEventListener('click', (e) => {
e.stopPropagation();
const nodeId = node.dataset.id;
selectNode(nodeId);
});
node.addEventListener('mouseenter', (e) => {
const nodeId = node.dataset.id;
const data = networkData[nodeId];
showTooltip(e, data);
highlightConnections(nodeId);
});
node.addEventListener('mouseleave', () => {
hideTooltip();
unhighlightConnections();
});
});
// Legend interactions
document.querySelectorAll('.legend-item').forEach(item => {
item.addEventListener('click', () => {
const type = item.dataset.type;
toggleNodeType(type);
});
});
// Connection hover
document.querySelectorAll('.connection').forEach(conn => {
conn.addEventListener('mouseenter', (e) => {
conn.classList.add('highlighted');
});
conn.addEventListener('mouseleave', (e) => {
conn.classList.remove('highlighted');
});
});
}
function selectNode(nodeId) {
// Remove previous selection
document.querySelectorAll('.node').forEach(n => n.classList.remove('selected'));
// Select new node
const node = document.querySelector(`[data-id="${nodeId}"]`);
if (node) {
node.classList.add('selected');
selectedNode = nodeId;
showDetailPanel(nodeId);
}
}
function showTooltip(event, data) {
const tooltip = document.getElementById('tooltip');
const services = data.services ? data.services.join(', ') : '';
const devices = data.devices ? data.devices.join(', ') : '';
tooltip.innerHTML = `
<strong>${data.name}</strong><br>
${data.ip ? `IP: ${data.ip}<br>` : ''}
${data.hostname ? `Host: ${data.hostname}<br>` : ''}
${data.desc ? `${data.desc}<br>` : ''}
${services ? `<small>Services: ${services}</small><br>` : ''}
${devices ? `<small>Devices: ${devices}</small>` : ''}
`;
tooltip.style.left = event.clientX + 15 + 'px';
tooltip.style.top = event.clientY - 10 + 'px';
tooltip.classList.add('show');
}
function hideTooltip() {
document.getElementById('tooltip').classList.remove('show');
}
function highlightConnections(nodeId) {
// This would parse the diagram to highlight related connections
// For simplicity, we'll just highlight all connections temporarily
document.querySelectorAll('.connection').forEach(conn => {
conn.style.stroke = '#60a5fa';
conn.style.strokeWidth = '3';
});
}
function unhighlightConnections() {
document.querySelectorAll('.connection').forEach(conn => {
conn.style.stroke = '';
conn.style.strokeWidth = '';
});
}
function showDetailPanel(nodeId) {
const data = networkData[nodeId];
const panel = document.getElementById('detail-panel');
const overlay = document.getElementById('overlay');
const title = document.getElementById('detail-title');
const content = document.getElementById('detail-content');
title.textContent = data.name;
let html = `
<div class="detail-section">
<p>${data.desc || 'No description available'}</p>
</div>
`;
if (data.ip) {
html += `
<div class="detail-section">
<h3>📡 Network Information</h3>
<div><strong>IP Address:</strong> <code class="tag">${data.ip}</code></div>
${data.hostname ? `<div><strong>Hostname:</strong> <code class="tag">${data.hostname}</code></div>` : ''}
</div>
`;
}
if (data.services) {
html += `
<div class="detail-section">
<h3>🚀 Services</h3>
${data.services.map(s => `<span class="tag">${s}</span>`).join('')}
</div>
`;
}
if (data.interfaces) {
html += `
<div class="detail-section">
<h3>🔌 Interfaces</h3>
${data.interfaces.map(i => `<span class="tag">${i}</span>`).join('')}
</div>
`;
}
if (data.devices) {
html += `
<div class="detail-section">
<h3>📱 Sub-Devices</h3>
${data.devices.map(d => `<span class="tag">${d}</span>`).join('')}
</div>
`;
}
// Add related connections
html += `
<div class="detail-section">
<h3>🔗 Connections</h3>
<p style="color: #94a3b8; font-size: 0.9em;">
Click on connections in the diagram to see details
</p>
</div>
`;
content.innerHTML = html;
overlay.classList.add('show');
panel.classList.add('show');
}
function closePanel() {
document.getElementById('overlay').classList.remove('show');
document.getElementById('detail-panel').classList.remove('show');
document.querySelectorAll('.node').forEach(n => n.classList.remove('selected'));
selectedNode = null;
}
function toggleNodeType(type) {
document.querySelectorAll(`.node[data-type="${type}"]`).forEach(node => {
const isVisible = node.style.display !== 'none';
node.style.display = isVisible ? 'none' : 'block';
node.style.opacity = isVisible ? '0' : '1';
});
}
function resetView() {
svgPanZoom.reset();
closePanel();
}
function toggleAnimation() {
isAnimating = !isAnimating;
if (isAnimating) {
startAnimation();
} else {
stopAnimation();
}
}
function startAnimation() {
document.querySelectorAll('.node[data-type="core"], .node[data-type="infra"]').forEach(node => {
node.classList.add('active');
});
}
function stopAnimation() {
document.querySelectorAll('.node').forEach(node => {
node.classList.remove('active');
});
}
function exportSVG() {
const svg = document.getElementById('network-svg');
const svgData = new XMLSerializer().serializeToString(svg);
const blob = new Blob([svgData], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'network-topology.svg';
a.click();
URL.revokeObjectURL(url);
}
// Simple pan/zoom implementation (if you don't want to use a library)
function svgPanZoomInstance(svg, options) {
let isPanning = false;
let startPoint = { x: 0, y: 0 };
let startTranslate = { x: 0, y: 0 };
let scale = 1;
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
g.id = 'pan-zoom-group';
while (svg.firstChild) {
g.appendChild(svg.firstChild);
}
svg.appendChild(g);
svg.addEventListener('mousedown', (e) => {
if (e.target === svg || e.target.tagName === 'path') {
isPanning = true;
startPoint = { x: e.clientX, y: e.clientY };
const transform = g.getAttribute('transform') || '';
const matches = transform.match(/translate\(([^,]+),([^)]+)\)/);
if (matches) {
startTranslate = { x: parseFloat(matches[1]), y: parseFloat(matches[2]) };
}
svg.style.cursor = 'grabbing';
}
});
svg.addEventListener('mousemove', (e) => {
if (!isPanning) return;
const dx = e.clientX - startPoint.x;
const dy = e.clientY - startPoint.y;
const newX = startTranslate.x + dx;
const newY = startTranslate.y + dy;
updateTransform(newX, newY, scale);
});
svg.addEventListener('mouseup', () => {
isPanning = false;
svg.style.cursor = 'grab';
});
svg.addEventListener('wheel', (e) => {
e.preventDefault();
const delta = e.deltaY > 0 ? 0.9 : 1.1;
scale = Math.max(options.minZoom, Math.min(options.maxZoom, scale * delta));
updateTransform(0, 0, scale);
});
function updateTransform(x, y, s) {
g.setAttribute('transform', `translate(${x},${y}) scale(${s})`);
}
return {
reset: () => {
scale = 1;
updateTransform(0, 0, 1);
}
};
}
</script>
</body>
</html>

View File

@@ -1,780 +0,0 @@
{
"discovery_time": "2025-12-07T16:06:45.539721",
"total_devices": 76,
"networks_scanned": [
"192.168.1.0/24",
"192.168.137.1/24",
"172.20.240.1/20",
"192.168.137.0/24",
"192.168.1.100/24",
"192.168.137.100/24"
],
"devices": [
{
"ip": "192.168.1.1",
"hostname": "192.168.1.1",
"mac": "b8:d5:26:d2:7d:c0",
"open_ports": [
5000
],
"type": "router",
"icon": "\ud83d\udedc",
"last_seen": "2025-12-07T15:52:09.705400"
},
{
"ip": "192.168.1.10",
"hostname": "192.168.1.10",
"mac": "40:9f:38:1c:1f:01",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:52:09.705400"
},
{
"ip": "192.168.1.49",
"hostname": "192.168.1.49",
"mac": "ec:b5:fa:a5:6c:90",
"open_ports": [
443,
80,
8080
],
"type": "server",
"icon": "\ud83d\udcbb",
"last_seen": "2025-12-07T15:52:22.062446"
},
{
"ip": "192.168.1.44",
"hostname": "192.168.1.44",
"mac": "48:27:e2:d4:d9:54",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:52:22.157183"
},
{
"ip": "192.168.1.59",
"hostname": "192.168.1.59",
"mac": "04:17:b6:82:05:1a",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:52:24.079670"
},
{
"ip": "192.168.1.65",
"hostname": "192.168.1.65",
"mac": "ea:e7:a7:88:43:e1",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:52:34.995741"
},
{
"ip": "192.168.1.100",
"hostname": "host.docker.internal",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:52:36.610550"
},
{
"ip": "192.168.1.102",
"hostname": "192.168.1.102",
"mac": "cc:f4:11:cd:76:50",
"open_ports": [
8008,
8443
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:52:47.145897"
},
{
"ip": "192.168.1.136",
"hostname": "192.168.1.136",
"mac": "b0:4a:39:58:ed:6a",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:52:58.676214"
},
{
"ip": "192.168.1.159",
"hostname": "git.appmodel.nl",
"mac": "50:eb:f6:2a:98:30",
"open_ports": [
80,
8080,
443,
22,
3000
],
"type": "server",
"icon": "\ud83d\udcbb",
"last_seen": "2025-12-07T15:53:00.598585"
},
{
"ip": "192.168.1.151",
"hostname": "192.168.1.151",
"mac": "34:cd:b0:2b:d9:a0",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:53:10.286185"
},
{
"ip": "192.168.1.163",
"hostname": "192.168.1.163",
"mac": "00:1e:06:31:b1:27",
"open_ports": [
22,
8000,
8080
],
"type": "dns",
"icon": "\ud83d\udee1\ufe0f",
"last_seen": "2025-12-07T15:53:31.910265"
},
{
"ip": "192.168.1.165",
"hostname": "HP678531.home",
"mac": "48:ba:4e:67:85:32",
"open_ports": [
80,
443,
8080
],
"type": "server",
"icon": "\ud83d\udcbb",
"last_seen": "2025-12-07T15:53:32.065413"
},
{
"ip": "192.168.1.193",
"hostname": "homeassistant",
"mac": "e4:b9:7a:9f:3b:5f",
"open_ports": [],
"type": "home_automation",
"icon": "\ud83c\udfe1",
"last_seen": "2025-12-07T15:53:54.643647"
},
{
"ip": "192.168.1.206",
"hostname": "192.168.1.206",
"mac": "7c:df:a1:54:d4:fc",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:54:16.332734"
},
{
"ip": "192.168.1.214",
"hostname": "192.168.1.214",
"mac": "10:7b:44:30:a0:b9",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:54:17.164333"
},
{
"ip": "192.168.1.240",
"hostname": "192.168.1.240",
"mac": "4c:49:29:7d:bc:e4",
"open_ports": [
8443,
8008
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:54:39.613611"
},
{
"ip": "192.168.1.243",
"hostname": "192.168.1.243",
"mac": "ac:67:84:61:90:d9",
"open_ports": [
8443,
8008
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:55:01.218760"
},
{
"ip": "192.168.137.1",
"hostname": "MI",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:55:02.284598"
},
{
"ip": "192.168.137.100",
"hostname": "MI",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:55:11.113935"
},
{
"ip": "192.168.137.239",
"hostname": "192.168.137.239",
"mac": "18:31:bf:4e:d7:8a",
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:55:41.136168"
},
{
"ip": "172.20.240.1",
"hostname": "MI.mshome.net",
"mac": null,
"open_ports": [
22
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:55:46.119130"
},
{
"ip": "192.168.137.1",
"hostname": "MI",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:55:49.126499"
},
{
"ip": "192.168.137.3",
"hostname": "192.168.137.3",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:56:09.203344"
},
{
"ip": "192.168.137.13",
"hostname": "192.168.137.13",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:56:10.560591"
},
{
"ip": "192.168.137.35",
"hostname": "192.168.137.35",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:56:32.787426"
},
{
"ip": "192.168.137.61",
"hostname": "192.168.137.61",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:56:55.788256"
},
{
"ip": "192.168.137.72",
"hostname": "192.168.137.72",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:56:56.768989"
},
{
"ip": "192.168.137.100",
"hostname": "MI",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:56:58.613419"
},
{
"ip": "192.168.137.102",
"hostname": "192.168.137.102",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:57:19.952047"
},
{
"ip": "192.168.137.114",
"hostname": "192.168.137.114",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:57:20.802691"
},
{
"ip": "192.168.137.137",
"hostname": "192.168.137.137",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:57:42.904414"
},
{
"ip": "192.168.137.161",
"hostname": "192.168.137.161",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:58:05.741701"
},
{
"ip": "192.168.137.172",
"hostname": "192.168.137.172",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:58:06.758378"
},
{
"ip": "192.168.137.203",
"hostname": "192.168.137.203",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:58:29.845884"
},
{
"ip": "192.168.137.217",
"hostname": "192.168.137.217",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:58:30.827941"
},
{
"ip": "192.168.137.239",
"hostname": "hermes.lan",
"mac": "18:31:bf:4e:d7:8a",
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:58:48.627302"
},
{
"ip": "192.168.137.244",
"hostname": "192.168.137.244",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T15:59:09.825882"
},
{
"ip": "192.168.1.10",
"hostname": "192.168.1.10",
"mac": "40:9f:38:1c:1f:01",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:59:31.412126"
},
{
"ip": "192.168.1.1",
"hostname": "192.168.1.1",
"mac": "b8:d5:26:d2:7d:c0",
"open_ports": [
5000
],
"type": "router",
"icon": "\ud83d\udedc",
"last_seen": "2025-12-07T15:59:31.412126"
},
{
"ip": "192.168.1.49",
"hostname": "192.168.1.49",
"mac": "ec:b5:fa:a5:6c:90",
"open_ports": [
8080,
80,
443
],
"type": "server",
"icon": "\ud83d\udcbb",
"last_seen": "2025-12-07T15:59:54.631041"
},
{
"ip": "192.168.1.44",
"hostname": "192.168.1.44",
"mac": "48:27:e2:d4:d9:54",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:59:54.769952"
},
{
"ip": "192.168.1.42",
"hostname": "192.168.1.42",
"mac": "38:2c:e5:45:be:3c",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:59:54.884149"
},
{
"ip": "192.168.1.59",
"hostname": "192.168.1.59",
"mac": "04:17:b6:82:05:1a",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T15:59:56.630244"
},
{
"ip": "192.168.1.65",
"hostname": "192.168.1.65",
"mac": "ea:e7:a7:88:43:e1",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:00:18.468155"
},
{
"ip": "192.168.1.100",
"hostname": "host.docker.internal",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:00:20.098760"
},
{
"ip": "192.168.1.93",
"hostname": "192.168.1.93",
"mac": "fe:67:72:c1:c9:8c",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:00:41.565323"
},
{
"ip": "192.168.1.102",
"hostname": "192.168.1.102",
"mac": "cc:f4:11:cd:76:50",
"open_ports": [
8443,
8008
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:01:03.168820"
},
{
"ip": "192.168.1.136",
"hostname": "192.168.1.136",
"mac": "b0:4a:39:58:ed:6a",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:01:25.683522"
},
{
"ip": "192.168.1.159",
"hostname": "git.appmodel.nl",
"mac": "50:eb:f6:2a:98:30",
"open_ports": [
80,
443,
3000,
8080,
22
],
"type": "server",
"icon": "\ud83d\udcbb",
"last_seen": "2025-12-07T16:01:27.603014"
},
{
"ip": "192.168.1.151",
"hostname": "192.168.1.151",
"mac": "34:cd:b0:2b:d9:a0",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:01:48.219580"
},
{
"ip": "192.168.1.163",
"hostname": "192.168.1.163",
"mac": "00:1e:06:31:b1:27",
"open_ports": [
22,
8080,
8000
],
"type": "dns",
"icon": "\ud83d\udee1\ufe0f",
"last_seen": "2025-12-07T16:02:09.802235"
},
{
"ip": "192.168.1.161",
"hostname": "192.168.1.161",
"mac": "4c:ba:d7:a6:c1:8c",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:02:09.802870"
},
{
"ip": "192.168.1.165",
"hostname": "HP678531.home",
"mac": "48:ba:4e:67:85:32",
"open_ports": [
443,
80,
8080
],
"type": "server",
"icon": "\ud83d\udcbb",
"last_seen": "2025-12-07T16:02:09.817569"
},
{
"ip": "192.168.1.190",
"hostname": "192.168.1.190",
"mac": "c8:c9:a3:60:0f:9d",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:02:31.453384"
},
{
"ip": "192.168.1.193",
"hostname": "homeassistant",
"mac": "e4:b9:7a:9f:3b:5f",
"open_ports": [],
"type": "home_automation",
"icon": "\ud83c\udfe1",
"last_seen": "2025-12-07T16:02:32.140000"
},
{
"ip": "192.168.1.206",
"hostname": "192.168.1.206",
"mac": "7c:df:a1:54:d4:fc",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:02:53.865089"
},
{
"ip": "192.168.1.214",
"hostname": "192.168.1.214",
"mac": "10:7b:44:30:a0:b9",
"open_ports": [],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:02:54.661758"
},
{
"ip": "192.168.1.240",
"hostname": "192.168.1.240",
"mac": "4c:49:29:7d:bc:e4",
"open_ports": [
8443,
8008
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:03:17.131184"
},
{
"ip": "192.168.1.243",
"hostname": "192.168.1.243",
"mac": "ac:67:84:61:90:d9",
"open_ports": [
8443,
8008
],
"type": "unknown",
"icon": "\u2753",
"last_seen": "2025-12-07T16:03:38.896155"
},
{
"ip": "192.168.137.1",
"hostname": "MI",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:03:39.964337"
},
{
"ip": "192.168.137.5",
"hostname": "192.168.137.5",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:00.058709"
},
{
"ip": "192.168.137.11",
"hostname": "192.168.137.11",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:00.737328"
},
{
"ip": "192.168.137.46",
"hostname": "192.168.137.46",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:23.792363"
},
{
"ip": "192.168.137.53",
"hostname": "192.168.137.53",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:24.722390"
},
{
"ip": "192.168.137.100",
"hostname": "MI",
"mac": null,
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:29.581053"
},
{
"ip": "192.168.137.82",
"hostname": "192.168.137.82",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:47.713917"
},
{
"ip": "192.168.137.91",
"hostname": "192.168.137.91",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:04:49.066341"
},
{
"ip": "192.168.137.116",
"hostname": "192.168.137.116",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:05:11.425890"
},
{
"ip": "192.168.137.142",
"hostname": "192.168.137.142",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:05:34.246370"
},
{
"ip": "192.168.137.156",
"hostname": "192.168.137.156",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:05:35.568531"
},
{
"ip": "192.168.137.174",
"hostname": "192.168.137.174",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:05:57.866182"
},
{
"ip": "192.168.137.206",
"hostname": "192.168.137.206",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:06:20.912642"
},
{
"ip": "192.168.137.215",
"hostname": "192.168.137.215",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:06:21.781321"
},
{
"ip": "192.168.137.239",
"hostname": "hermes.lan",
"mac": "18:31:bf:4e:d7:8a",
"open_ports": [
22
],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:06:39.618322"
},
{
"ip": "192.168.137.233",
"hostname": "192.168.137.233",
"mac": null,
"open_ports": [],
"type": "worker",
"icon": "\ud83d\udef0\ufe0f",
"last_seen": "2025-12-07T16:06:43.724109"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
============================================================
NETWORK DISCOVERY SUMMARY
============================================================
Discovery Time: 2025-12-07 16:06:45
Total Devices Found: 76
Devices by Type:
----------------------------------------

View File

@@ -1,9 +0,0 @@
============================================================
NETWORK DISCOVERY SUMMARY
============================================================
Discovery Time: 2025-12-07 16:35:12
Total Devices Found: 96
Devices by Type:
----------------------------------------

View File

@@ -1,172 +0,0 @@
flowchart TD
%% ---------- styles ----------
classDef internet fill:#e1f5ff,stroke:#007bff
classDef router fill:#fff3cd,stroke:#ffc107
classDef server fill:#ffe6e6,stroke:#dc3545
classDef dns fill:#e6ffe6,stroke:#28a745
classDef homeauto fill:#fff0f5,stroke:#e83e8c
classDef worker fill:#f0e6ff,stroke:#6f42c1
classDef iot fill:#fff9e6,stroke:#fd7e14
classDef unknown fill:#f8f9fa,stroke:#6c757d
subgraph LAN["LAN 192.168.1.0/24 - 40 devices"]
subgraph CORE["Core Infrastructure"]
192_168_1_1["[Router] 192.168.1.1<br/>192.168.1.1"]
class 192_168_1_1 router;
192_168_1_49["[Server] 192.168.1.49<br/>192.168.1.49"]
class 192_168_1_49 server;
192_168_1_100["[Worker] host.docker.internal<br/>192.168.1.100"]
class 192_168_1_100 worker;
192_168_1_159["[Server] git.appmodel.nl<br/>192.168.1.159"]
class 192_168_1_159 server;
192_168_1_163["[DNS] 192.168.1.163<br/>192.168.1.163"]
class 192_168_1_163 dns;
192_168_1_165["[Server] HP678531.home<br/>192.168.1.165"]
class 192_168_1_165 server;
192_168_1_193["[Home] homeassistant<br/>192.168.1.193"]
class 192_168_1_193 homeauto;
192_168_1_1["[Router] 192.168.1.1<br/>192.168.1.1"]
class 192_168_1_1 router;
192_168_1_49["[Server] 192.168.1.49<br/>192.168.1.49"]
class 192_168_1_49 server;
192_168_1_100["[Worker] host.docker.internal<br/>192.168.1.100"]
class 192_168_1_100 worker;
192_168_1_159["[Server] git.appmodel.nl<br/>192.168.1.159"]
class 192_168_1_159 server;
192_168_1_163["[DNS] 192.168.1.163<br/>192.168.1.163"]
class 192_168_1_163 dns;
192_168_1_165["[Server] HP678531.home<br/>192.168.1.165"]
class 192_168_1_165 server;
192_168_1_193["[Home] homeassistant<br/>192.168.1.193"]
class 192_168_1_193 homeauto;
end
192_168_1_10["[?] 192.168.1.10<br/>192.168.1.10"]
class 192_168_1_10 unknown;
192_168_1_44["[?] 192.168.1.44<br/>192.168.1.44"]
class 192_168_1_44 unknown;
192_168_1_59["[?] 192.168.1.59<br/>192.168.1.59"]
class 192_168_1_59 unknown;
192_168_1_65["[?] 192.168.1.65<br/>192.168.1.65"]
class 192_168_1_65 unknown;
192_168_1_102["[?] 192.168.1.102<br/>192.168.1.102"]
class 192_168_1_102 unknown;
192_168_1_136["[?] 192.168.1.136<br/>192.168.1.136"]
class 192_168_1_136 unknown;
192_168_1_151["[?] 192.168.1.151<br/>192.168.1.151"]
class 192_168_1_151 unknown;
192_168_1_206["[?] 192.168.1.206<br/>192.168.1.206"]
class 192_168_1_206 unknown;
192_168_1_214["[?] 192.168.1.214<br/>192.168.1.214"]
class 192_168_1_214 unknown;
192_168_1_240["[?] 192.168.1.240<br/>192.168.1.240"]
class 192_168_1_240 unknown;
192_168_1_243["[?] 192.168.1.243<br/>192.168.1.243"]
class 192_168_1_243 unknown;
192_168_1_10["[?] 192.168.1.10<br/>192.168.1.10"]
class 192_168_1_10 unknown;
192_168_1_44["[?] 192.168.1.44<br/>192.168.1.44"]
class 192_168_1_44 unknown;
192_168_1_42["[?] 192.168.1.42<br/>192.168.1.42"]
class 192_168_1_42 unknown;
192_168_1_59["[?] 192.168.1.59<br/>192.168.1.59"]
class 192_168_1_59 unknown;
192_168_1_65["[?] 192.168.1.65<br/>192.168.1.65"]
class 192_168_1_65 unknown;
192_168_1_93["[?] 192.168.1.93<br/>192.168.1.93"]
class 192_168_1_93 unknown;
192_168_1_102["[?] 192.168.1.102<br/>192.168.1.102"]
class 192_168_1_102 unknown;
192_168_1_136["[?] 192.168.1.136<br/>192.168.1.136"]
class 192_168_1_136 unknown;
192_168_1_151["[?] 192.168.1.151<br/>192.168.1.151"]
class 192_168_1_151 unknown;
192_168_1_161["[?] 192.168.1.161<br/>192.168.1.161"]
class 192_168_1_161 unknown;
192_168_1_190["[?] 192.168.1.190<br/>192.168.1.190"]
class 192_168_1_190 unknown;
192_168_1_206["[?] 192.168.1.206<br/>192.168.1.206"]
class 192_168_1_206 unknown;
192_168_1_214["[?] 192.168.1.214<br/>192.168.1.214"]
class 192_168_1_214 unknown;
192_168_1_240["[?] 192.168.1.240<br/>192.168.1.240"]
class 192_168_1_240 unknown;
192_168_1_243["[?] 192.168.1.243<br/>192.168.1.243"]
class 192_168_1_243 unknown;
end
subgraph TETHER["Tether 192.168.137.0/24 - 35 devices"]
192_168_137_1["[Worker] MI<br/>192.168.137.1"]
class 192_168_137_1 worker;
192_168_137_100["[Worker] MI<br/>192.168.137.100"]
class 192_168_137_100 worker;
192_168_137_239["[Hermes] 192.168.137.239<br/>192.168.137.239"]
class 192_168_137_239 worker;
192_168_137_1["[Worker] MI<br/>192.168.137.1"]
class 192_168_137_1 worker;
192_168_137_3["[Worker] 192.168.137.3<br/>192.168.137.3"]
class 192_168_137_3 worker;
192_168_137_13["[Worker] 192.168.137.13<br/>192.168.137.13"]
class 192_168_137_13 worker;
192_168_137_35["[Worker] 192.168.137.35<br/>192.168.137.35"]
class 192_168_137_35 worker;
192_168_137_61["[Worker] 192.168.137.61<br/>192.168.137.61"]
class 192_168_137_61 worker;
192_168_137_72["[Worker] 192.168.137.72<br/>192.168.137.72"]
class 192_168_137_72 worker;
192_168_137_100["[Worker] MI<br/>192.168.137.100"]
class 192_168_137_100 worker;
192_168_137_102["[Worker] 192.168.137.102<br/>192.168.137.102"]
class 192_168_137_102 worker;
192_168_137_114["[Worker] 192.168.137.114<br/>192.168.137.114"]
class 192_168_137_114 worker;
192_168_137_137["[Worker] 192.168.137.137<br/>192.168.137.137"]
class 192_168_137_137 worker;
192_168_137_161["[Worker] 192.168.137.161<br/>192.168.137.161"]
class 192_168_137_161 worker;
192_168_137_172["[Worker] 192.168.137.172<br/>192.168.137.172"]
class 192_168_137_172 worker;
192_168_137_203["[Worker] 192.168.137.203<br/>192.168.137.203"]
class 192_168_137_203 worker;
192_168_137_217["[Worker] 192.168.137.217<br/>192.168.137.217"]
class 192_168_137_217 worker;
192_168_137_239["[Hermes] hermes.lan<br/>192.168.137.239"]
class 192_168_137_239 worker;
192_168_137_244["[Worker] 192.168.137.244<br/>192.168.137.244"]
class 192_168_137_244 worker;
192_168_137_1["[Worker] MI<br/>192.168.137.1"]
class 192_168_137_1 worker;
192_168_137_5["[Worker] 192.168.137.5<br/>192.168.137.5"]
class 192_168_137_5 worker;
192_168_137_11["[Worker] 192.168.137.11<br/>192.168.137.11"]
class 192_168_137_11 worker;
192_168_137_46["[Worker] 192.168.137.46<br/>192.168.137.46"]
class 192_168_137_46 worker;
192_168_137_53["[Worker] 192.168.137.53<br/>192.168.137.53"]
class 192_168_137_53 worker;
192_168_137_100["[Worker] MI<br/>192.168.137.100"]
class 192_168_137_100 worker;
192_168_137_82["[Worker] 192.168.137.82<br/>192.168.137.82"]
class 192_168_137_82 worker;
192_168_137_91["[Worker] 192.168.137.91<br/>192.168.137.91"]
class 192_168_137_91 worker;
192_168_137_116["[Worker] 192.168.137.116<br/>192.168.137.116"]
class 192_168_137_116 worker;
192_168_137_142["[Worker] 192.168.137.142<br/>192.168.137.142"]
class 192_168_137_142 worker;
192_168_137_156["[Worker] 192.168.137.156<br/>192.168.137.156"]
class 192_168_137_156 worker;
192_168_137_174["[Worker] 192.168.137.174<br/>192.168.137.174"]
class 192_168_137_174 worker;
192_168_137_206["[Worker] 192.168.137.206<br/>192.168.137.206"]
class 192_168_137_206 worker;
192_168_137_215["[Worker] 192.168.137.215<br/>192.168.137.215"]
class 192_168_137_215 worker;
192_168_137_239["[Hermes] hermes.lan<br/>192.168.137.239"]
class 192_168_137_239 worker;
192_168_137_233["[Worker] 192.168.137.233<br/>192.168.137.233"]
class 192_168_137_233 worker;
end
%% ---------- Connections ----------
192_168_1_159 -.-> TETHER
192_168_1_1 --> LAN

View File

@@ -1,14 +1,65 @@
from PIL import Image # python
from pathlib import Path
import cairosvg import cairosvg
from PIL import Image
# Convert SVG to PNG first PUBLIC = Path("./public")
png_path = "./public/img/favicon.png" PUBLIC.mkdir(parents=True, exist_ok=True)
ico_path = "./public/img/favicon.ico"
cairosvg.svg2png(url="./public/img/favicon.svg", write_to=png_path) # SVG content for `public/favicon.svg`
SVG = """<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" role="img" aria-label="App.model">
<defs>
<linearGradient id="g" x1="0" x2="1" y1="0" y2="1">
<stop offset="0" stop-color="#60a5fa"/>
<stop offset="1" stop-color="#818cf8"/>
</linearGradient>
<filter id="s" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0f172a" flood-opacity="0.6"/>
</filter>
</defs>
# Convert PNG → ICO <rect x="2" y="2" width="60" height="60" rx="12" ry="12" fill="url(#g)" filter="url(#s)"/>
img = Image.open(png_path)
img.save(ico_path, format='ICO', sizes=[(32,32),(16,16), (48,48), (64,64)])
ico_path <g transform="translate(32,34) scale(0.9)">
<path d="M-12,-8 L0,-22 L12,-8 Z" fill="#0f172a" opacity="0.95"/>
<rect x="-10" y="-8" width="20" height="16" rx="3" ry="3" fill="#0f172a" opacity="0.95"/>
<rect x="-3" y="0" width="6" height="8" rx="1" ry="1" fill="#60a5fa"/>
<circle cx="10" cy="-4" r="3" fill="#fbbf24" stroke="#fff5" stroke-width="0.6"/>
</g>
</svg>
"""
svg_path = PUBLIC / "favicon.svg"
svg_path.write_text(SVG, encoding="utf-8")
# Render a high-resolution source PNG (256x256) from the SVG
base_png = PUBLIC / "favicon-256.png"
cairosvg.svg2png(url=str(svg_path), write_to=str(base_png), output_width=256, output_height=256)
# Produce PNG icons at required sizes
sizes_and_names = [
(32, PUBLIC / "favicon-32x32.png"),
(16, PUBLIC / "favicon-16x16.png"),
(180, PUBLIC / "apple-touch-icon.png"),
]
with Image.open(base_png) as im:
im = im.convert("RGBA")
for size, out_path in sizes_and_names:
icon = im.resize((size, size), resample=Image.LANCZOS)
icon.save(out_path, format="PNG")
# Save multi-size ICO (source should be sufficiently large for quality)
ico_path = PUBLIC / "favicon.ico"
im.save(ico_path, format="ICO", sizes=[(16,16), (32,32), (48,48), (64,64)])
# Optionally remove the intermediate 256 PNG
# base_png.unlink()
print("Created:", *[str(p) for p in [
svg_path,
PUBLIC / "favicon-32x32.png",
PUBLIC / "favicon-16x16.png",
PUBLIC / "apple-touch-icon.png",
PUBLIC / "favicon.ico"
]])

9
src/nex.iml Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>