# Suraj Mandal

> Full Stack Developer and freelance software engineer based in Ottawa, ON, Canada. Builds systems across product, infrastructure, and developer tooling. Open to full-time positions, contract work, and freelance consulting.

This file is served at https://mandalsuraj.com/llms.txt for AI assistants and crawlers. The blog post list below is generated from the live site, so it never lags behind what is published.

## About

Suraj Mandal is a Full Stack Developer currently working as a Research Technician at MealLens Inc. in Ottawa, Canada. He designs and ships full-stack systems where interface, infrastructure, and automation behave as one product: web dashboards, APIs, containerized services, cloud infrastructure, and embedded device tooling.

Core stack: React, Next.js, Node.js, TypeScript, Go, Python, FastAPI, PostgreSQL, Docker, Terraform, Ansible, AWS, Linux.

## Experience

- MealLens Inc. (Oct 2025 - present), Research Technician. React dashboard, FastAPI and Node.js APIs, Docker microservices, MQTT embedded tooling.
- Algonquin College (Sep 2024 - Jul 2025), Research Assistant. Next.js dashboard processing 70K+ live data points, Grafana, Python network tools.
- Rideau Valley Soaring (Jun 2024 - Aug 2024), Research Assistant. Sensor ingestion pipeline, Python processing, PostgreSQL, React dashboard. Published libigc on PyPI.
- Art Fervour (2020 - 2022), Product Developer. React web platform, 15+ interactive campaign microsites, reusable component library.
- Pointo (2019 - 2021), Lead SDE. Rider and driver apps, live fleet operations dashboards, and real-time backend services for an on-demand e-rickshaw platform.

## Contact

- Email: me@mandalsuraj.com
- Phone: +1 (416) 726-4766
- LinkedIn: https://linkedin.com/in/mandalsuraj
- GitHub: https://github.com/surajmandalcell
- Location: Ottawa, ON, Canada

---

# Blog posts and case studies

---

# KaruNeko

> A quality-first manga library and reader with local control

- URL: https://mandalsuraj.com/blog/karuneko
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-08-10
- Project date: 2026-08-10
- Tags: desktop, reader, library, automation, typescript
- Git repo: https://gitflic.ru/project/cruelplatypus67/karuneko

![KaruNeko cover](https://mandalsuraj.com/images/blog/karuneko/cover.png)

KaruNeko is a **standalone manga library and reader**. It keeps discovery, quality checks, reading progress, and local control in one focused desktop app.

It can also work beside [Recap Pro](https://mandalsuraj.com/blog/recap-pro) as its source and reading companion.


![KaruNeko library with reading progress, series cards, chapter status, and local export controls](https://mandalsuraj.com/images/blog/karuneko/library.png)


![KaruNeko reader with a manga page and the reader settings panel open](https://mandalsuraj.com/images/blog/karuneko/reader.png)

The library and reader are shown as they appear in the real desktop app.

## Library And Sources

KaruNeko brings **multiple enabled sources** into one search and library view. It keeps the source list private and shows only the reader-facing result.

The import flow puts **page quality first**. A clear library state makes progress, chapter state, and the next reading action easy to scan.

## Reading Experience

The reader keeps the page at the center. Its settings rail controls:

- Continuous or paged reading
- Reading direction and page fit
- Page width, spacing, theme, and brightness

The app remembers reading position so a title opens where the reader stopped.

## Local Programmatic Access

KaruNeko offers **local programmatic control** for approved desktop workflows. Tools can request user-owned library actions without exposing private service details in the public interface.

## Standalone Or With Recap Pro

KaruNeko works on its own for discovery, library management, and reading. With [Recap Pro](https://mandalsuraj.com/blog/recap-pro), it becomes the companion surface for choosing and reviewing source material before production.

The two apps stay useful apart. Together, they form one clean path from a local reading library to a reviewed recap project.

---

# MacPowerToys: Seven Native Mac Utilities

> A native macOS utility suite for screen measurement, power control, color capture, local OCR, cloud transfers, Claude Code history, and diagnostics.

- URL: https://mandalsuraj.com/blog/macpowertoys
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-08-09
- Project date: 2026-08-01
- Tags: macos, swiftui, appkit, opensource, productivity, developer-tools, desktop-app, appdev
- GitHub: https://github.com/surajmandalcell/macpowertoys
- Releases: https://github.com/surajmandalcell/macpowertoys/releases

![MacPowerToys: Seven Native Mac Utilities cover](https://mandalsuraj.com/images/blog/macpowertoys/cover.png)

Sections

    [01 Overview](#one-native-home)
    [02 Measure](#ruler)
    [03 Transfer](#cloud-sync)
    [04 History](#claude-history)
    [05 Build](#native-by-design)


MacPowerToys puts seven focused utilities in one native Mac app. It replaces a pile of unrelated menu bar tools with one launcher, one visual language, and one set of window rules.

The suite stays local by default. Recognition, histories, settings, diagnostics, and window state remain on the Mac.

  Small tools work better when they share one quiet, predictable home.

One native home

The launcher groups every utility by purpose. Search narrows the catalog, while each tool keeps its own window and restores its last useful position.


![MacPowerToys launcher showing all seven built-in tools](https://mandalsuraj.com/images/blog/macpowertoys/launcher.png)

| Tool | Job |
|---|---|
| Ruler | Measure the screen in pixels, millimeters, or inches. |
| Awake | Keep the Mac or display awake by mode, time, or process. |
| Color Picker | Sample the screen and reuse local color history. |
| Text Extractor | Copy text from any screen region with Apple Vision. |
| Cloud Sync | Plan and run local and remote rclone transfers. |
| Claude History | Search, bookmark, inspect, and export Claude Code sessions. |
| Logs | Filter and copy MacPowerToys diagnostics. |


    01Developer
    Measure without leaving the screen
    Ruler places movable horizontal and vertical rulers over the desktop. Each ruler can use pixels, millimeters, or inches.

      Create several rulers and cycle between them.
      Resize, group, align, float, and copy measurements.
      Set color, opacity, aspect ratio, origin, and calibration.
      Show a crosshair or pin the rulers at the pointer.




![Ruler controls for units, calibration, guides, and active rulers](https://mandalsuraj.com/images/blog/macpowertoys/ruler.png)




    02System
    Keep work running on your terms
    Awake uses native macOS power assertions. It does not rewrite Energy settings.

      Stay awake indefinitely, for an interval, or until a date and time.
      Keep the display on as a separate choice.
      Start from quick time presets.
      Attach the awake state to a running process.




![Awake utility with passive, indefinite, timed, and process modes](https://mandalsuraj.com/images/blog/macpowertoys/awake.png)




    03Developer
    Sample once, reuse everywhere
    Color Picker starts the native macOS sampler, copies the chosen value, and adds it to a searchable local history.

      Copy HEX, RGB, HSL, CSS, SwiftUI, or NSColor output.
      Pin useful colors and group them into projects.
      Choose a default copy format.
      Record a global keyboard shortcut.




![Color Picker history with searchable saved colors](https://mandalsuraj.com/images/blog/macpowertoys/color-picker.png)


![Color Picker global shortcut settings](https://mandalsuraj.com/images/blog/macpowertoys/color-picker-settings.png)




    04Text
    Copy text from any visible region
    Text Extractor lets the user drag over the screen, then recognizes the selection with on-device Apple Vision.

      Copy recognized text as soon as extraction finishes.
      Keep a local history with one-click copy and detail views.
      Choose fast or accurate recognition.
      Set preferred languages and language correction.




![Text Extractor history with saved recognition rows](https://mandalsuraj.com/images/blog/macpowertoys/text-extractor.png)


![Text Extractor recognition quality and language settings](https://mandalsuraj.com/images/blog/macpowertoys/text-extractor-settings.png)




    05Files
    Plan transfers before files move
    Cloud Sync gives rclone a native Mac workspace. Every transfer is dry-run planned before copy, move, mirror, or two-way work begins.

      Track overall and per-file progress with persistent completion state.
      Retry failed work with backoff and keep the latest local changes.
      Browse remotes and preview files with Quick Look.
      Control parallel work, bandwidth, ignore rules, and default operations.




![Cloud Sync transfer dashboard with completed and cancelled jobs](https://mandalsuraj.com/images/blog/macpowertoys/cloud-sync.png)


![Cloud Sync settings for ignore rules, concurrency, retries, and rclone](https://mandalsuraj.com/images/blog/macpowertoys/cloud-sync-settings.png)




    06Developer
    Make local Claude Code work searchable
    Claude History reads local Claude Code sessions and groups them by project. New messages can appear while a session is still running.

      Search session titles or scan message content with deep search.
      Bookmark sessions and filter user, Claude, and tool messages.
      Inspect tool input and output beside the conversation.
      Copy or export selected messages in useful formats.




![Claude History browser with project groups and an empty conversation state](https://mandalsuraj.com/images/blog/macpowertoys/claude-history.png)


![Claude History settings for launch, refresh, deep search, and cache](https://mandalsuraj.com/images/blog/macpowertoys/claude-history-settings.png)




    07System
    Keep diagnostics readable
    Logs brings messages from every tool into one selectable view. Search and level filters reduce noise during support work.

      Filter errors, warnings, information, and debug output.
      Search across messages and sources.
      Copy exact log text into a report.
      Prune entries after two days and clear the active view.




![MacPowerToys Logs window with searchable tool diagnostics](https://mandalsuraj.com/images/blog/macpowertoys/logs.png)



## The shell around the tools

The app settings keep shared behavior out of each utility. The user can choose appearance, window behavior, and optional iCloud settings sync.

The marketplace accepts catalog sources and lists verified add-on tools. Install checks cover checksums, Developer ID identity, bundle identity, and Apple notarization.


![MacPowerToys general app settings](https://mandalsuraj.com/images/blog/macpowertoys/app-settings-cropped.png)


![MacPowerToys marketplace catalog settings](https://mandalsuraj.com/images/blog/macpowertoys/marketplace.png)

Shared appearance, window, iCloud, and marketplace controls.

Native by design

MacPowerToys uses SwiftUI for the launcher, compact utilities, and full workspaces. AppKit handles window behavior and the FreeRuler overlay where direct Mac control matters.

| Layer | Native job |
|---|---|
| SwiftUI | Launcher, sidebars, compact applets, settings, sheets, and workspace views. |
| AppKit | Ruler windows, menu commands, precise window state, Dock icon changes, and Mac-specific chrome. |
| Apple Vision | Local text recognition for Text Extractor. |
| macOS power assertions | Awake modes without changing Energy settings. |
| rclone | Remote providers, planning, transfer execution, and credential control. |
| Local storage | Histories, logs, bookmarks, settings, and remembered window state. |

The result is one utility suite that feels consistent without forcing every tool into the same shape. Compact tasks stay compact. Dense work gets a full workspace. The launcher remains the stable way back to everything.

## Build it

MacPowerToys requires macOS 26.2 or later and Xcode 26.2 or later. Cloud Sync also needs rclone.

```bash
brew install rclone
git clone https://github.com/surajmandalcell/macpowertoys.git
cd macpowertoys
make build
```

The repository includes the Xcode project, tests, Raycast commands, release notes, privacy policy, and security policy under the MIT License.

---

# mlv-eval: AI Evaluation Harness

> A released Go evaluation harness that scores golden datasets, targets any HTTP endpoint or command, and turns quality thresholds into CI exit codes.

- URL: https://mandalsuraj.com/blog/mlv-eval
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-08-29
- Tags: go, ai, evaluation, cli, ci, testing, opensource
- Source: https://github.com/surajmandalcell/mlv-eval
- v0.1.0 release: https://github.com/surajmandalcell/mlv-eval/releases/tag/v0.1.0

![mlv-eval: AI Evaluation Harness cover](https://mandalsuraj.com/images/blog/mlv-eval/cover.png)

`mlv-eval` is a released, open-source Go harness that turns golden datasets into CI quality gates. It treats the system under test as a black box behind an HTTP endpoint or shell command.

The integration stays language-neutral: no SDK inside the target, no hosted dashboard, and no model required to test the harness itself.

## Quickstart

Install the single binary, scaffold one of the bundled evaluation projects, and run it offline:

```bash
go install github.com/surajmandalcell/mlv-eval/cmd/mlv-eval@latest
mlv-eval init image2meta
mlv-eval run
```


![Terminal showing mlv-eval scaffolding the image2meta preset, scoring six cases, and printing GATE PASS](https://mandalsuraj.com/images/blog/mlv-eval/demo.svg?v=2)

  The image2meta scaffold runs against a bundled offline target before it is pointed at a real system.

## Targets

Every case is one JSON object with `input` and `expected` fields. JSONL keeps datasets reviewable in Git, while content-derived case IDs stay stable when lines are reordered or reformatted.

| Target | Contract |
|---|---|
| HTTP | POST one case as JSON and read one JSON object from the response. |
| Command | Write one case to standard input and read one JSON object from standard output. |

HTTP targets receive the case ID in `X-Mlv-Case`. Command targets receive the same value in `MLV_CASE`, making failures easy to correlate with target-side logs or traces.

Runs support bounded concurrency, per-case timeouts, retries, and suite selection. A failed target call scores zero instead of disappearing from the aggregate.

## Scorers

The three presets cover common AI workloads without locking the harness to one model type:


![Three mlv-eval presets: image2meta for labelled bounding boxes, query2rank for ranked identifiers, and text2json for structured extraction](https://mandalsuraj.com/images/blog/mlv-eval/presets.svg?v=2)

  Each preset pairs a target shape with scorers suited to that workload.

| Workload | Preset | Built-in scorers |
|---|---|---|
| Vision | `image2meta` | JSON Schema, field accuracy, and bounding-box IoU. |
| Retrieval | `query2rank` | hit@k and mean reciprocal rank. |
| Extraction | `text2json` | JSON Schema, exact match, field accuracy, and fuzzy text similarity. |

Built-in scorers cover overlap, ranking quality, schema validity, field accuracy, exact matches, and fuzzy text. A custom scorer can be any executable that accepts a case on standard input and returns a scored JSON verdict.

## CI Quality Gates

Thresholds turn aggregate scores into CI outcomes. A run exits `0` when every gate passes, `1` when quality falls below a gate, and `2` when configuration or execution fails.


![mlv-eval quality gate: passing thresholds exit 0, a broken quality gate exits 1, and configuration or runtime errors exit 2](https://mandalsuraj.com/images/blog/mlv-eval/gate.svg?v=2)

  Stable exit codes let the same evaluation run act as a CI quality gate.

| Exit code | Meaning |
|---|---|
| `0` | Every configured quality gate passed. |
| `1` | At least one score fell below its threshold. |
| `2` | Configuration, dataset, target, or runtime failure. |

Use `-json` to capture suite metrics and failed-case reasons for build artifacts or pull-request comments.

## Release

The v0.1.0 offline examples cover 30 cases across all three presets:

| Example | Cases | Result |
|---|---:|---|
| `image2meta` | 6 | Schema 1.000, fields 1.000, IoU 1.000. |
| `query2rank` | 16 | hit@5 0.938, MRR 0.875. |
| `text2json` | 8 | Schema 1.000, fields 0.875, fuzzy 0.875. |

---

# Keypath Building Intelligence

> A BACnet-backed operations dashboard with live monitoring, alert setup, network discovery tools, and handoff documentation for Algonquin College.

- URL: https://mandalsuraj.com/blog/keypath-building-intelligence
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2025-04-29
- Project date: 2025-03-13
- Tags: algonquin, dashboard, fullstack, python, grafana, bacnet, webdev, automation, contract
- Algonquin College: https://www.algonquincollege.com/

![Keypath Building Intelligence cover](https://mandalsuraj.com/images/blog/keypath-building-intelligence/cover.png)

I delivered this **client project** for an Algonquin College contract. The system turned BACnet building data into a clear operations view.

## Visual Proof

![Keypath Building Intelligence dashboard overview with selected campus readings](https://mandalsuraj.com/images/blog/keypath-building-intelligence/keypath-dashboard.jpg)

![Keypath Building Intelligence connection-status dashboard state](https://mandalsuraj.com/images/blog/keypath-building-intelligence/keypath-network-table.jpg)

![Keypath Building Intelligence device-point table with private address details partially redacted](https://mandalsuraj.com/images/blog/keypath-building-intelligence/keypath-reading-modal.jpg)

![Keypath Building Intelligence alert configuration workflow](https://mandalsuraj.com/images/blog/keypath-building-intelligence/keypath-alert-config.jpg)

Dashboard, connection state, point readings, and alert setup.

## What Shipped

| Area | Work | Why it matters |
|---|---|---|
| Operations dashboard | Built the readings, status, alerts, and context views. | Gives operators one place to inspect building state. |
| BACnet data path | Helped map devices and points into a stable product model. | Converts protocol data into useful names and states. |
| Monitoring | Added Grafana-backed system and telemetry checks. | Makes data health visible during operation. |
| Network discovery | Built Python tools for device inventory work. | Cuts manual discovery work. |
| Handoff | Wrote architecture, deployment, and operation notes. | Makes the first release easier to run and extend. |

## Architecture Overview

1. Building systems expose BACnet points and readings.
2. Discovery tools identify devices and their available points.
3. Backend services normalize the data.
4. Grafana tracks service and telemetry health.
5. The dashboard presents readings, status, and alerts.

```mermaid
flowchart LR
  accTitle: Keypath Building Intelligence Architecture
  accDescr: Campus systems move through device discovery, readable building data, operations storage, monitoring, and the dashboard.
  systems["<strong>Campus Systems</strong><br/><small>Building Automation Points</small>"] --> discovery["<strong>Find Devices</strong><br/><small>Build A Clear Inventory</small>"]
  discovery --> prepare["<strong>Prepare Readings</strong><br/><small>Use Stable Names And States</small>"]
  prepare --> data["<strong>Save Operations Data</strong><br/><small>Readings And History</small>"]
  data --> dashboard["<strong>Show Building State</strong><br/><small>Readings Status And Alerts</small>"]
  prepare --> health["<strong>Track Service Health</strong><br/><small>Telemetry And Checks</small>"]
  health --> monitoring["<strong>Monitor Operations</strong><br/><small>Find Problems Early</small>"]
```

## Delivery

The first release joined UI work, data access, discovery, monitoring, and documentation. The final handoff included a working demo and operating notes.

---

# libIGC Flight Log Parser

> A Python package that parses IGC glider logs into validated fixes, tasks, thermals, glides, and common export formats.

- URL: https://mandalsuraj.com/blog/libigc
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2024-09-30
- Project date: 2024-11-30
- Tags: python, data, gis, parsing, datascience
- Source: https://github.com/surajmandalcell/libigc
- PyPI package: https://pypi.org/project/libigc/

![libIGC Flight Log Parser cover](https://mandalsuraj.com/images/blog/libigc/cover.png)

IGC files are text logs written by flight recorders. `libIGC` turns those logs into Python objects that describe the route, altitude, flight state, thermals, glides, and task progress.

The examples below use the real `new_zealand.igc` file from the test suite. The cover route, terminal output, and numbers all come from that flight.

`libIGC` needs Python 3.12 or later.

```bash
pip install libigc
```


![Three-dimensional New Zealand flight path colored from blue to amber by altitude, above verified libIGC terminal output](https://mandalsuraj.com/images/blog/libigc/flight-visual.png)

  The approved cover diagram uses longitude, latitude, and altitude from 5,367 parsed fixes.

## What You Can Do With libIGC


    Flight Overview
    See The Whole Flight
    Find takeoff, landing, flight time, route shape, and altitude changes without reading raw recorder lines.


    Thermal Analysis
    Compare Every Climb
    See how long each thermal lasted, how much height it gained, and how quickly the glider climbed.


    Glide Analysis
    Measure Each Glide
    Measure distance, speed, altitude loss, and glide ratio between climbs.


    Course Progress
    Check Course Progress
    Load an LK8000 task and see when the flight reached each start, turnpoint, speed section, and goal.


    Reusable Exports
    Use Flight Data Anywhere
    Open KML in mapping tools or send CSV data to Python, R, spreadsheets, notebooks, and dashboards.


    Data Checks
    Catch Bad Flight Data
    Find broken time gaps, impossible altitude changes, sensor problems, missing dates, and incomplete flights.


## From One Command To A Flight Model

The repository includes a demo that runs the complete path. Give it an IGC file and an output directory.

```bash
uv run examples/libigc_demo.py \
  tests/testfiles/new_zealand.igc \
  -o output
```

The command validates the log, prints detected flight phases, and generates five files.

```text
Flight: Flight(valid=True, fixes: 5367, thermals: 27)
thermal[0]: Thermal(vertical_velocity=1.25 m/s, duration=4m 51s)
```

```mermaid
flowchart LR
  accTitle: libIGC Processing Flow
  accDescr: An IGC recorder log moves through parsing, validation, flight analysis, and export.
  %% caption: One public API turns recorder text into reusable flight data.
  log["<strong>IGC Log</strong><br/><small>A · B · H · I Records</small>"] --> parse["<strong>Parse</strong><br/><small>Build Fixes</small>"]
  parse --> validate["<strong>Validate</strong><br/><small>Time · Altitude</small>"]
  validate --> analyze["<strong>Analyze</strong><br/><small>Thermals · Glides</small>"]
  analyze --> export["<strong>Export</strong><br/><small>KML · CSV<br/>WPT · CUP</small>"]
```

| Generated file | What it contains | Useful in |
|---|---|---|
| `new_zealand-flight.kml` | Route, takeoff, landing, and thermal points | Google Earth and GIS tools |
| `new_zealand-flight.csv` | Fix time, position, bearing, speed, and state | Python, R, and spreadsheets |
| `new_zealand-thermals.csv` | Thermal entry and exit times | Custom analysis |
| `new_zealand-thermals.wpt` | Thermal waypoints | Navigation tools |
| `new_zealand-thermals.cup` | SeeYou thermal waypoints | Soaring software |

## The Code Behind The Command

`Flight.create_from_file` is the main API. Check `valid` before reading derived values because validation can stop analysis early.

```python
from libigc import Flight

flight = Flight.create_from_file("new_zealand.igc")
if not flight.valid:
    raise ValueError("; ".join(flight.notes))

print(len(flight.fixes))
print(flight.takeoff_fix)
print(flight.landing_fix)
print(len(flight.thermals), len(flight.glides))
```

Every valid B record becomes a `GNSSFix`. The parser keeps its time, coordinates, validity, pressure altitude, GNSS altitude, and extension text.

```mermaid
flowchart TB
  accTitle: IGC B Record Anatomy
  accDescr: A B record splits into record type, UTC time, latitude, longitude, validity, pressure altitude, and GNSS altitude.
  %% caption: The fixed-width recorder line becomes a typed point in the flight.
  raw["B1227484612592N01249579EA0043700493"]
  raw --> record["<strong>B</strong><br/><small>Record</small>"]
  raw --> time["<strong>122748</strong><br/><small>12:27:48 UTC</small>"]
  raw --> latitude["<strong>4612592N</strong><br/><small>Latitude</small>"]
  raw --> longitude["<strong>01249579E</strong><br/><small>Longitude</small>"]
  raw --> validity["<strong>A</strong><br/><small>Valid</small>"]
  raw --> pressure["<strong>00437</strong><br/><small>437 m Pressure</small>"]
  raw --> gnss["<strong>00493</strong><br/><small>493 m GNSS</small>"]
```

## What The New Zealand Flight Revealed

The sample crosses midnight UTC. `libIGC` repairs the day boundary before it calculates flight duration and state.

```mermaid
flowchart LR
  accTitle: New Zealand Flight Statistics
  accDescr: The parsed flight has 5,367 fixes, lasts 4 hours 19 minutes, covers 519 kilometers, and contains 27 thermals and 28 glides.
  %% caption: These values are calculated from the checked-in sample, not placeholder data.
  fixes["<strong>5,367</strong><br/><small>Valid Fixes</small>"] ~~~ airborne["<strong>4h 19m</strong><br/><small>Airborne</small>"]
  airborne ~~~ track["<strong>519 km</strong><br/><small>Recorded Track</small>"]
  track ~~~ thermals["<strong>27</strong><br/><small>Thermals</small>"]
  thermals ~~~ glides["<strong>28</strong><br/><small>Glides</small>"]
```

Each thermal has entry and exit fixes, duration, altitude gain, and average vertical speed. Each glide has distance, duration, average speed, altitude change, and glide ratio.

```python
for thermal in flight.thermals:
    print(thermal.time_change())
    print(thermal.alt_change())
    print(thermal.vertical_velocity())

for glide in flight.glides:
    print(glide.track_length)
    print(glide.speed())
    print(glide.glide_ratio())
```

## How The Cover Diagram Was Made

`libIGC` supplies the data. A small renderer turns each flying fix into an east, north, altitude point. This keeps the artwork tied to the real route.

```python
from math import cos, pi

fixes = flight.fixes[
    flight.takeoff_fix.index : flight.landing_fix.index + 1
]
lat0 = sum(fix.lat for fix in fixes) / len(fixes)
lon0 = sum(fix.lon for fix in fixes) / len(fixes)

route = [
    (
        (fix.lon - lon0) * 111_320 * cos(lat0 * pi / 180),
        (fix.lat - lat0) * 110_540,
        fix.alt,
    )
    for fix in fixes
]
```

The cover renderer rotates this 3D route for composition. It maps low altitude to blue, high altitude to amber, and keeps faint XYZ axes so the path retains depth.

## Check A Task

Tasks can come from an LK8000 `.lkt` file or be built from `Turnpoint` objects. The result is the fix at which each turnpoint was reached.

```python
from libigc import Task

task = Task.create_from_lkt_file("task.lkt")
reached = task.check_flight(flight)

for turnpoint, fix in zip(task.turnpoints, reached):
    print(turnpoint.kind, fix.rawtime)
```

The task checker supports start-enter, start-exit, cylinder, end-of-speed-section, and goal-cylinder logic within a task time window.

## Export The Result

The dumpers write common flight and waypoint formats. No private object conversion is needed.

```python
from libigc.lib.dumpers import (
    dump_flight_to_csv,
    dump_flight_to_kml,
    dump_thermals_to_cup_file,
    dump_thermals_to_wpt_file,
)

dump_flight_to_kml(flight, "flight.kml")
dump_flight_to_csv(flight, "track.csv", "thermals.csv")
dump_thermals_to_wpt_file(flight, "thermals.wpt", endpoints=True)
dump_thermals_to_cup_file(flight, "thermals.cup")
```

## Functionality At A Glance

| Area | What `libIGC` does |
|---|---|
| Records | Parses A, B, H, and I records and ignores unsupported record types |
| Metadata | Reads date, glider, class, recorder, firmware, hardware, GPS, and pressure-sensor fields when present |
| Fixes | Stores UTC time, timestamp, coordinates, validity, both altitudes, chosen altitude, speed, bearing, flying state, and circling state |
| Validation | Checks fix count, time gaps, midnight crossings, altitude range, altitude movement, date, takeoff, and usable altitude sensors |
| Geometry | Calculates Earth distance, bearing, and spherical angle |
| Flight state | Detects flying, takeoff, landing, straight flight, and circling with smoothed state sequences |
| Analysis | Builds thermal and glide sections with duration, climb, speed, distance, and ratio metrics |
| Tasks | Parses LK8000 tasks and checks timed cylinders against the flight |
| Exports | Writes WPT, CUP, KML, track CSV, and thermal CSV files |

## Tune Detection When Needed

The defaults cover normal logs. A custom `FlightParsingConfig` can change validation, landing, and thermal thresholds for another recorder or analysis rule.

```python
from libigc import Flight, FlightParsingConfig

class LongThermalConfig(FlightParsingConfig):
    min_time_for_thermal = 90.0

flight = Flight.create_from_file("flight.igc", LongThermalConfig)
```

## Why The State Looks Stable

Raw speed and bearing changes are noisy. `libIGC` uses a two-state Viterbi decoder for flying and circling, then applies time rules for landing and thermal duration.

That smoothing prevents one unusual fix from splitting a long glide or inventing a landing.

## Repository Evidence

The test suite covers record parsing, date changes, altitude checks, flight state, thermals, glides, tasks, geography, Viterbi smoothing, and every export format.


![libIGC README with installation, parsing, analysis, task, and export examples](https://mandalsuraj.com/images/blog/libigc/readme.png)


![libIGC GitHub repository with Python source, examples, and tests](https://mandalsuraj.com/images/blog/libigc/github.png)

---

# Darwin UI Component Library

> A macOS-inspired React 19 component library with glass surfaces, theme tokens, docs, charts, overlays, and a package pipeline for app-ready UI.

- URL: https://mandalsuraj.com/blog/darwin-ui
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-01-24
- Project date: 2025-12-30
- Tags: design-system, components, react, typescript, webdev
- Source: https://github.com/surajmandalcell/darwin-ui
- Docs site: https://darwin-ui.mandalsuraj.com
- npm package: https://www.npmjs.com/package/@pikoloo/darwin-ui

![Darwin UI Component Library cover](https://mandalsuraj.com/images/blog/darwin-ui/cover.png)

Darwin UI is a **React 19 component library** for compact desktop-style apps. It uses layered glass surfaces, clear controls, light and dark themes, and restrained motion.

## Visual Proof

![Darwin UI documentation page for agentic coding](https://mandalsuraj.com/images/blog/darwin-ui/docs-agentic-coding.png)

![Darwin UI documentation page showing progress components](https://mandalsuraj.com/images/blog/darwin-ui/docs-progress.png)

![Darwin UI homepage component showcase](https://mandalsuraj.com/images/blog/darwin-ui/home-components.png)

![Darwin UI desktop style example](https://mandalsuraj.com/images/blog/darwin-ui/desktop.png)

## Install

Install the package and import its compiled stylesheet once.

```bash
npm install @pikoloo/darwin-ui
```

```tsx
import { Button, Card } from "@pikoloo/darwin-ui";
import "@pikoloo/darwin-ui/styles.css";
```

Version 2.1 and later does not need a Tailwind `@source` rule.

## Package Shape

Tsup builds CommonJS, ESM, TypeScript declarations, and one CSS file. A `"use client"` banner marks the React output for client-rendered frameworks.

CSS variables define color, border, surface, type, and motion tokens. The same contract drives both themes.

## Components

The package has more than 35 components for app layouts, forms, data, overlays, feedback, charts, media, and utilities.

- A shared floating layer supports popovers and tooltips.
- Dialogs and menus use portals and keyboard focus behavior.
- Recharts powers the chart wrappers.
- Motion respects the reduced-motion setting.
- Loading, empty, icon, and error states are part of the main controls.

## Docs And Distribution

The docs show real states and examples. A shadcn-compatible registry supports single-component installs. Package checks build both outputs and validate the registry before release.

---

# Codex Proxy Developer Tool

> A Rust desktop tool that translates Anthropic Messages API requests into local ChatGPT Codex calls, with account, model, log, and setup controls.

- URL: https://mandalsuraj.com/blog/codex-proxy
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-05-24
- Project date: 2026-05-23
- Tags: developer-tools, rust, desktop, cli, openai, dashboard
- Source: https://github.com/surajmandalcell/codex-proxy

![Codex Proxy Developer Tool cover](https://mandalsuraj.com/images/blog/codex-proxy/cover.png)

Codex Proxy is a **local Rust compatibility bridge**. It lets a client that uses the Anthropic Messages API send work through one configured ChatGPT Codex account.

## Visual Proof

![Codex Proxy dashboard with account health, quick tests, and Claude Code configuration](https://mandalsuraj.com/images/blog/codex-proxy/dashboard-screenshot.png)

![Codex Proxy settings screen with server info and Claude model mapping controls](https://mandalsuraj.com/images/blog/codex-proxy/settings-screenshot.png)

![Codex Proxy account management screen with account status and quota controls](https://mandalsuraj.com/images/blog/codex-proxy/account-management.png)

## Request Flow

1. A client sends an Anthropic-format request to the loopback server.
2. The proxy maps messages, model names, tools, and stream events.
3. It sends the request through the configured ChatGPT session.
4. It converts the result to Anthropic-style server-sent events.

The server binds to `127.0.0.1` by default. The desktop app and proxy share process state, so account and log controls do not need a second control API.

## Desktop Controls

| Surface | Work |
|---|---|
| Account | Connect, import, refresh, replace, or remove one local account. |
| Client setup | Write or remove the proxy values in Claude Code settings. |
| Models | Map Claude aliases to current OpenAI model IDs. |
| Logs | Read live request and response events. |
| Tests | Send a small request from the app. |

## Install And Run

Rust 1.89 or later is required.

```bash
git clone https://github.com/surajmandalcell/codex-proxy
cd codex-proxy
cargo install --path .
codex-proxy
```

Use `codex-proxy serve` on a computer with no display.

## Local API

- `GET /health` returns server state.
- `GET /account` returns the configured account state.
- `POST /v1/messages` accepts Anthropic-compatible requests.

The default route uses the configured account only. Adding or importing an account replaces the current local account.

---

# ASR Pro

> A local-first Electron desktop transcription app with native Whisper, microphone capture, model management, transcript history, portable data, and startup controls.

- URL: https://mandalsuraj.com/blog/asrpro
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-05-16
- Project date: 2025-09-07
- Tags: ai, desktop, electron, whisper, react, typescript, appdev
- Source: https://github.com/surajmandalcell/asrpro
- Releases: https://github.com/surajmandalcell/asrpro/releases

![ASR Pro cover](https://mandalsuraj.com/images/blog/asrpro/cover.png)

ASR Pro is a **local desktop transcription app**. It records speech, runs Whisper on the computer, and keeps models, transcripts, settings, and logs in app-owned storage.

## Visual Proof

![ASR Pro home screen with recording workflow and stats](https://mandalsuraj.com/images/blog/asrpro/asrpro_home.jpg)

![ASR Pro models library with Whisper model options](https://mandalsuraj.com/images/blog/asrpro/asrpro_models_library.jpg)

![ASR Pro configuration screen with overlay and shortcut controls](https://mandalsuraj.com/images/blog/asrpro/asrpro_configuration.jpg)

![ASR Pro sound settings screen with microphone controls](https://mandalsuraj.com/images/blog/asrpro/asrpro_sound.jpg)

![ASR Pro history screen with transcript archive](https://mandalsuraj.com/images/blog/asrpro/asrpro_history.jpg)

![ASR Pro about screen with app identity and data folder](https://mandalsuraj.com/images/blog/asrpro/asrpro_about.jpg)

## Desktop Product

| Area | Work | Why it matters |
|---|---|---|
| Electron shell | Tray, global shortcut, waveform overlay, and secure preload API. | Keeps recording close without exposing Node to the page. |
| Native Whisper | Uses `@kutalia/whisper-node-addon` and whisper.cpp models. | Runs transcription without a hosted speech API. |
| Model library | Downloads, verifies, selects, and removes five model options. | Lets users choose speed, language, accuracy, and disk use. |
| Local history | Stores transcript text and source audio when available. | Keeps private work on the computer. |
| Portable data | Uses app-owned folders and repairs moved startup targets. | Supports portable Windows and Linux installs. |

## Native Engine Flow

1. The React renderer records microphone audio.
2. Web Audio converts it to mono 16 kHz WAV.
3. A context-isolated preload API sends the audio to Electron.
4. Electron runs the native Whisper addon.
5. The result returns to the renderer and local history.

The selected model downloads only when it is first needed. A checksum check runs before the model is used.

## Model And Data Design

| Model | Use |
|---|---|
| `whisper-tiny-en` | Fast English dictation. |
| `whisper-base-en` | Default English model. |
| `whisper-base` | Small multilingual model. |
| `whisper-small-en` | Higher English accuracy. |
| `whisper-large-v3-turbo` | Highest-accuracy bundled option. |

Windows and Linux packaged builds use a sibling `asrpro-data/` folder. Installed macOS builds use the standard app support folder.

## Run From Source

Development needs Node.js 20.19 or 22.12 or later.

```bash
git clone https://github.com/surajmandalcell/asrpro.git
cd asrpro
npm install
npm run electron:dev
```

If the native engine cannot load, reinstall dependencies for the current OS and CPU. If a moved app starts from an old path, turn startup launch off and on again.

---

# Stream Toolbox

> A media workspace that turns long videos into reviewed vertical clips.

- URL: https://mandalsuraj.com/blog/stream-toolbox
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2025-12-31
- Project date: 2025-10-16
- Tags: ai, media, video, dashboard, automation, fullstack

![Stream Toolbox cover](https://mandalsuraj.com/images/blog/stream-toolbox/cover.png)

Stream Toolbox turns long videos into short vertical clips. It keeps **selection, reframing, review, and output** in one operator workspace.

## Visual Proof

![Stream Toolbox create job screen with redacted source URL and recent jobs](https://mandalsuraj.com/images/blog/stream-toolbox/create-twitch-url-1080p.png)

![Stream Toolbox media manager showing generated clip folders](https://mandalsuraj.com/images/blog/stream-toolbox/media-manager-1080p.png)

Start with a source. Finish with organized, reviewable output.

## Outcome Flow

```mermaid
flowchart LR
  accTitle: Stream Toolbox Outcome Flow
  accDescr: A source video moves through moment selection, vertical framing, review, and organized output.
  source["<strong>Source Video</strong><br/><small>URL Or Upload</small>"] --> select["<strong>Find Strong Moments</strong><br/><small>Create Candidates</small>"]
  select --> reframe["<strong>Frame For Vertical</strong><br/><small>Keep The Subject Clear</small>"]
  reframe --> review["<strong>Review Clips</strong><br/><small>Check Media And Details</small>"]
  review --> output["<strong>Organize Output</strong><br/><small>Ready For The Next Step</small>"]
```

1. Add a URL or upload a video.
2. Find strong moments and create vertical candidates.
3. Keep the subject framed without distracting camera motion.
4. Review clips, thumbnails, and metadata together.
5. Retry failed work without restarting the whole job.

Each stage has a clear input and output. Implementation details stay encapsulated behind the workflow.

## Reframing Engine

The reframing engine follows the subject inside a stable safe area. It moves only when the composition needs correction.

Fallback framing keeps output usable when confident tracking is unavailable. The result favors watchable motion over constant correction.

## Operator Workspace

The dashboard supports repeat work: create a job, follow progress, inspect output, and resume from a known state.

## Result

The media manager keeps source files, clips, thumbnails, metadata, and drafts together. The operator sees what is ready, what failed, and what needs review without extra system noise.

---

# Switch AI Agent Account

> A small Go CLI for switching local app profiles by backing up and restoring file or folder configs for Codex, Claude, VSCode, Cursor, SSH, Git, and more.

- URL: https://mandalsuraj.com/blog/switch
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2025-12-29
- Project date: 2025-09-03
- Tags: go, cli, developer-tools
- Source: https://github.com/surajmandalcell/switch

![Switch AI Agent Account cover](https://mandalsuraj.com/images/blog/switch/cover.png)

Switch is a small **Go CLI for named local profiles**. It backs up and restores the file or folder that an app uses for its settings.

## Visual Proof


![Switch project mockup](https://mandalsuraj.com/images/blog/switch/interface.png)


![Switch README dark screenshot](https://mandalsuraj.com/images/blog/switch/readme-dark.png)

## Commands

The CLI supports a few direct commands:

- `switch` cycles the default app.
- `switch <app>` cycles profiles for one app.
- `switch <app> <profile>` targets a specific profile.
- `switch add` launches the setup wizard.
- `switch list` shows apps and profiles.
- `switch default <app>` changes the default app.
- `switch config` opens the config file.

The setup wizard detects known apps or accepts a custom file or folder. Direct commands keep common switches short.

## Storage Model

Switch stores its state in `~/.switch.toml`. Each app entry has a current profile, profile names, an active path, and a backup pattern.

Built-in templates cover Codex, Claude, VSCode, Cursor, SSH, and Git. Users can add any app that keeps its settings in a file or folder.

## File And Folder Switching

`copyPath` handles files and folders. Paths expand `~`, normalize Windows separators, and use clean forms for stable comparisons.

JSON profile checks ignore formatting changes. Folder profile checks use simpler file operations and do not promise a semantic comparison.

## Build And Test

The project needs Go 1.24.5 or later. Build and test it with the existing Makefile.

```bash
make test
make install
```

CI tests Ubuntu, macOS, and Windows builds. The tool has no daemon or background service.

---

# Lunatecz Client Website

> A cinematic Next.js platform for an artist and company running shows, events, services, shop flows, and wearable lighting products.

- URL: https://mandalsuraj.com/blog/lunatecz
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2025-12-19
- Project date: 2025-08-19
- Tags: nextjs, commerce, events, stripe, webdev, fullstack
- Live site: https://lunatecz.com
- Instagram: https://www.instagram.com/lunaivanaa
- YouTube: https://youtube.com/c/LUNAflyttefrem

![Lunatecz Client Website cover](https://mandalsuraj.com/images/blog/lunatecz/cover.png)

Lunatecz is the public site and operating platform for Luna Ivana. It joins an artist portfolio with events, services, products, inquiries, and admin tools.

## Visual Proof

![Lunatecz home viewport screenshot](https://mandalsuraj.com/images/blog/lunatecz/home_screen.png)

![Lunatecz shop viewport screenshot](https://mandalsuraj.com/images/blog/lunatecz/shop_screen.png)

![Lunatecz full home page screenshot](https://mandalsuraj.com/images/blog/lunatecz/home_full.png)

![Lunatecz full shop page screenshot](https://mandalsuraj.com/images/blog/lunatecz/shop_full.png)

## Product Scope

The public site uses full-width performance images, dark surfaces, bright LED color, and editorial type. Business actions stay clear within that visual style.

- Events support several date formats.
- The shop supports stock, carts, checkout, and orders.
- Contact forms create a clear inquiry path.
- Admin pages manage events, media, products, posts, customers, and orders.

![Lunatecz full about page screenshot](https://mandalsuraj.com/images/blog/lunatecz/about_full.png)

![Lunatecz full blog page screenshot](https://mandalsuraj.com/images/blog/lunatecz/blog_full.png)

## Architecture

The stack uses Next.js 16, React 19, TypeScript, Tailwind CSS 4, Drizzle, PostgreSQL, Clerk, Stripe, Redis, and Sentry.

The App Router separates public pages, admin pages, and API routes. Controllers own business rules. The Drizzle schema models contacts, posts, events, products, customers, carts, and orders.

## Safe Checkout

The checkout route validates its input and allowed redirect hosts. It reads product prices from PostgreSQL instead of trusting prices from the browser.

The Stripe webhook verifies its signature and handles repeat events by session ID. It then saves the customer and order snapshot, creates order items, and reduces stock.

Clerk and role checks protect admin routes. Redis caching has a local fallback, while Sentry reports production errors.

---

# Canada Post Conversational BI

> A four-person 2024 capstone I led: a BI system that turned plain-language questions into SQL-backed tables, charts, and follow-up analysis.

- URL: https://mandalsuraj.com/blog/canada-post-ai-assisted-bi
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2024-03-27
- Project date: 2024-05-09
- Tags: ai, datascience, openai, postgresql, react, nodejs, webdev, fullstack, college, bisi
- LinkedIn post: https://lnkd.in/p/gnQrrgWJ

![Canada Post Conversational BI cover](https://mandalsuraj.com/images/blog/canada-post-ai-assisted-bi/cover.png)

This four-person **Business Intelligence and System Infrastructure** capstone started at Algonquin College in February 2024.

  I led the team, split ownership across data, backend, React, and prompting, then brought it together around one goal: useful reports without writing SQL.

## What Canada Post BI Does


    01 · Plain Language
    Ask A Business Question
    Use plain language and optional filters. The app turns the request into a report plan.


    02 · SQL And Charts
    Build A Live Report
    The server runs the generated PostgreSQL query and returns a table with a bar or line chart.


    03 · Follow-Up
    Explore The Next Question
    Each report can suggest the next question, so an analyst can move from a total to a cause or region.


    04 · Query Cache
    Reuse Proven Queries
    Full-text search finds saved questions and popular reports before another model call is needed.


## Agentic BI Before OpenAI's Agent Products

This timeline keeps only milestones that changed the same workflow: plan a query, run data work, and return a usable report.


    Mar 2023
    [GPT-3.5 Turbo API](https://openai.com/index/introducing-chatgpt-and-whisper-apis/)
    OpenAI released the low-cost chat model that later powered our report planner.


    Jun 2023
    [Function Calling](https://openai.com/index/function-calling-and-other-api-updates/)
    OpenAI added JSON-schema function calls. Apps could turn natural language into structured tool or database requests.


    Jul 2023
    [Code Interpreter](https://help.openai.com/en/articles/6825453-chatgpt-release-notes)
    ChatGPT Plus gained file analysis, Python execution, charts, math, and file editing.


    Nov 2023
    [Assistants API And GPTs](https://openai.com/index/new-models-and-developer-products-announced-at-devday/)
    OpenAI combined instructions, retrieval, Code Interpreter, and function calling for purpose-built assistants.


    Feb 2024
    Canada Post BI
    Our app used GPT-3.5 Turbo to plan SQL and charts, query PostgreSQL, stream a report, and suggest the next question.


    May 2024
    [Interactive Data Analysis](https://openai.com/index/improvements-to-data-analysis-in-chatgpt/)
    ChatGPT added connected files, expandable tables, interactive charts, and chart downloads.


    Jan 2026
    [OpenAI Data Agent](https://openai.com/index/inside-our-in-house-data-agent/)
    OpenAI showed its internal agent for company data, business context, analysis, and reliable insight.


The capstone was narrow and purpose-built. Its core loop was already clear: ask in plain language, choose the data work, and return a report ready to use.

## Visual Proof

![Business question search and saved report suggestions](https://mandalsuraj.com/images/blog/canada-post-ai-assisted-bi/v2-search.png)

![Work centre failure report with chart and ranked table](https://mandalsuraj.com/images/blog/canada-post-ai-assisted-bi/v2-report.png)

![Query refinement controls and report preview](https://mandalsuraj.com/images/blog/canada-post-ai-assisted-bi/v2-query-help.png)

![Model, data, and session settings](https://mandalsuraj.com/images/blog/canada-post-ai-assisted-bi/v2-settings.png)

## Report Flow

```mermaid
flowchart LR
  accTitle: Canada Post BI Report Architecture
  accDescr: A question moves from the React client through the Node.js server, a saved query or model plan, PostgreSQL, and a live report.
  client["<strong>React Client</strong><br/><small>Question And Filters</small>"] --> server["<strong>Express + Socket.IO</strong><br/><small>Search + Report Events</small>"]
  server --> plan["<strong>Cache Or Model</strong><br/><small>Reuse SQL Or Plan A Report</small>"]
  plan --> data["<strong>PostgreSQL</strong><br/><small>Run The Query</small>"]
  data --> result["<strong>Live Report</strong><br/><small>Rows + Chart + Follow-Up</small>"]
```

The React app uses the Express API for filters, autocomplete, and frequent reports. It uses Socket.IO for report loading states and final report data.

The main OpenAI adapter used `gpt-3.5-turbo` with forced function calling and a low temperature. A local DeepSeek Coder adapter was also available.

PostgreSQL stores the master data and weighted full-text cache. The server executes the chosen query and sends rows and chart data back. The source data stays behind the server.

## Failure Volume Fell Faster Than Parcel Volume

The live chart uses separate zero-based scales, so each series keeps its real shape without a misleading second axis. Jul 24 carried the most work and failures.

| Day | Parcel Volume | Failure Volume |
|---|---:|---:|
| Jul 23 | 71,382 | 4,679 |
| Jul 24 | 519,040 | 39,283 |
| Jul 25 | 495,333 | 28,288 |
| Jul 26 | 458,266 | 19,668 |
| Jul 27 | 431,890 | 16,750 |
| Jul 28 | 294,387 | 7,440 |
| Jul 29 | 111,677 | 3,061 |

## Searchable Query Cache

Each saved question had a weighted search vector. Prime questions ranked first, annotations added context, and execution counts raised common questions.

```sql
"query_annotation" text,
"execution_count" int4 DEFAULT 1,
"prime_query" bool DEFAULT false,
"search_vector" tsvector GENERATED ALWAYS AS (
    setweight(to_tsvector('english', coalesce(query, '')), 'A') ||
    setweight(to_tsvector('english', coalesce("query_annotation", '')), 'B') ||
    setweight(to_tsvector('english', coalesce("execution_count"::text, '')), 'C') ||
    setweight(to_tsvector('english', CASE WHEN prime_query THEN 'true' ELSE 'false' END), 'D')
) STORED,
```

This cache reduced repeat model calls and made common questions appear sooner.

### GPT-3.5 Turbo Planned The Report

The OpenAI call forced one `report_generator` function. The function returned data SQL, optional chart SQL, chart fields, and follow-up questions as structured JSON.

```ts
const data = await openai.chat.completions.create({
  messages,
  model: "gpt-3.5-turbo",
  temperature: 0.08,
  tools,
  tool_choice: {
    type: "function",
    function: { name: "report_generator" },
  },
});
```

### Socket.IO Sent Partial And Final Results

The server first marked both views as loading. It then sent table rows, chart data, chart fields, and follow-up questions in the final event.

```ts
socket.emit("message_loading", {
  data_loading: true,
  chart_loading: true,
});

const report_data = await pool.query(ai_result.sql_data.replace(";", ""));

socket.emit("message_to_client", {
  success: true,
  report_data: report_data.rows,
  report_chart: {
    chart_type: CHART_TYPE[ai_result.report_chart.chart_type],
    xField: ai_result.report_chart.xField,
    yField: ai_result.report_chart.yField,
    chart_data: report_chart.rows,
  },
  suggestions: ai_result.suggestions,
});
```

The capstone ran against a controlled sample database. A production version should validate generated SQL and use a read-only PostgreSQL role before execution.

## Results

- The app returned limited reports in less than one second in most tests.
- Larger tests stayed below five seconds in most cases.
- The test database held more than 600,000 rows.
- The test server had four ARM64 CPU cores and 24 GB of memory.
- Model API use cost less than US$0.50 during the test phase.

The model layer was replaceable. This kept provider-specific setup outside the report flow.

---

# Terraform & Ansible Scalable IaC Project

> A college infrastructure project that uses Terraform to provision Azure resources and Ansible to configure the Linux VM fleet.

- URL: https://mandalsuraj.com/blog/terraform-ansible-final-ccgc
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2023-09-01
- Project date: 2023-08-21
- Tags: automation, college, ccgc, terraform, ansible, devops, infrastructure
- Source: https://github.com/surajmandalcell/automation-final-terraform-ansible

![Terraform & Ansible Scalable IaC Project cover](https://mandalsuraj.com/images/blog/terraform-ansible-final-ccgc/cover.png)

This was the final project for the **2023 Humber College CCGC Automation course**. My classmates and I split cloud provisioning from server setup.

## Architecture

![Terraform and Ansible infrastructure project cover](https://mandalsuraj.com/images/blog/terraform-ansible-final-ccgc/cover.png)

```mermaid
flowchart TB
  accTitle: Terraform And Ansible Architecture
  accDescr: Terraform provisions the Azure network, Linux fleet, and shared services. Ansible configures the Linux hosts.
  terraform["<strong>Terraform Modules</strong><br/><small>Provision Azure</small>"] --> network["<strong>Network Boundary</strong><br/><small>Virtual Network And Security</small>"]
  terraform --> compute["<strong>Linux Compute</strong><br/><small>Virtual Machine Fleet</small>"]
  terraform --> services["<strong>Shared Services</strong><br/><small>Data Protection And Monitoring</small>"]
  network --> balance["<strong>Load Balancer</strong><br/><small>Route Public Traffic</small>"]
  compute --> hosts["<strong>Linux Hosts</strong><br/><small>Three Configured Servers</small>"]
  balance --> hosts
  ansible["<strong>Ansible Roles</strong><br/><small>Configure The Hosts</small>"] --> hosts
  services --> database["<strong>PostgreSQL</strong><br/><small>Managed Database</small>"]
  services --> storage["<strong>Storage</strong><br/><small>Shared Data</small>"]
  services --> monitoring["<strong>Monitoring</strong><br/><small>Logs And Health</small>"]
  services --> recovery["<strong>Recovery</strong><br/><small>Backup Services</small>"]
```

**Terraform** owns the Azure resources. **Ansible** turns the Linux hosts into usable servers. This split made each failure easier to find.

### Terraform Modules

| Module | Purpose |
|---|---|
| `rgroup-RandomID` | Creates the resource group. |
| `network-RandomID` | Creates the virtual network, subnet, and security group. |
| `common-RandomID` | Creates monitoring, recovery, and storage services. |
| `vmlinux-RandomID` | Creates Linux VMs across availability zones. |
| `datadisk-RandomID` | Attaches 10 GB data disks to the VM fleet. |
| `loadbalancer-RandomID` | Places the Linux VM fleet behind a public load balancer. |
| `database-RandomID` | Creates Azure Database for PostgreSQL. |

The root module joins these modules and prints their outputs.

### Ansible Roles

| Role | Purpose |
|---|---|
| `datadisk-n01537188` | Partitions, formats, and mounts data disks. |
| `profile-n01537188` | Updates system profile values and session timeouts. |
| `user-n01537188` | Manages users, groups, SSH keys, and sudo access. |
| `webserver-n01537188` | Installs Apache, deploys a page, and starts the service. |

## Demo

Additional Videos

## Run The Project

### Ansible

Install Ansible, then run the playbook from its project folder.

```bash
sudo apt update
sudo apt install ansible
ansible-playbook  --verbose n01537188-playbook.yaml
```

### Terraform

Run these commands from the Terraform root module.

```bash
terraform init
terraform validate
terraform plan
terraform apply
```

Use the detailed exit code in automation. Remove the lab resources when the work is complete.

```bash
terraform plan -detailed-exitcode
terraform destroy
```

---

# My work at Pointo

> How I built Pointo's operations dashboard and platform services, and helped build the rider and driver backends.

- URL: https://mandalsuraj.com/blog/pointo-platform
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-08-11
- Project date: 2021-09-30
- Tags: pointo, mobility, dashboard, backend, fullstack, operations
- Pointo.in: https://www.pointo.in
- LinkedIn: https://www.linkedin.com/company/pointoindia

![My work at Pointo cover](https://mandalsuraj.com/images/blog/pointo-platform/cover.png)

Pointo was an on-demand e-rickshaw platform for local trips. It connected riders, drivers, and the team running the fleet through one ride lifecycle.

I worked as Pointo's **Full Stack Lead Developer**. I built the operations dashboard and its backend, and I owned the platform services. I worked with my team on the rider and driver backends.

The product has since shut down. This case study preserves the work without publishing customer or driver data.


![Pointo drivers map with synthetic vehicle positions](https://mandalsuraj.com/images/blog/pointo-platform/drivers-map-sanitized.webp)


![Pointo live-rides operations board with personal details obscured](https://mandalsuraj.com/images/blog/pointo-platform/live-rides-cards-redacted.png)


![Pointo live-rides data table with rider identifiers obscured](https://mandalsuraj.com/images/blog/pointo-platform/live-rides-data-redacted.png)


![Pointo driver records table with personal data obscured](https://mandalsuraj.com/images/blog/pointo-platform/drivers-data-redacted.png)


![Pointo rides map with synthetic rider, pickup, and destination positions](https://mandalsuraj.com/images/blog/pointo-platform/rides-map-sanitized.webp)



![Pointo driver detail dashboard with personal data obscured](https://mandalsuraj.com/images/blog/pointo-platform/driver-detail-redacted.png)

    A driver record joined verification, ride counts, income, and trip history.



![Pointo live ride control screen with rider and driver details obscured](https://mandalsuraj.com/images/blog/pointo-platform/ride-control-redacted.png)

    Operations could cancel, finish, reassign, or verify a live ride from one screen.


## What I built

Pointo was not a single booking screen. Each surface shared the same ride, driver, fare, and status model.

| Surface | What I worked on |
|---|---|
| Rider app backend | Built with my team: route and fare data, bookings, active trips, wallets, history, referrals, feedback, and emergency actions |
| Driver app backend | Built with my team: registration, verification, availability, ride requests, pickup, trip state, completion, and earnings |
| Operations dashboard and backend | Owned and built end to end: live rides, driver records, fleet state, assignment, cancellation, completion, and reporting |
| Platform services | Owned and built end to end: authentication, booking, location, payments, notifications, and real-time ride events |

## Fleet operations

I built the operations dashboard and its backend end to end.

```mermaid
flowchart LR
  accTitle: Pointo Fleet Operations
  accDescr: The operations dashboard turns live fleet state into records, controls, and reports.
  fleet["<strong>Live Fleet</strong><br/><small>Ride Cards And Maps</small>"] --> inspect["<strong>Inspect Records</strong><br/><small>Rides, Drivers, And Fares</small>"]
  inspect --> control["<strong>Control A Ride</strong><br/><small>Assign, Edit, Cancel, Or Finish</small>"]
  control --> report["<strong>Review Operations</strong><br/><small>Filters, Metrics, And Export</small>"]
```

## The platform behind the screens

I built the API and service layer that connected each product surface.

```mermaid
flowchart LR
  accTitle: Pointo Ride Platform
  accDescr: Rider and driver requests move through booking, matching, live ride state, trip control, and completion while operations shares the same state.
  rider["<strong>Rider App</strong><br/><small>Route And Trip Request</small>"] --> booking["<strong>Booking Services</strong><br/><small>Fare And Request State</small>"]
  driver["<strong>Driver App</strong><br/><small>Availability And Response</small>"] --> matching["<strong>Driver Matching</strong><br/><small>Available Drivers</small>"]
  booking --> matching --> live["<strong>Live Ride State</strong><br/><small>One Shared Lifecycle</small>"]
  operations["<strong>Operations Dashboard</strong><br/><small>Control And Recovery</small>"] <--> live
  live --> trip["<strong>Pickup And Trip</strong><br/><small>Controlled State Changes</small>"] --> complete["<strong>Completion</strong><br/><small>Payment, History, And Records</small>"]
```

The backend covered authentication, profiles, booking, location, ride requests, payments, wallets, referrals, notifications, and support workflows.

### Engineering choices

- **One ride model across products.** Rider, driver, and dashboard actions shared the same core states.
- **Real-time state with operational controls.** Location and ride events were paired with assignment and management actions.
- **Separate interfaces, consistent services.** Each product fit its audience while authentication, validation, state, and data access stayed consistent behind it.
- **Recovery in the product.** Connectivity loss, unavailable drivers, permissions, cancellation, and payment outcomes had explicit interface paths.

### Core stack

- **Dashboards:** React, Angular, TypeScript, Material UI, Bootstrap, and map tooling.
- **Services:** Node.js, Express, TypeScript, MySQL, Redis, Socket.IO, and background jobs.
- **Delivery:** Firebase, containerized services, CI/CD, AWS, and GCP.

## What the work shows

Pointo became a connected mobility product rather than a set of isolated screens. Riders had a complete trip flow, drivers had a working trip lifecycle, operations had live fleet tools, and the service layer kept those views synchronized.

The company and product are no longer operating, but the work still represents how I build: across web, backend, real-time systems, and the operational interfaces that make the rest usable.

---

# Blooms & Beyond Shopify Rebuild

> A Jammu flower and gifting store got a cleaner, faster storefront that is easier to shop and trust. Under the hood, the rebuild moved Shopify Liquid to Hydrogen with stronger UX, SEO, cart, and delivery flows.

- URL: https://mandalsuraj.com/blog/blooms-and-beyond
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-05-25
- Project date: 2026-05-06
- Tags: shopify, hydrogen, commerce, seo, react, webdev, fullstack
- Live store: https://bloomsandbeyond.shop/
- Instagram: https://www.instagram.com/bloomsandbeyond.jammu/
- Facebook: https://www.facebook.com/profile.php?id=61584696810091

![Blooms & Beyond Shopify Rebuild cover](https://mandalsuraj.com/images/blog/blooms-and-beyond/cover.png)

Blooms & Beyond was a working Shopify shop. I rebuilt its Liquid storefront in **Hydrogen** while Shopify kept products, carts, checkout, customers, and store operations.

## Before And After

![Blooms & Beyond Hydrogen home page with gift categories and product rows](https://mandalsuraj.com/images/blog/blooms-and-beyond/mockup-home-hero.png)

### Homepage

The new home page leads with delivery, search, categories, occasions, a campaign, and bestsellers.

Move the divider to compare the Liquid theme and Hydrogen rebuild.

### Collection Browsing

Collections now keep category links, stock, price, sort, and layout controls near the product grid.

### Product Page

The product page puts the gallery, price, variants, gift note, quantity, delivery help, cart, FAQs, and recommendations in one order.

### Mobile Shopping

Mobile keeps the menu, cart, location, search, categories, products, and support actions within reach.

## Commerce Architecture

| Layer | Work |
|---|---|
| Shopify | Keeps products, collections, customers, carts, checkout, and admin data. |
| Hydrogen | Owns routes, loaders, product UI, cart actions, search, and customer pages. |
| Storefront API | Supplies typed catalog and content data to each route. |
| Oxygen | Runs the production storefront and its release workflow. |

The quick cart supports add, update, and remove actions. Product choices stay in the URL. Gift notes use cart line values, and order notes stay editable in the cart.

## Delivery And Support

Eligible orders show same-day Jammu delivery. The cart states the 15 km delivery area and builds a cart-aware WhatsApp quote for longer routes.

WhatsApp also supports urgent timing, detailed personalization, address questions, and product changes before checkout.

## SEO And Release Checks

The shared SEO helper creates titles, descriptions, canonical URLs, social metadata, and route rules. Product, organization, search, and florist JSON-LD describe key pages.

Sitemap routes cover products, pages, collections, blogs, and articles. Account pages use `noindex` and `no-store` rules.

The release workflow installs dependencies, runs lint, tests, type checks, builds the Hydrogen app, and deploys to Oxygen.

---

# Highrays Brand And Campaign Platform

> A combined case study for the Highrays umbrella brand site and TheHighraysYT campaign platform, covering Next.js 16, Drizzle/Postgres, payments, admin tooling, attribution, SEO, and Cloudflare deployment work.

- URL: https://mandalsuraj.com/blog/highrays
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2026-05-24
- Project date: 2025-12-02
- Tags: highrays, nextjs, commerce, payments, dashboard, postgresql, cloudflare, webdev, fullstack
- Highrays site: https://www.thehighrays.com/
- HighraysYT: https://www.thehighraysyt.com/
- Instagram: https://instagram.com/thehighrays
- LinkedIn: https://linkedin.com/company/thehighrays
- Facebook: https://facebook.com/thehighrays
- X: https://twitter.com/thehighrays

![Highrays Brand And Campaign Platform cover](https://mandalsuraj.com/images/blog/highrays/cover.png)

Highrays has two connected products. One presents the umbrella brand. The other sells and runs video ad campaigns.

## Visual Proof

![TheHighrays root homepage with digital success brand messaging](https://mandalsuraj.com/images/blog/highrays/highrays-root-home.png)

![TheHighRays homepage with video ad campaign package preview](https://mandalsuraj.com/images/blog/highrays/highraysyt-home.png)

![TheHighrays umbrella brand page with YouTube growth service visuals](https://mandalsuraj.com/images/blog/highrays/highrays-brand.png)

![TheHighRays pricing page with campaign package cards](https://mandalsuraj.com/images/blog/highrays/highraysyt-pricing.png)

![TheHighRays blog page and content library](https://mandalsuraj.com/images/blog/highrays/highraysyt-journal.png)

Umbrella brand, campaign home, pricing, and content screens.

## At A Glance

| Surface | What it became | Why it matters |
|---|---|---|
| `highrays-root` | Umbrella brand site with HighraysYT and Elec3D routes. | Brand, SEO, leads, and newsletter capture. |
| `highrays-yt` | Campaign commerce and operations platform. | Pricing, checkout, admin, media, attribution, and payments. |
| Shared stack | Next.js 16, React 19, Tailwind CSS 4, Drizzle, PostgreSQL, Sentry. | One typed base for public and operating flows. |

## Campaign Flow

Customers can choose a direct package or ask for a callback before purchase.

![TheHighRays campaign flow showing direct and assisted journeys](https://mandalsuraj.com/images/blog/highrays/highraysyt-campaign-flow.png)

## Commerce And Admin

| System | What it handles |
|---|---|
| Pricing and checkout | Package tiers, country-aware gateway routing, Stripe, PayU, and purchase records. |
| Admin CMS | Blog editor, portfolio manager, pricing manager, media browser, settings, users, sessions, and IP bans. |
| Attribution | UTM capture, first-touch and last-touch journey tracking, Meta Pixel and Conversions API deduplication. |
| Communications | Resend email templates, notifications, callback flows, and lead capture. |
| Audit | Correlation IDs, actor data, resource IDs, gateway events, and database guards. |

Stripe handles international checkout. PayU handles checkout in India. Both paths verify return events and protect repeat updates.

## Deployment Complexity

OpenNext builds TheHighraysYT for Cloudflare Workers. The app uses split workers because one Next.js bundle exceeded edge size limits.

| Constraint | Engineering response |
|---|---|
| Large Next.js app on edge limits | Split worker topology instead of forcing everything into one bundle. |
| Database access from Workers | Uses Hyperdrive and request-scoped database clients. |
| Checkout paths | Keeps gateway callbacks and webhooks on known production routes. |
| Release checks | Audits client boundaries, checks worker size, and runs a dry deployment before release. |

---

# 3D Printer Color Management

> A Next.js and Supabase dashboard for tracking filament spools, printers, assignments, presets, photos, and usage.

- URL: https://mandalsuraj.com/blog/3dtoolbox
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2025-12-07
- Project date: 2025-11-29
- Tags: 3d-printing, inventory, nextjs, supabase, dashboard, webdev, fullstack, appdev

![3D Printer Color Management cover](https://mandalsuraj.com/images/blog/3dtoolbox/cover.png)

3D Toolbox shows the live link between **spools, printers, materials, and print jobs**. It replaces workshop memory with a fast inventory view.

## Visual Proof

![3D Toolbox busy dashboard screen](https://mandalsuraj.com/images/blog/3dtoolbox/busy-dashboard.png)

![3D Toolbox filament grid screen](https://mandalsuraj.com/images/blog/3dtoolbox/filaments-grid.png)

![3D Toolbox filament inventory list](https://mandalsuraj.com/images/blog/3dtoolbox/filaments-list.png)

![3D Toolbox printer assignment screen](https://mandalsuraj.com/images/blog/3dtoolbox/printers.png)

Inventory, filament, and printer assignment views.

## Architecture

The app uses Next.js 16, React 19, TypeScript, Tailwind CSS 4, TanStack Query, and Supabase.

| Layer | Work |
|---|---|
| Local mode | Stores printers, filaments, preferences, and timestamps in `localStorage`. |
| Cloud mode | Adds auth, images, presets, assignments, analytics, and row-level security. |
| Query layer | Caches reads, prefetches tabs, and loads printer assignments in one bulk query. |

## Workshop Flows

### Grouped Filament

The list groups equal spools by brand, color, material, diameter, and custom values. It merges counts and removes repeated assignments.

### Printer Slots

`@dnd-kit/core` links a spool to a printer slot with drag and drop. The active slot gets a clear focus ring and scale change.

### Usage

Usage logs can reduce the saved spool weight. Photos, presets, search, and region-specific brand data make each record useful at the workbench.

---

# IveEaten Food Memory App

> A Flutter mobile app for remembering restaurants and dishes, with offline Hive storage, Riverpod state, cloud sync history, photos, tags, ratings, and export tools.

- URL: https://mandalsuraj.com/blog/iveeaten
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2025-12-30
- Project date: 2025-08-20
- Tags: flutter, mobile, offline-first, firebase, appdev

![IveEaten Food Memory App cover](https://mandalsuraj.com/images/blog/iveeaten/cover.png)

IveEaten is a private food journal. It remembers **restaurants, dishes, ratings, photos, and notes** after discovery apps stop being useful.

The app works without an account. It saves each change on the device first and uses cloud sync only when the user asks for it.

## Visual Proof

![IveEaten home screen](https://mandalsuraj.com/images/blog/iveeaten/home.png)

![IveEaten settings and sync screen](https://mandalsuraj.com/images/blog/iveeaten/settings.png)

![IveEaten mobile screenshot from fresh capture](https://mandalsuraj.com/images/blog/iveeaten/mobile-home.png)

![IveEaten Pixel 7 mobile screenshot](https://mandalsuraj.com/images/blog/iveeaten/mobile-pixel7.png)

## Current Stack

The current app uses Flutter, Dart, Riverpod, go_router, Hive, Firebase Auth, Cloud Firestore, geolocator, image_picker, photo_view, and Material 3.

It moved from React Native and Expo to Flutter. Riverpod replaced hooks, go_router replaced Expo Router, Hive replaced AsyncStorage, and Flutter widgets replaced the old UI stack.

## Data Model

Restaurants can store an address and GPS location. Dishes can store a rating, description, notes, price, tags, and up to five photos.

Hive saves each change first. This keeps the full journal available offline.

## State And Sync

Riverpod providers update local state, then start optional Firebase sync for signed-in users. Smart sync uses the last change when local and cloud copies conflict.

Sync failure does not block app startup. Users can also choose one-way upload or download.

## Data Ownership

Settings include sign-in, sync, upload, download, JSON export, JSON import, and local data removal. Distance sorting and search also work from the local data.

---

# Local Delivery App

> Shipped a complete food delivery platform in 3 months. Flutter app with real-time order tracking, React admin dashboard with analytics, push notifications, payment integration.

- URL: https://mandalsuraj.com/blog/madebymaa
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2023-03-27
- Project date: 2023-03-27
- Tags: madebymaa, flutter, mobile, react, dashboard, commerce, webdev, fullstack, appdev
- Official site: https://madebymaa.in/
- Play Store: https://play.google.com/store/apps/details?id=com.madebymaa.food
- App Store: https://apps.apple.com/in/app/madebymaa/id6737498686
- Instagram: https://www.instagram.com/eat_madebymaa/
- LinkedIn: https://www.linkedin.com/company/madebymaa

![Local Delivery App cover](https://mandalsuraj.com/images/blog/madebymaa/cover.png)

MadeByMaa connected home cooks with customers who wanted meal plans and local delivery. A freelance team shipped the full platform in **three months**.

*The client later stopped the original build. The brand now has a public site and apps.*

## My Work

I built the React admin dashboard and its API routes. I also helped set up push notifications, analytics, and Crashlytics.

The dashboard managed users, vendors, delivery partners, orders, settlements, banners, and service settings.

## Platform

- **Flutter:** customer and food maker apps.
- **React:** admin dashboard.
- **Node.js and Express:** dashboard, seller, user, cart, order, upload, auth, and payment routes.
- **Firebase:** data, storage, notifications, analytics, and crash reports.
- **Stripe:** payments.
- **Google Maps:** location services.

## Visual Proof

![Cover](https://mandalsuraj.com/images/blog/madebymaa/cover.png)
![Cover](https://mandalsuraj.com/images/blog/madebymaa/cover_big.png)

### App Screens

![Screenshot 1](https://mandalsuraj.com/images/blog/madebymaa/screenshot_1.png)

![Screenshot 2](https://mandalsuraj.com/images/blog/madebymaa/screenshot_2.png)

![Screenshot 3](https://mandalsuraj.com/images/blog/madebymaa/screenshot_3.png)

![Screenshot 4](https://mandalsuraj.com/images/blog/madebymaa/screenshot_4.png)

---

# Art Crossword Puzzle

> Built a branded weekly React crossword for Art Fervour, with JSON clue sets, responsive play, completion timing, analytics, social sharing, and a finish flow that promoted more games.

- URL: https://mandalsuraj.com/blog/artfervour-crossword
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2024-03-27
- Project date: 2020-10-09
- Tags: artfervour, game, react, webdev
- Art Fervour: https://artfervour.com/
- Instagram: https://www.instagram.com/art.fervour
- LinkedIn: https://www.linkedin.com/company/artfervour/
- Facebook: https://www.facebook.com/share/1Az19umPhL/

![Art Crossword Puzzle cover](https://mandalsuraj.com/images/blog/af-crossword/coverv2.png)

I built a weekly **React crossword** for Art Fervour. Players used clues to name artists, then shared or opened another game.

## Campaign Flow

- Dated JSON files supplied each weekly clue set.
- A React crossword component handled the grid.
- Sass and styled-components applied the brand style.
- Analytics tracked play and completion events.
- The finish page offered restart, sharing, and more games.

The static build worked on phones and desktop browsers. New levels only needed a new clue file.

## Visual Proof

![Art Fervour crossword cover](https://mandalsuraj.com/images/blog/af-crossword/coverv2.png)

### Game Screens

![crossword preview 3](https://mandalsuraj.com/images/blog/af-crossword/3.png)

![crossword preview 2](https://mandalsuraj.com/images/blog/af-crossword/2.png)

![crossword preview 4](https://mandalsuraj.com/images/blog/af-crossword/4.png)

![crossword preview 1](https://mandalsuraj.com/images/blog/af-crossword/1.png)

---

# Covid19 Tracker

> Real-time COVID-19 dashboard for India. Angular 9 PWA with live case tracking, recovery trends, and installable offline support. Built and shipped when the pandemic hit.

- URL: https://mandalsuraj.com/blog/covid-tracker
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2020-03-20
- Project date: 2020-09-14
- Tags: covid, dashboard, angular, pwa, webdev, appdev
- Source: https://github.com/surajmandalcell/covid-tracker-India
- Live PWA: https://covid.surajmandal.in

![Covid19 Tracker cover](https://mandalsuraj.com/images/blog/covid-tracker/cover.png)

I shipped this **Angular 9 PWA** during the early COVID-19 pandemic. It gave users a quick view of India and global case data.

## Product Scope

- India totals and state data.
- Global totals and country search.
- Charts, news, and health guidance.
- Light and dark themes.
- Firebase hosting and PWA installation.

Public data sources changed often. I updated search, state pages, news pages, and service worker behavior as the project ran.

## Visual Proof

![Cover](https://mandalsuraj.com/images/blog/covid-tracker/cover.png)

### Desktop And Mobile Screens


![Desktop home in dark mode](https://mandalsuraj.com/images/blog/covid-tracker/home_desktop_dark.png)


![Desktop home in light mode](https://mandalsuraj.com/images/blog/covid-tracker/home_desktop_light.png)


![Desktop statistics in dark mode](https://mandalsuraj.com/images/blog/covid-tracker/stats_desktop_dark.png)


![Desktop statistics in light mode](https://mandalsuraj.com/images/blog/covid-tracker/stats_desktop_light.png)


![Mobile home in dark mode](https://mandalsuraj.com/images/blog/covid-tracker/home_dark_new.png)


![Mobile home in light mode](https://mandalsuraj.com/images/blog/covid-tracker/home_light_new.png)


![Mobile statistics in dark mode](https://mandalsuraj.com/images/blog/covid-tracker/stats_dark.png)


![Mobile statistics in light mode](https://mandalsuraj.com/images/blog/covid-tracker/stats_light.png)

---

# Elementary RemiX

> Cherry-picked the best icons from multiple packs and unified them into one cohesive theme. Pixel-tuned for Elementary OS wingpanel sizing and HiDPI displays.

- URL: https://mandalsuraj.com/blog/elementary-remix
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2019-05-05
- Project date: 2019-05-10
- Tags: linux, desktop, theming, linux-icon-theme, photoshop
- Source: https://github.com/surajmandalcell/elementary-remiX

![Elementary RemiX cover](https://mandalsuraj.com/images/blog/elementary-remix/cover.png)

Elementary RemiX combines several icon sets into one **elementary OS theme**. The main work was careful selection, sizing, naming, and fallback control.

## Theme Coverage

- Elementary, Cupertino, Breeze, and GNOME fallbacks.
- Wingpanel icons and power, volume, and terminal states.
- MIME types, folders, places, and app aliases.
- App icons for tools such as Android Studio, Discord, and GitKraken.
- HiDPI assets in `@2x` and `@3x` folders.

The fixed sizes keep panel icons aligned. The aliases also prevent apps from falling back to a different visual style.

## Visual Proof

![Elementary RemiX icon theme on the elementary OS desktop](https://mandalsuraj.com/images/blog/elementary-remix/main.png)

---

# Elementary X

> Rewrote the Elementary OS GTK stylesheet to swap window controls for macOS-style traffic lights. Light and dark variants, full Pantheon desktop integration, GTK 3.22+.

- URL: https://mandalsuraj.com/blog/elementary-x
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2018-01-23
- Project date: 2018-09-19
- Tags: linux, theming, elementary-os, os-theme, css
- Source: https://github.com/surajmandalcell/elementary-x
- Project page: https://surajmandalcell.github.io/elementary-x/

![Elementary X cover](https://mandalsuraj.com/images/blog/elementary-x/cover.png)

Elementary X adds macOS-style window controls to **elementary OS and Pantheon**. It supports GTK 3.22 and later.

## What Changed

The theme includes light and dark styles, title button assets, GTK imports, and Pantheon fixes. It also covers Plank, notifications, tabs, fonts, and desktop scripts.

I kept the theme close to upstream styles. This made the controls feel native across the shell instead of added to one window.

## Visual Proof

![Cover](https://mandalsuraj.com/images/blog/elementary-x/cover.png)

### Desktop Screens

![System Settings](https://mandalsuraj.com/images/blog/elementary-x/system-settings.png)

![File Manager](https://mandalsuraj.com/images/blog/elementary-x/file-manager.png)

![Terminal](https://mandalsuraj.com/images/blog/elementary-x/terminal.png)

![File Manager Light](https://mandalsuraj.com/images/blog/elementary-x/file-manager-light.png)

---

# Potato Dark

> Hugo blog theme for writers who want dark aesthetics without the bloat. Responsive layouts, related posts, Medium-style image zoom. Elegance in under 100KB.

- URL: https://mandalsuraj.com/blog/potato-dark
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2018-03-27
- Project date: 2018-06-27
- Tags: hugo, template, blog, css, theming, webdev
- Source: https://github.com/surajmandalcell/potato-dark
- Theme demo: https://surajmandalcell.github.io/potato-dark/

![Potato Dark cover](https://mandalsuraj.com/images/blog/potato-hugo-blog-theme/cover.png)

Potato Dark is a small **Hugo theme for long-form writing**. It keeps dark pages clear without a large front-end stack.

## Included Features

- Tags, related posts, and responsive layouts.
- Open Graph and Twitter metadata.
- Social links and Mastodon `rel="me"` support.
- Google Analytics integration.
- Disqus, Commento, and Coral hooks.
- A `zoom-img` shortcode with `zoom.js`.

## Visual Proof

![Potato Dark Hugo theme article page](https://mandalsuraj.com/images/blog/potato-hugo-blog-theme/main.png)

---

# Elegant SDDM

> Stripped the noise from Linux login screens. QML-based SDDM theme for KDE Plasma with clean typography, subtle animations, no visual clutter. Just type your password.

- URL: https://mandalsuraj.com/blog/elegant-sddm
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2018-01-24
- Project date: 2018-01-24
- Tags: linux, desktop, theming, qml
- Source: https://github.com/surajmandalcell/Elegant-sddm

![Elegant SDDM cover](https://mandalsuraj.com/images/blog/sddm-theme/cover.png)

Elegant SDDM is a **quiet Linux login theme** for KDE Plasma. QML defines the interface and its state changes.

## Login Flow

The theme handles user, session, password, and power states. It also supports keyboard navigation and session icon detection.

A soft background change and avatar glow show progress during sign-in. The SDDM greeter mode provides a direct test path.

## Visual Proof

![Elegant SDDM login screen with a dark blurred background](https://mandalsuraj.com/images/blog/sddm-theme/main.png)

*The visual direction comes from `linuxdeepin/dde-session-ui`.*

---

# Gtk Alt Documentation

> The GTK theming reference I wished existed. CSS selectors, widget hierarchy, inspector tricks, and real examples. Everything you need to build a Linux desktop theme from zero.

- URL: https://mandalsuraj.com/blog/gtk-theming-guide
- Author: Suraj Mandal (https://mandalsuraj.com)
- Published: 2017-02-24
- Project date: 2017-03-15
- Tags: linux, theming, docs-as-code, hugo, static-site, css, webdev
- Source: https://github.com/surajmandalcell/Gtk-Theming-Guide
- Docs site: https://gtkthemingguide.surajmandal.in

![Gtk Alt Documentation cover](https://mandalsuraj.com/images/blog/gtk-theming-guide/cover.png)

GTK theming facts were spread across forums, source trees, and tests. I put the useful parts into one **Hugo reference site**.

## What The Guide Covers

- GTK Inspector setup and theme search paths.
- GTK 2 and GTK 3 differences.
- CSS imports, selectors, and widget nodes.
- Icon theme folders and cache refreshes.
- Common file permission errors.

The project grew through focused updates to setup pages, selector notes, tools, FAQs, and site formatting.

## Visual Proof

![Current GTK theming guide home page](https://mandalsuraj.com/images/blog/gtk-theming-guide/Gtk-theming-guide.png)

### Original Site

![Original GTK theming guide from 2017](https://mandalsuraj.com/images/blog/gtk-theming-guide/main.png)
