<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sam codex</title>
    <description>The latest articles on DEV Community by sam codex (@sam_codex).</description>
    <link>https://dev.to/sam_codex</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4029743%2F232e81f7-1c26-4c6c-aa13-e0dc0f1b8c19.png</url>
      <title>DEV Community: sam codex</title>
      <link>https://dev.to/sam_codex</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sam_codex"/>
    <language>en</language>
    <item>
      <title>Building a Windows Laptop Monitoring Agent with Webex and Email Alerts</title>
      <dc:creator>sam codex</dc:creator>
      <pubDate>Wed, 15 Jul 2026 06:59:18 +0000</pubDate>
      <link>https://dev.to/sam_codex/building-a-windows-laptop-monitoring-agent-with-webex-and-email-alerts-1l9d</link>
      <guid>https://dev.to/sam_codex/building-a-windows-laptop-monitoring-agent-with-webex-and-email-alerts-1l9d</guid>
      <description>&lt;h1&gt;
  
  
  Building a Windows Laptop Monitoring Agent with Webex and Email Alerts
&lt;/h1&gt;

&lt;p&gt;I wanted to build a small security and device-monitoring tool for my Windows laptop.&lt;/p&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When someone unlocks my laptop using a Windows PIN or password, I should receive a Webex message and an email.&lt;/li&gt;
&lt;li&gt;When the laptop battery reaches 50% or lower while it is not charging, I should receive a Webex alert.&lt;/li&gt;
&lt;li&gt;I should also be notified about important events such as failed login attempts, charger disconnection, sleep, resume, restart and shutdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of creating a heavy employee-monitoring application, I decided to design a lightweight Windows background agent focused only on device security and power events.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the System Should Do
&lt;/h2&gt;

&lt;p&gt;The first version will monitor one Windows laptop.&lt;/p&gt;

&lt;p&gt;It will detect the following events:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Webex Alert&lt;/th&gt;
&lt;th&gt;Email Alert&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Laptop unlocked&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop locked&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Battery reaches 50% or lower&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charger disconnected&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failed Windows login attempts&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop started&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop restarted&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop shut down&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop entered sleep mode&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop resumed from sleep&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unexpected shutdown detected&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For battery monitoring, the alert should be sent only when:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Battery percentage &amp;lt;= 50%
AND
Laptop is not charging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The notification must not repeat every few seconds while the battery remains below 50%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Unlock Notification
&lt;/h2&gt;

&lt;p&gt;When the laptop is unlocked, the Webex and email notification could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔓 LAPTOP UNLOCKED

Device: LENOVO-LAPTOP
Windows User: Sam
Date: 15 July 2026
Time: 11:35 AM
Battery: 76%
Power Status: Not charging
Local IP: 192.168.1.25
Network: Office Wi-Fi

Event: Windows PIN/password unlock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives enough information to understand when, where and under which Windows account the laptop was accessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Battery Notification
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🪫 BATTERY WARNING

Device: LENOVO-LAPTOP
Windows User: Sam
Battery: 49%
Charging: No
Charger: Disconnected
Time: 3:20 PM

Please connect the laptop charger.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I may also add secondary thresholds later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50% - Warning
20% - Critical
10% - Emergency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Proposed Architecture
&lt;/h2&gt;

&lt;p&gt;The system will contain two main parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Windows monitoring agent installed on the laptop&lt;/li&gt;
&lt;li&gt;A backend API connected to Webex, email and PostgreSQL
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────┐
│          Windows Laptop          │
│                                  │
│  ┌────────────────────────────┐  │
│  │ Windows Monitoring Agent   │  │
│  │                            │  │
│  │ - Unlock and lock events   │  │
│  │ - Battery monitoring       │  │
│  │ - Charger monitoring       │  │
│  │ - Sleep and resume events  │  │
│  │ - Failed login detection   │  │
│  │ - Local retry queue        │  │
│  └──────────────┬─────────────┘  │
└─────────────────┼────────────────┘
                  │ HTTPS
                  ▼
┌──────────────────────────────────┐
│          Backend API             │
│                                  │
│  - Validate device API key       │
│  - Store event in PostgreSQL     │
│  - Prevent duplicate alerts      │
│  - Send Webex direct message     │
│  - Send email notification       │
└───────────┬──────────────┬───────┘
            │              │
            ▼              ▼
      Webex Bot        SMTP Server
            │              │
            ▼              ▼
      Direct Message    Email Alert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Use a C# Windows Service?
&lt;/h2&gt;

&lt;p&gt;The laptop-side agent could technically be built using Node.js or Python.&lt;/p&gt;

&lt;p&gt;However, I prefer C# and .NET for this part because it provides better native integration with Windows.&lt;/p&gt;

&lt;p&gt;A .NET Windows Service can handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows session events&lt;/li&gt;
&lt;li&gt;Automatic startup with Windows&lt;/li&gt;
&lt;li&gt;Power mode changes&lt;/li&gt;
&lt;li&gt;Sleep and resume events&lt;/li&gt;
&lt;li&gt;Windows Event Log monitoring&lt;/li&gt;
&lt;li&gt;Battery and charger information&lt;/li&gt;
&lt;li&gt;Service recovery when the process crashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent should run quietly in the background without requiring the user to manually start it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Keep Notifications in the Backend?
&lt;/h2&gt;

&lt;p&gt;The Windows agent should not directly contain sensitive credentials such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Webex bot access token&lt;/li&gt;
&lt;li&gt;SMTP username&lt;/li&gt;
&lt;li&gt;SMTP password&lt;/li&gt;
&lt;li&gt;Database credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, the agent should call a protected backend endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/device-alerts
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend will handle all external integrations.&lt;/p&gt;

&lt;p&gt;This also makes it easier to change notification providers later without reinstalling the laptop agent.&lt;/p&gt;

&lt;p&gt;For example, Webex could later be replaced or extended with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Teams&lt;/li&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;li&gt;Telegram&lt;/li&gt;
&lt;li&gt;Push notifications&lt;/li&gt;
&lt;li&gt;SMS&lt;/li&gt;
&lt;li&gt;WhatsApp&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example Event Payload
&lt;/h2&gt;

&lt;p&gt;The Windows agent can send a JSON payload like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deviceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop-sam-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deviceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LENOVO-LAPTOP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"windowsUser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEVICE_UNLOCKED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-15T11:35:00+05:30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"batteryPercentage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isCharging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"localIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.25"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"networkName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Office Wi-Fi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agentVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authenticationType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WINDOWS_CREDENTIAL"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend can then store the event and decide which notification channels should be used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Types
&lt;/h2&gt;

&lt;p&gt;The first version may support these event types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEVICE_UNLOCKED
DEVICE_LOCKED
BATTERY_LOW
BATTERY_CRITICAL
CHARGER_CONNECTED
CHARGER_DISCONNECTED
DEVICE_SLEEP
DEVICE_RESUMED
DEVICE_STARTED
DEVICE_RESTARTED
DEVICE_SHUTDOWN
UNEXPECTED_SHUTDOWN
FAILED_LOGIN
AGENT_STARTED
AGENT_STOPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using standard event names will make the system easier to maintain and extend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Battery Alert Logic
&lt;/h2&gt;

&lt;p&gt;Battery alerts need careful state management.&lt;/p&gt;

&lt;p&gt;Without it, the agent may send the same warning every 30 seconds.&lt;/p&gt;

&lt;p&gt;A better approach is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Check battery status every 30 seconds.

2. Check whether the laptop is charging.

3. If the laptop is not charging and battery is 50% or lower:
   - Check whether the 50% alert was already sent.
   - If not, send the alert.
   - Save the alert state locally.

4. Do not send the same alert again while the battery remains below 50%.

5. Reset the warning state after the battery charges above 55%.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pseudocode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCharging&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Percentage&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LowBatteryAlertSent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;alertService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BATTERY_LOW"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LowBatteryAlertSent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;stateStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCharging&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Percentage&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LowBatteryAlertSent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;stateStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids notification spam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting Failed Login Attempts
&lt;/h2&gt;

&lt;p&gt;Failed Windows sign-in attempts should also be monitored.&lt;/p&gt;

&lt;p&gt;However, sending an alert for every incorrect password attempt may create too many notifications.&lt;/p&gt;

&lt;p&gt;A better rule would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First failed attempt:
Store it in the log.

Three failed attempts within five minutes:
Send a Webex and email warning.

Five or more failed attempts:
Send a high-priority security alert.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚨 MULTIPLE FAILED WINDOWS SIGN-INS

Device: LENOVO-LAPTOP
Attempted User: Sam
Failed Attempts: 3
Period: 5 minutes
Time: 2:14 AM

Multiple failed login attempts were detected.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling Internet Disconnection
&lt;/h2&gt;

&lt;p&gt;The laptop may be unlocked while the internet is unavailable.&lt;/p&gt;

&lt;p&gt;The alert should not be lost.&lt;/p&gt;

&lt;p&gt;The agent should maintain a small local offline queue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Event detected
      |
      v
Is internet available?
      |
  ┌───┴───┐
  │       │
 Yes      No
  │       │
Send    Save locally
  │       │
  │    Retry later
  │       │
  └───┬───┘
      v
Mark as delivered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQLite or an encrypted local JSON store could be used for the first version.&lt;/p&gt;

&lt;p&gt;When connectivity returns, pending alerts can be sent automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Securing the Agent API
&lt;/h2&gt;

&lt;p&gt;Every laptop should receive its own identity and API key.&lt;/p&gt;

&lt;p&gt;Example agent configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HEIDI_API_URL=https://heidi.example.com/api/device-alerts
DEVICE_ID=laptop-sam-001
DEVICE_API_KEY=generated-long-random-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend should implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS-only communication&lt;/li&gt;
&lt;li&gt;One API key per device&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Request timestamp validation&lt;/li&gt;
&lt;li&gt;Request signing&lt;/li&gt;
&lt;li&gt;Duplicate-event protection&lt;/li&gt;
&lt;li&gt;Device enable and disable controls&lt;/li&gt;
&lt;li&gt;API-key rotation&lt;/li&gt;
&lt;li&gt;Audit logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A stronger implementation can sign each request using HMAC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;signature = HMAC_SHA256(
    requestBody + timestamp,
    deviceSecret
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend can reject requests with invalid signatures or old timestamps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Structure
&lt;/h2&gt;

&lt;p&gt;A basic PostgreSQL design could contain three tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Devices
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;devices&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_code&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;assigned_user&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;api_key_hash&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;is_active&lt;/span&gt; &lt;span class="nb"&gt;BOOLEAN&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;last_seen_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Device Events
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;device_events&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;windows_user&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;battery_percentage&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;is_charging&lt;/span&gt; &lt;span class="nb"&gt;BOOLEAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;local_ip&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;network_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;event_time&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notification Logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;notification_logs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_event_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;device_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;recipient&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;provider_response&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sent_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Separating device events and notification logs helps track cases where the event was recorded successfully but the Webex or email delivery failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend Processing Flow
&lt;/h2&gt;

&lt;p&gt;When the backend receives an event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Validate the device ID.

2. Validate the API key or HMAC signature.

3. Reject expired requests.

4. Check for duplicate event IDs.

5. Store the event in PostgreSQL.

6. Load notification rules for the event type.

7. Send a Webex direct message.

8. Send email when required.

9. Store the delivery result.

10. Return the processing status to the laptop agent.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"d25183bb-8f74-4623-9884-a291a5c82102"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"notifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sent"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Future Admin Dashboard
&lt;/h2&gt;

&lt;p&gt;Although the first release will monitor only one laptop, I want the database and API to support multiple company devices.&lt;/p&gt;

&lt;p&gt;The dashboard could eventually show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Online and offline devices&lt;/li&gt;
&lt;li&gt;Current battery percentage&lt;/li&gt;
&lt;li&gt;Charging status&lt;/li&gt;
&lt;li&gt;Last unlock time&lt;/li&gt;
&lt;li&gt;Current Windows username&lt;/li&gt;
&lt;li&gt;Last IP address&lt;/li&gt;
&lt;li&gt;Failed login attempts&lt;/li&gt;
&lt;li&gt;Recent security alerts&lt;/li&gt;
&lt;li&gt;Agent version&lt;/li&gt;
&lt;li&gt;Notification delivery status&lt;/li&gt;
&lt;li&gt;Device activation and deactivation&lt;/li&gt;
&lt;li&gt;Per-device Webex recipients&lt;/li&gt;
&lt;li&gt;Per-device email recipients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example dashboard layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────┐
│ Laptop Monitoring Dashboard                                 │
├──────────────────────────────────────────────────────────────┤
│ Online Devices: 8      Offline Devices: 2      Alerts: 4     │
├──────────────────────────────────────────────────────────────┤
│ Device          User       Battery     Status      Last Event│
│--------------------------------------------------------------│
│ Sam-Laptop      Sam        74%          Online      Unlocked  │
│ Sales-Laptop-1  Arjun      48%          Warning     Battery   │
│ HR-Laptop-2     Priya      91%          Charging    Online    │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Privacy Considerations
&lt;/h2&gt;

&lt;p&gt;This project should remain a device-security tool, not hidden surveillance software.&lt;/p&gt;

&lt;p&gt;It should not capture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keystrokes&lt;/li&gt;
&lt;li&gt;Screenshots&lt;/li&gt;
&lt;li&gt;Webcam images&lt;/li&gt;
&lt;li&gt;Microphone audio&lt;/li&gt;
&lt;li&gt;Personal files&lt;/li&gt;
&lt;li&gt;Browser history&lt;/li&gt;
&lt;li&gt;Application content&lt;/li&gt;
&lt;li&gt;Private messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For employee devices, it should be installed only on company-owned laptops with a clear monitoring policy and employee consent.&lt;/p&gt;

&lt;p&gt;The goal is to monitor device health and security events, not private user activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proposed Technology Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Windows Agent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C#
.NET 8
Windows Service
Windows Event Log
WMI or Windows Management APIs
SQLite for offline queue
HttpClient for API communication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node.js
Express or NestJS
PostgreSQL
Webex Bot API
SMTP or Microsoft 365 email
JWT or HMAC device authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dashboard
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Next.js
React
Tailwind CSS
Recharts
Role-based access control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Development Phases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: Personal Laptop Agent
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Detect Windows unlock and lock&lt;/li&gt;
&lt;li&gt;Send Webex direct messages&lt;/li&gt;
&lt;li&gt;Send email alerts&lt;/li&gt;
&lt;li&gt;Detect battery level&lt;/li&gt;
&lt;li&gt;Detect charger state&lt;/li&gt;
&lt;li&gt;Add local logs&lt;/li&gt;
&lt;li&gt;Start automatically with Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phase 2: Security Events
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Detect failed login attempts&lt;/li&gt;
&lt;li&gt;Detect repeated failed logins&lt;/li&gt;
&lt;li&gt;Detect sleep and resume&lt;/li&gt;
&lt;li&gt;Detect startup and shutdown&lt;/li&gt;
&lt;li&gt;Detect unexpected shutdowns&lt;/li&gt;
&lt;li&gt;Add local retry queue&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phase 3: Multi-Device Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Device registration&lt;/li&gt;
&lt;li&gt;Per-device API keys&lt;/li&gt;
&lt;li&gt;PostgreSQL event storage&lt;/li&gt;
&lt;li&gt;Notification rules&lt;/li&gt;
&lt;li&gt;Delivery logs&lt;/li&gt;
&lt;li&gt;Device heartbeat&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phase 4: Admin Dashboard
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Device list&lt;/li&gt;
&lt;li&gt;Battery and online status&lt;/li&gt;
&lt;li&gt;Security alert history&lt;/li&gt;
&lt;li&gt;Notification history&lt;/li&gt;
&lt;li&gt;Device controls&lt;/li&gt;
&lt;li&gt;Per-device settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phase 5: Enterprise Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Remote configuration&lt;/li&gt;
&lt;li&gt;Agent auto-update&lt;/li&gt;
&lt;li&gt;Department-based devices&lt;/li&gt;
&lt;li&gt;Alert escalation rules&lt;/li&gt;
&lt;li&gt;Microsoft Teams and Slack support&lt;/li&gt;
&lt;li&gt;Reporting and analytics&lt;/li&gt;
&lt;li&gt;Device health score&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This started as a simple requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Send me a Webex message and an email when my laptop is unlocked.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But it can grow into a useful lightweight device security and monitoring platform.&lt;/p&gt;

&lt;p&gt;The most important design decision is keeping the Windows agent simple.&lt;/p&gt;

&lt;p&gt;The agent should only detect events, collect limited device information and securely send data to the backend. All notification logic, credentials, logging and administration should remain on the server.&lt;/p&gt;

&lt;p&gt;This provides better security, easier maintenance and a clear path from monitoring one personal laptop to managing multiple company devices.&lt;/p&gt;

&lt;p&gt;I plan to start with the Windows unlock and battery monitoring features, then gradually add the security events, backend dashboard and multi-device support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tags
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#windows
#dotnet
#csharp
#node
#webex
#security
#automation
#postgresql
#devops
#programming
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>node</category>
      <category>webex</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
