{"id":809,"date":"2025-08-02T15:32:38","date_gmt":"2025-08-02T15:32:38","guid":{"rendered":"https:\/\/yairmartinezcybersecurityportfolio.com\/?p=809"},"modified":"2025-12-26T22:38:59","modified_gmt":"2025-12-26T22:38:59","slug":"creating-a-nmap-dashboard","status":"publish","type":"post","link":"https:\/\/yairmartinezcybersecurityportfolio.com\/?p=809","title":{"rendered":"Creating A Nmap Dashboard"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Why I built this?<\/h2>\n\n\n\n<p>I made the Nmap Dashboard as a way to teach myself Python, not just learning the syntax, but actually using it to build something useful. I didn\u2019t want to just follow along with tutorials. I wanted to create a tool that worked, that could solve a real problem, and that would push me to figure things out as I went.<\/p>\n\n\n\n<p>It started out simple: just a basic web app to display Nmap scan results. But as I kept working on it, the project kept growing. I added more features like risk-based tagging, PDF exports, scan comparisons, undo delete, and others all because I kept asking myself \u201cwhat else can I make this do?\u201d Bit by bit, it turned into a full dashboard.<\/p>\n\n\n\n<p>I built the whole thing from scratch. It\u2019s not based on any existing project just something I wanted to figure out for myself. I developed it on a Ubuntu VM, which also gave me a chance to improve my Linux skills. Eventually, I moved it over to Docker to make it easier to use and more portable. The Docker setup is written for Linux, and that&#8217;s the environment I\u2019ve focused on the most.<\/p>\n\n\n\n<p>This project also helped me understand how things work under the hood, like managing file paths, logging system activity, and using SQL to store scan data. I wrote additional Python scripts outside the main app to help reset the database or archive scans, which I run directly from the Linux terminal. It became more than just a web app \u2014 it was a way to reinforce everything I\u2019d been learning about the OS, scripting, and backend logic.<\/p>\n\n\n\n<p>One thing I want to be transparent about is that the frontend was AI-generated, every piece of html code was generated by AI, and I also used AI throughout the project as a helping hand. Whether it was debugging tricky Python errors, thinking through logic, or getting inspired for new features, AI was a big part of how I pushed my skills further. It helped me go from basic Python knowledge to building something much more complex faster than I could\u2019ve done on my own.<\/p>\n\n\n\n<p>This project reflects a lot of learning and growth. It started as a way to get more hands-on with Flask and Python, and ended up almost as a full fledged tool I could use. I didn\u2019t expect it to turn into a full dashboard, but that&#8217;s what it transitioned into.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Demo Demonstration<\/h2>\n\n\n\n<p>This GIF shows the interface I built including scan viewing, tagging, exporting, and comparison features all wrapped in a user-friendly layout built with Flask and Python. Unfortunately I can&#8217;t share the details in depth as that would result in me exposing my network info.  <\/p>\n\n\n\n<div class=\"wp-block-stackable-image stk-block-image stk-block stk-1888cae\" data-block-id=\"1888cae\"><style>.stk-1888cae {margin-bottom:0px !important;}<\/style><figure><span class=\"stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-1324\" src=\"https:\/\/yairmartinezcybersecurityportfolio.com\/wp-content\/uploads\/2025\/08\/dashboard.gif\" width=\"1290\" height=\"645\"\/><\/span><\/figure><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Table of Content<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#key-features\">Key Features of the Nmap Dashboard<\/a><\/li>\n\n\n\n<li><a href=\"#tech-stack\">Tech Stack<\/a><\/li>\n\n\n\n<li><a href=\"#architecture-overview\">How It Works: Architecture Overview<\/a><\/li>\n\n\n\n<li><a href=\"#deep-dive-1\">Code Deep Dive 1: Smarter Parsing with Tags and Risk Scoring<\/a><\/li>\n\n\n\n<li><a href=\"#deep-dive-2\">Code Deep Dive 2: Tagging, Risk Scoring &amp; Exporting in scans.py<\/a><\/li>\n\n\n\n<li><a href=\"#deep-dive-3\">Code Deep Dive 3: Intelligent Port-by-Port Scan Diffing<\/a><\/li>\n\n\n\n<li><a href=\"#challenges\">Challenges I Faced<\/a><\/li>\n\n\n\n<li><a href=\"#lessons-learned\">What I Learned<\/a><\/li>\n\n\n\n<li><a href=\"#improvements\">Things I&#8217;d Improve Next Time<\/a><\/li>\n\n\n\n<li><a href=\"#links\">Links<\/a><\/li>\n\n\n\n<li><a href=\"#final-thoughts\">Final Thoughts<\/a><\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"key-features\">Key Features of the Nmap Dashboard<\/h2>\n\n\n\n<p>Here\u2019s what the dashboard currently supports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Clean, Searchable Scan Tables<\/strong><br>View and filter scan results in a neatly organized table \u2014 showing IPs, MAC addresses, hostnames, ports, service types, and more.<\/li>\n\n\n\n<li><strong>One-Click Scan Buttons<\/strong><br>Run tailored Nmap scans directly from the dashboard \u2014 including Inventory management, system administration and others. Each scan runs predefined Nmap flags suited for different use cases.<\/li>\n\n\n\n<li><strong>Scan Log Generation<\/strong><br>Every scan produces a log file with full terminal output, so nothing gets lost. You can view and download these logs directly from the dashboard to review Nmap&#8217;s raw output.<\/li>\n\n\n\n<li><strong>Risk-Based Tagging System<\/strong><br>Tags are auto-suggested based on port\/services detected (e.g. SSH, HTTP, Telnet). You can also manually tag devices to track vulnerabilities or group hosts by importance.<\/li>\n\n\n\n<li><strong>Scan History &amp; Comparison Tools<\/strong><br>Instantly compare two scans of the same host or network to see what changed \u2014 such as new open ports, offline hosts, or updated services.<\/li>\n\n\n\n<li><strong>ZIP Importing with Undo Delete<\/strong><br>Import archived scans from ZIP files. Accidentally deleted something? The undo preview lets you restore deleted entries safely.<\/li>\n\n\n\n<li><strong>PDF Report Exporting<\/strong><br>Turn any scan into a formatted, printable PDF that includes hosts, ports, statuses, and all applied tags.<\/li>\n\n\n\n<li><strong>Custom Scripts for Linux Terminal Use<\/strong><br>Separate Python tools allow you to:\n<ul class=\"wp-block-list\">\n<li>Reset the database<\/li>\n\n\n\n<li>Archive or restore scan sessions<br>These run outside the dashboard, directly in a Linux shell.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Docker-Ready for Linux<\/strong><br>The entire app runs in Docker (host networking) with a Linux-first setup \u2014 making it easy to deploy and portable across systems.<\/li>\n\n\n\n<li><strong>Discreet Logging System<\/strong><br>Key actions \u2014 like tag edits, deletions, or file imports \u2014 are quietly logged in the background to a log file.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"tech-stack\">Tech Stack<\/h2>\n\n\n\n<p>These are the main technologies and tools behind the Nmap Dashboard:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Python<\/strong> \u2013 Core programming language used to handle logic, data parsing, scan control, and backend processes.<\/li>\n\n\n\n<li><strong>Flask<\/strong> \u2013 Lightweight web framework used to build the dashboard structure, route handling, and API endpoints.<\/li>\n\n\n\n<li><strong>SQLite<\/strong> \u2013 Local relational database to store scan results, tagging info, logs, and metadata.<\/li>\n\n\n\n<li><strong>HTML + Jinja2 Templates<\/strong> \u2013 Used to render dynamic scan tables and pages inside the Flask app.<\/li>\n\n\n\n<li><strong>Bootstrap (via HTML templates)<\/strong> \u2013 Used to improve UI layout and responsiveness with clean, pre-built components.<\/li>\n\n\n\n<li><strong>Docker + Docker Compose<\/strong> \u2013 Used to containerize the app for easy deployment. The Dockerfiles and <code>docker-compose.yml<\/code> define the environment setup and networking.<\/li>\n\n\n\n<li><strong>Nmap<\/strong> \u2013 The core scanning engine used to run full, quick, or custom scans \u2014 integrated with Python backend logic.<\/li>\n\n\n\n<li><strong>Linux (Ubuntu)<\/strong> \u2013 The development and runtime environment for the app. All features were built and tested in a Linux-based VM.<\/li>\n\n\n\n<li><strong>AI Tools (ChatGPT)<\/strong> \u2013 Used as a learning resource and development assistant. Helped debug Python code, brainstorm features, and generate the frontend layout.<\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong> While the frontend was AI-generated, the core application logic, scan handling, database design, and tool scripts were all built manually to support learning goals and reinforce real-world understanding.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"architecture-overview\">How It Works: Architecture Overview<\/h2>\n\n\n\n<p>At its core, the Nmap Dashboard revolves around processing Nmap scan results and making them accessible, searchable, and actionable inside a web interface. There are two main ways to bring scan data into the system:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Run a new scan<\/strong> directly from the dashboard using one of the built-in scan buttons.<\/li>\n\n\n\n<li><strong>Import an existing <code>.xml<\/code> Nmap scan<\/strong> file manually.<\/li>\n<\/ol>\n\n\n\n<p>In both cases, the scan data is processed by a custom parser script (<code>parse2_nmap.py<\/code>), which extracts host and port information, calculates risk scores, and applies suggested tags based on past tagging behavior. The parsed results are then inserted into a local SQLite database (<code>nmap_results.db<\/code>).<\/p>\n\n\n\n<p>Surrounding this scan workflow are features designed to help users manage and analyze their network scans more effectively:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Manual tagging<\/strong> of hosts or ports for customized categorization<\/li>\n\n\n\n<li><strong>Scan comparison<\/strong> to track changes over time<\/li>\n\n\n\n<li><strong>Soft deletion<\/strong> and <strong>undo restore<\/strong> for safe editing<\/li>\n\n\n\n<li><strong>PDF export<\/strong> for reporting or documentation<\/li>\n\n\n\n<li><strong>Detailed logging<\/strong>, stored in a <code>logs\/<\/code> directory outside the app<\/li>\n<\/ul>\n\n\n\n<p>Outside the dashboard itself, I created <strong>supporting Python scripts<\/strong> that can:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Reset or archive the database<\/li>\n\n\n\n<li>Manage <code>.xml<\/code> and <code>.txt<\/code> files<\/li>\n\n\n\n<li>Help maintain the project entirely from a Linux terminal if needed<\/li>\n<\/ul>\n\n\n\n<p>This blend of automated parsing, manual tagging, data persistence, and utility scripts makes the app both flexible and educational \u2014 it\u2019s not just a project, but a hands-on tool I actively used to reinforce both my Python and Linux fundamentals.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"deep-dive-1\">Code Deep Dive 1: Smarter Parsing<\/h2>\n\n\n\n<p>At the heart of this project lies parse2_nmap.py a custom-built parser that doesn&#8217;t just extract raw data from Nmap XML scans, but <strong>adds intelligent enrichment<\/strong> through auto-tagging and risk scoring.<\/p>\n\n\n\n<p>Once the XML file is parsed, I loop through each <code>&lt;host&gt;<\/code> and <code>&lt;port&gt;<\/code> block. But instead of blindly dumping data into a database, I added several enhancements to make each record more meaningful and actionable.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Service Detection + Script Parsing<\/h4>\n\n\n\n<p>For each detected port, the parser extracts metadata like the service name, product banner, version, and any script output:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>service = service_elem.attrib.get(\"name\", \"\") if service_elem is not None else \"\"\nproduct = service_elem.attrib.get(\"product\", \"\") if service_elem is not None else \"\"\nscript_output = parse_scripts(port)  # parses &lt;script&gt; tags\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Automatic Tag Suggestions<\/h4>\n\n\n\n<p>If the current device or service hasn&#8217;t already been tagged \u2014 either in this scan session or globally \u2014 I use a custom-built <code>suggest_tags()<\/code> function to generate relevant labels:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>device_tag, service_tag = suggest_tags(addr_ip, port_id, service, mac_vendor=vendor, os_match=os_match)\nif device_tag and not session_tags.get(\"device\") and not global_tags.get(\"device\"):\n    set_tag(session_id, addr_ip, mac_addr, \"device\", device_tag, cursor)\n<\/code><\/pre>\n\n\n\n<p>This ensures consistency across sessions, even when scan targets change IPs or services shift.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Risk Scoring Per Port<\/h4>\n\n\n\n<p>Each open port is assigned a risk score based on heuristics that evaluate the service type and port number:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>risk = compute_row_risk_score(port_id, service)\n<\/code><\/pre>\n\n\n\n<p>For example, an open SSH port on 22 might be lower risk than an unexpected web service on port 8080.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Clean Database Insertion<\/h3>\n\n\n\n<p>Finally, all parsed and enriched data is inserted into the <code>scan_results<\/code> table:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>insert_scan_result(session_id, entry, cursor, risk_score=risk)\n<\/code><\/pre>\n\n\n\n<p>This logic ensures that every scan result is not just stored \u2014 it&#8217;s contextualized.<\/p>\n\n\n\n<p>Want to see the full source?<br>Browse the complete <a class=\"\" href=\"https:\/\/github.com\/yairemartinez\/nmap_dashboard\/blob\/main\/app\/utils\/parse2_nmap.py\"><code>parse2_nmap.py<\/code><\/a> on GitHub.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"deep-dive-2\">Code Deep Dive 2: Tagging, Risk Scoring &amp; Exporting in scans.py<\/h2>\n\n\n\n<p>While the parser extracts and enriches scan data, the real magic happens when users interact with individual scan sessions through the <code>scans.py<\/code> module. This route file powers session analysis, tag management, risk visualization, and even PDF exports.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Session-Level Drilldowns<\/h4>\n\n\n\n<p>Each scan session is viewable at <code>\/scan\/&lt;session_id&gt;<\/code>, where filters can be applied for IPs, ports, services, or tags. Risk scores are aggregated per host, and the most vulnerable IP is highlighted automatically:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>cursor.execute(\"\"\"\n    SELECT ip, SUM(risk_score) as total_risk\n    FROM scan_results\n    WHERE session_id = ?\n    GROUP BY ip\n    ORDER BY total_risk DESC\n    LIMIT 1\n\"\"\", (session_id,))\n<\/code><\/pre>\n\n\n\n<p>This gives users immediate visibility into their highest-risk assets.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Suggested vs Global Tags<\/h4>\n\n\n\n<p>For every host, the dashboard cross-references existing global tags and offers AI-driven tag suggestions based on vendor, OS, service, and port. It even lets users apply tags session-wide or edit them manually:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>suggested_device, suggested_service = suggest_tags(ip, port, service, mac_vendor, os_match)\n<\/code><\/pre>\n\n\n\n<p>These tags are stored in a separate <code>global_tags<\/code> table and used to filter or group results for future scans.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Risk Explanations &amp; Visualization<\/h4>\n\n\n\n<p>To explain why a host scored high risk, <code>scans.py<\/code> breaks down each port-level risk:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>reason = f\"Port {port}, Service '{service}', Score: {score}\"\nrisk_reasons_by_host.setdefault(ip, []).append(reason)\n<\/code><\/pre>\n\n\n\n<p>In the dashboard UI, this helps users quickly understand <strong>why<\/strong> a host is flagged \u2014 not just that it was.<\/p>\n\n\n\n<p>It also generates simple charts (bar graphs) for port and service frequency using values like:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>port_counts[port] = port_counts.get(port, 0) + 1\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Export to PDF<\/h4>\n\n\n\n<p>A standout feature is the <strong>export to PDF<\/strong> button, which renders a timestamped, full formatted report of the scan session using WeasyPrint:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>rendered = render_template(\"export_pdf.html\", ...)\npdf = HTML(string=rendered).write_pdf()\n<\/code><\/pre>\n\n\n\n<p>This makes it easy to share results or keep reports for audit logs.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Want to see the full source?<br>Check out <a class=\"\" href=\"https:\/\/github.com\/yairemartinez\/nmap_dashboard\/blob\/main\/app\/routes\/scans.py\"><code>scans.py<\/code><\/a> on GitHub.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"deep-dive-3\">Code Deep Dive 3: Intelligent Port-by-Port Scan Diffing<\/h2>\n\n\n\n<p>One of the most technically robust components of my Nmap Dashboard is the <code>compute_diff()<\/code> function in <a class=\"\" href=\"https:\/\/github.com\/yairemartinez\/nmap_dashboard\/blob\/main\/app\/utils\/db_utils.py\"><code>db_utils.py<\/code><\/a>. This function performs a <strong>granular, port-by-port comparison<\/strong> between two Nmap scan sessions \u2014 enabling the dashboard to show exactly what changed on a host and how.<\/p>\n\n\n\n<p>Here\u2019s a real example from the core logic:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>for port in ports:\n    old = old_data.get(port, {})\n    new = new_data.get(port, {})\n\n    changes = {\"port\": port}\n\n    if clean_lower(old.get(\"state\", \"\")) != clean_lower(new.get(\"state\", \"\")):\n        changes[\"old_state\"] = old.get(\"state\", \"\u2014\") or \"\u2014\"\n        changes[\"new_state\"] = new.get(\"state\", \"\u2014\") or \"\u2014\"\n\n    if clean_lower(old.get(\"service\", \"\")) != clean_lower(new.get(\"service\", \"\")) or \\\n       clean_lower(old.get(\"version\", \"\")) != clean_lower(new.get(\"version\", \"\")):\n        changes[\"old_svc_ver\"] = f\"{old.get('service', '')} {old.get('version', '')}\".strip() or \"\u2014\"\n        changes[\"new_svc_ver\"] = f\"{new.get('service', '')} {new.get('version', '')}\".strip() or \"\u2014\"\n    \n    ...\n    \n    if len(changes) &gt; 1:\n        changes[\"full_old\"] = {...}\n        changes[\"full_new\"] = {...}\n        side_by_side.append(changes)\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">What Makes This Unique<\/h4>\n\n\n\n<p><strong>1. Multi-field precision<\/strong><br>Each port is compared across key attributes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Port state (<code>open<\/code>, <code>filtered<\/code>, <code>closed<\/code>, etc.)<\/li>\n\n\n\n<li>Service name and version<\/li>\n\n\n\n<li>Product info, OS guesses, CPEs<\/li>\n\n\n\n<li>Script output (e.g. <code>http-title<\/code>, <code>ssh-hostkey<\/code>)<\/li>\n\n\n\n<li>Host-level metadata (uptime, last boot)<\/li>\n<\/ul>\n\n\n\n<p>This level of detail ensures meaningful diffs \u2014 not just noise.<\/p>\n\n\n\n<p><strong>2. Side-by-side formatting<\/strong><br>The output is intentionally structured to support intuitive UI rendering. Users can view:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>What changed and on which port<\/li>\n\n\n\n<li>Before\/after values for each field<\/li>\n\n\n\n<li>Extra context like hostnames, MAC addresses, and tags<\/li>\n<\/ul>\n\n\n\n<p>This mirrors the usability of commercial tools like Nessus or Qualys \u2014 but built entirely from scratch.<\/p>\n\n\n\n<p><strong>3. Data normalization &amp; error handling<\/strong><br>To ensure consistency, all comparisons use normalization helpers:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopyEdit<code>def clean(val): return (val or \"\").strip()\ndef clean_lower(val): return clean(val).lower()\n<\/code><\/pre>\n\n\n\n<p>This avoids false positives due to case differences or whitespace, and ensures robust behavior even when fields are missing.<\/p>\n\n\n\n<p><strong>4. Enriched context through tagging<\/strong><br>After changes are detected, tags are fetched and merged from the tags database \u2014 adding descriptions like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8220;Web Server (nginx)&#8221;<\/li>\n\n\n\n<li>&#8220;Printer \u2013 Guest VLAN&#8221;<\/li>\n\n\n\n<li>&#8220;Risk: Critical&#8221;<\/li>\n<\/ul>\n\n\n\n<p>This turns a technical scan diff into a readable, security-aware report. <\/p>\n\n\n\n<p>Below is a example of the feature in use Mac Address is included for other Ips chose this photo as a example as it excludes Mac for security reasons <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/yairmartinezcybersecurityportfolio.com\/wp-content\/uploads\/2025\/08\/Screenshot-from-2025-08-05-14-13-14-1024x355.png\" alt=\"\" class=\"wp-image-998\"\/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">What This Says About My Skills<\/h4>\n\n\n\n<p>I think holistically \u2014 bridging raw scan output with readable, actionable results<\/p>\n\n\n\n<p>I\u2019m comfortable working with low-level data parsing and structured diffs<\/p>\n\n\n\n<p>I prioritize both <strong>technical accuracy<\/strong> and <strong>usability<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"challenges\">Challenges I Faced<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">1. Learning Python from Scratch<\/h4>\n\n\n\n<p>When I started this project, I had no experience with Python or coding at all. Even basic concepts were unfamiliar. I relied heavily on AI tools to help explain code line by line and slowly built up an understanding of how Python works.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. Poor Initial Planning<\/h4>\n\n\n\n<p>Originally, I didn\u2019t expect this project to grow as large as it did. I started with everything in one file and no real structure. As new features kept getting added, I had to constantly patch the code and rethink how everything fit together. This forced me to learn about Flask blueprints and refactor the project into a modular architecture. It wasn\u2019t smooth but it was valuable.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. Connecting Frontend to Backend<\/h4>\n\n\n\n<p>Even though most of the frontend design was generated completely with AI assistance, I still had to learn how to wire everything up. Figuring out how buttons should trigger routes, how to display dynamic data using Jinja templates, and how to get the right information on screen was a steep learning curve. Every new page was a new lesson in full-stack development.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">4. Testing the Parser<\/h4>\n\n\n\n<p>One of the most time-consuming tasks was getting the Nmap XML parser to output exactly what I needed. Each change required running or importing different Nmap scans, which take time. I eventually realized I could save and reuse existing scan files to test faster and more efficiently \u2014 a small insight that made a big difference.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">5. Logging the Right Way<\/h4>\n\n\n\n<p>At first, I used simple print statements. But as the project grew, I needed a robust logging system to track events across different modules. Setting up log files for specific features, formatting entries for clarity, and making sure logs persisted in production required experimentation \u2014 but taught me the value of well-planned debugging tools.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">6. Using GitHub for the First Time<\/h4>\n\n\n\n<p>Before this, I had never used GitHub. Learning how to track changes, use commits properly, clean up my history, and manage a <code>.gitignore<\/code> file taught me that version control isn\u2019t just about saving work.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">7. Building Without a Tutorial<\/h4>\n\n\n\n<p>This dashboard wasn\u2019t built by following a single guide. I had to figure out every part from Nmap parsing to Flask routes to PDF generation on my own, often with no exact answer available. That process, while frustrating at times, gave me much deeper problem-solving skills than any tutorial could have.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">8. Migrating to Docker<\/h4>\n\n\n\n<p>Once the app was stable, I moved everything into Docker to make it easier to run across linux systems. That meant learning how to write a <code>Dockerfile<\/code>, manage volumes, deal with file permissions, and use <code>docker-compose<\/code> to orchestrate everything. It was a big step forward in understanding how real-world deployments work.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"lessons-learned\">What I Learned<\/h2>\n\n\n\n<p>Working on the Nmap Dashboard pushed me out of my comfort zone and helped me grow across multiple areas of development and cybersecurity:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Python fundamentals<\/strong><br>I started with no experience in Python. By building this project, I learned how to structure programs, write functions, handle files, and use core libraries effectively.<\/li>\n\n\n\n<li><strong>Flask web development<\/strong><br>From routing to Jinja templating, I learned how Flask apps are built and how the backend connects to dynamic HTML templates. I also learned how to organize larger apps using <strong>blueprints<\/strong>.<\/li>\n\n\n\n<li><strong>Full-stack logic<\/strong><br>Figuring out how to trigger backend actions from buttons in the frontend gave me a deeper understanding of request\/response cycles, form handling, and how front-end actions are wired to logic.<\/li>\n\n\n\n<li><strong>Nmap and network analysis<\/strong><br>Beyond just using Nmap, I learned how to read its XML output, extract relevant info, and visualize it \u2014 which gave me a stronger grasp of ports, protocols, services, and network security principles.<\/li>\n\n\n\n<li><strong>Logging and debugging<\/strong><br>I built a custom logging system that helped me trace errors and monitor app activity. I learned how to write logs to specific files, format messages, and make debugging easier.<\/li>\n\n\n\n<li><strong>SQLite and data relationships<\/strong><br>Designing and querying a relational database taught me about foreign keys, joins, indexing, and the importance of clean data structure when building scalable applications.<\/li>\n\n\n\n<li><strong>Docker and app deployment<\/strong><br>I containerized the entire project using Docker and Docker Compose, which taught me how to handle permissions, volumes, and make the app easy to deploy on any machine.<\/li>\n\n\n\n<li><strong>GitHub and project hygiene<\/strong><br>This was my first time using GitHub seriously. I learned how to track changes, use <code>.gitignore<\/code> correctly, and publish a clean, shareable repo for others to use or build on.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"improvements\">Things I&#8217;d Improve Next Time<\/h2>\n\n\n\n<p><strong>Start with Blueprints and Clean Architecture<\/strong><br>In the beginning, I underestimated how big the app would become. I learned the hard way that organizing your project from the start pays off later. In future builds, I\u2019d use Flask Blueprints and modular design right away to avoid technical debt.<\/p>\n\n\n\n<p><strong>Add Authentication and Access Control<\/strong><br>Currently, the app assumes trusted users. A clear next step would be implementing proper login systems and permission handling to support multi-user access securely.<\/p>\n\n\n\n<p><strong>Better Security Practices<\/strong><br>This app handles potentially sensitive scan data, so I\u2019d like to improve on secure file handling, input validation, and reduce attack surface \u2014 especially if this were deployed in a production setting.<\/p>\n\n\n\n<p><strong>Plan Features More Carefully<\/strong><br>This project grew organically, which led to some patchwork solutions. Next time, I\u2019d plan out features more intentionally and stick to a roadmap to keep the codebase cleaner and the workflow more efficient.<\/p>\n\n\n\n<p><strong>Build Fully-Realized Features<\/strong><br>Some features were built just to be functional \u2014 not polished. Going forward, I want to focus on completing features with real usability in mind, including edge cases, user feedback, and documentation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"links\">Links<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GitHub Repo<\/strong><br><a class=\"\" href=\"https:\/\/github.com\/yairemartinez\/nmap_dashboard\">https:\/\/github.com\/yairemartinez\/nmap_dashboard<\/a><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"final-thoughts\">Final Thoughts<\/h2>\n\n\n\n<p>Working on this project gave me hands-on experience with building something practical using Python. I started with a simple idea and kept improving it while learning how to connect code, organize logic, and solve problems as they came up. Tools like Flask, Docker, and AI guidance helped me turn it into a full-featured network scanner dashboard that I can actually use. This project serves as great precursor to the tools and utilities I can create in the future with python.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why I built this? I made the Nmap Dashboard as a way to teach myself Python, not just learning the syntax, but actually using it to build something useful. I didn\u2019t want to just follow along with tutorials. I wanted to create a tool that worked, that could solve a real problem, and that would [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1324,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,37],"tags":[53,45,42,51,54,50,44,46],"class_list":["post-809","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-projects","category-python","tag-docker","tag-flask","tag-linux","tag-logging","tag-nmap","tag-parsing","tag-python","tag-sqlite3"],"_links":{"self":[{"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/posts\/809","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=809"}],"version-history":[{"count":51,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/posts\/809\/revisions"}],"predecessor-version":[{"id":1327,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/posts\/809\/revisions\/1327"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=\/wp\/v2\/media\/1324"}],"wp:attachment":[{"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=809"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=809"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yairmartinezcybersecurityportfolio.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=809"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}