B2B contractor · Remote · Open to EU/US
I'm Damián, a full stack engineer .NET and TypeScript systems, currently working on a global clinical study platform for a US client in a regulated environment. I have shipped production software across backend APIs, cloud infrastructure and modern React frontends. Outside of client work I build my own projects and tools that you can checkout on this website!
Working on a global Web application for a major US client in the medical field. The software supports clinical studies and clinical trial data collection worldwide. The project has an international development team and operates in a regulated environment.
Aug 2025 - PresentDesigning and implementing an application for interactive visualization of autonomous driving data, enhancing both user engagement and data clarity. Simultaneously developing an admin dashboard for Audi services to manage Azure user data and privileges across internal projects.
Dec 2024 - Aug 2025Began as an intern and advanced to a pivotal position with complete accountability for managing the company's internal web/desktop applications, which are utilized by software engineers for reporting and collecting ultrasound testing data.
Jun 2022 - Dec 2024A remote Model Context Protocol server in C# that exposes tools to Claude over Streamable HTTP, persisting to Postgres through EF Core. Authentication is mandatory and production-shaped: it runs as an OAuth 2.1 resource server, validating JWTs issued by WorkOS AuthKit and enforcing an email allowlist on every single call. Built on the official MCP C# SDK and hosted behind public HTTPS so claude.ai can connect to it directly.
C# 97.8%, Dockerfile 2.2% · 11 commits · updated 17/07/2026 · View on GitHub
A Model Context Protocol server (official C# SDK,
ModelContextProtocol 2.0.0-preview.1) that stores facts about Bobi the cat. It runs as a
Streamable HTTP server and persists to Postgres (Supabase) via EF Core.
| Tool | Arguments | Description |
|---|---|---|
get_facts | – | Return all facts about Bobi. |
insert_fact | content: string | Add a new fact; returns the created fact. |
delete_fact | id: int | Delete a fact by id; returns if it hit. |
src/BobMcp.Server/
Models/Fact.cs EF Core entity
Dtos/ Wire DTOs (FactDto, DeleteResultDto)
Data/BobiDbContext.cs EF Core DbContext
Data/DesignTimeDbContextFactory.cs For `dotnet ef`
Migrations/ EF Core migrations (Npgsql)
Services/IFactService.cs Injectable service abstraction
Services/FactService.cs EF Core implementation (IDbContextFactory)
Tools/FactTools.cs [McpServerToolType] — thin handlers, delegate to service
Program.cs Host + DI + HTTP MCP wiring
src/BobMcp.Client/ A real MCP client (HTTP) used to test the server
The tool layer holds no logic — every tool maps arguments to an injected IFactService
call, which is the only place that touches the database.
| Env var | Required | Default |
|---|---|---|
BOBI_DB_CONNECTION | yes | – |
BOBI_HTTP_URL | no | http://localhost:5111 |
AUTH_ISSUER | yes | – |
MCP_RESOURCE | yes | – |
ALLOWED_EMAILS | yes | – |
Authentication is mandatory (see Authentication): if AUTH_ISSUER,
MCP_RESOURCE, or ALLOWED_EMAILS is missing the server throws on startup and will not
run — there is no unauthenticated mode.
BOBI_DB_CONNECTION is an Npgsql key/value string (not a postgresql:// URI). For
Supabase use the Session pooler with channel binding disabled:
Host=aws-1-eu-central-1.pooler.supabase.com;Port=5432;Username=postgres.<project-ref>;Password=<pw>;Database=postgres;SSL Mode=Require;Trust Server Certificate=true;Channel Binding=Disable
Channel Binding=Disableis required — Supavisor rejects Npgsql's default SCRAM channel binding and otherwise returns a misleading28P01 password authentication failed.
dotnet build BobMcp.slnx -c Release
BOBI_DB_CONNECTION="Host=...;Channel Binding=Disable" \
AUTH_ISSUER="https://your-app.authkit.app" \
MCP_RESOURCE="http://localhost:5111/mcp" \
ALLOWED_EMAILS="you@gmail.com" \
dotnet src/BobMcp.Server/bin/Release/net10.0/BobMcp.Server.dll
The auth vars are required — the server throws on startup without them. See Authentication.
The MCP endpoint is http://localhost:5111/mcp. The server applies EF Core migrations on
startup.
dotnet src/BobMcp.Client/bin/Release/net10.0/BobMcp.Client.dll # localhost:5111
dotnet src/BobMcp.Client/bin/Release/net10.0/BobMcp.Client.dll https://host/mcp
Or with curl:
curl -i -X POST http://localhost:5111/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
dotnet ef migrations add <Name> --project src/BobMcp.Server
The server is an OAuth 2.1 resource server, and auth is required — it refuses to
start unless AUTH_ISSUER, MCP_RESOURCE, and ALLOWED_EMAILS are all set. It never
shows a login page itself — it validates a JWT access token on every /mcp call and only
lets through tokens whose email claim is in ALLOWED_EMAILS. The actual "sign in with Google" flow is run by
WorkOS AuthKit, which acts as the OAuth
authorization server. claude.ai (the MCP client) drives the whole flow: it discovers
AuthKit from /.well-known/oauth-protected-resource, registers itself (DCR), sends you to
Google to log in, then retries with Authorization: Bearer <token>.
claude.ai ──initialize──▶ /mcp ──401 + WWW-Authenticate──▶ claude.ai
claude.ai ──discovers──▶ WorkOS AuthKit ──Google login──▶ access token (aud = MCP_RESOURCE)
claude.ai ──Bearer token──▶ /mcp ──validate JWT + email allowlist──▶ tools
Why AuthKit and not Google directly: Google's OAuth doesn't support Dynamic Client Registration and won't scope tokens to this server, both of which MCP clients need.
The wiring lives in Auth/AuthenticationExtensions.cs:
AddJwtBearer validates the token, .AddMcp(...) serves the resource metadata, and an
authorization policy enforces the email allowlist.
"email": "{{ user.email }}" so the access token carries the email claim the
allowlist checks.https://<host>/mcp. This becomes the token's aud. (Without it AuthKit uses a
default environment-scoped aud, which won't match MCP_RESOURCE.)https://your-app.authkit.app) — that's AUTH_ISSUER.AUTH_ISSUER=https://your-app.authkit.app # AuthKit domain (the OAuth issuer)
MCP_RESOURCE=https://<host>/mcp # must match the AuthKit Resource Indicator + the URL you add in claude.ai
ALLOWED_EMAILS=you@gmail.com # comma-separated allowlist
claude.ai connects to remote MCP servers over Streamable HTTP. To expose this one:
https://. Make MCP_RESOURCE match this public /mcp URL.https://<host>/mcp. claude.ai will walk you
through the Google sign-in on first connect.A Retrieval-Augmented Generation pipeline written from scratch in C# — no LangChain, no hosted AI API. It extracts text from PDFs, splits it into overlapping chunks, generates embeddings with a local Ollama/Phi3 model, and stores them in a Qdrant vector database for semantic search. Implements the full RAG loop end to end: ingestion, vectorization, similarity retrieval, context augmentation, and answer generation.
C# 96.6%, Shell 3.4% · 25 commits · updated 19/02/2026 · View on GitHub
A C# implementation of a Retrieval-Augmented Generation (RAG) system that processes PDF documents and enables intelligent question-answering using local AI models.
This RAG implementation allows you to ask questions about PDF documents by combining semantic search with large language models. The system extracts text from PDFs, converts it into semantic vectors, stores them in a vector database, and retrieves relevant context to generate accurate answers.
The system uses the following components:
Ensure Docker has access to your GPU. You need:
--gpus=all flag supportA lightweight ORM for .NET built from the ground up, mapping annotated C# classes onto PostgreSQL tables. It generates schema and junction tables from entity definitions, and walks LINQ expression trees to translate lambdas into parameterized SQL WHERE clauses. It also resolves related entities recursively through their junction tables — the parts of EF Core most people treat as magic, implemented by hand.
C# 100.0% · 46 commits · updated 16/04/2026 · View on GitHub
A lightweight ORM for .NET that maps C# classes to PostgreSQL tables using custom attributes and a generic DbContext<T>.
CREATE TABLE SQL from annotated C# entitiesWHERE clauses1. Annotate your entities
[TableAttribute]
public class CarEntity
{
[PrimaryKeyAttribute]
public int Id { get; set; }
public string Name { get; set; }
public string Make { get; set; }
[SecondaryKeyAttribute]
public DriverEntity? Driver { get; set; }
}
2. Create tables and run queries
var db = new DatabaseConnector(connString);
// Auto-create tables from entity definitions
var entities = new TableEntitiesMaker(new TypeTranslator()).CreateObjectEntities();
await db.ExecuteCommands(new SqlCreateTablesTranslator(entities).TranslateEntitiesToCreateTables());
// CRUD
IDbContext<CarEntity> ctx = new DbContext<CarEntity>(db);
await ctx.InsertData(new CarEntity("Civic", "Honda", driver));
var all = await ctx.GetData();
var hondas = await ctx.GetDataBy(x => x.Make == "Honda" && x.Name != "Accord");
await ctx.UpdateData(car);
await ctx.DeleteData(car);
LINQ expression support — GetDataBy walks the expression tree and translates binary expressions (==, !=, <, <=, >, >=, &&, ||) directly into parameterized SQL conditions.
3. Recursive fetching of related objects
Pass recursive: true (or isRecursive: true on DbContext) to automatically load related entities via their junction tables:
// Fetch all articles and populate their related TagEntity objects
var articles = await ctx.GetData(isRecursive: true);
// Same with a filter
var articles = await ctx.GetDataBy(x => x.Title == "Hello", isRecursive: true);
For each fetched object, DjOrm:
{ParentType}{RelatedType}) using the parent's primary key.[SecondaryKey]-annotated property.This works recursively — related objects that themselves have [SecondaryKey] properties are also populated.
Connection string is loaded from a .env file:
HOST=localhost
PORT=5432
USERNAME=postgres
PASSWORD=postgres
DATABASE=testdb
A production .NET 9 and React 19 platform for football coaching staff, tracking player RPE and wellness to compute training load and the Acute:Chronic Workload Ratio used to flag injury risk. Ships with Microsoft Entra ID authentication, Azure Key Vault and Blob Storage, and integration tests that run against real PostgreSQL instances via Testcontainers. Every push to main runs the suite, builds both Docker images, and deploys to Azure Container Apps through GitHub Actions.
JavaScript 57.7%, C# 40.5%, CSS 0.8% · 162 commits · updated 18/02/2026 · View on GitHub
RSTracker helps coaching staff make data-driven decisions about player load management. By tracking daily RPE (Rating of Perceived Exertion) and wellness scores across a squad, the application calculates key performance indicators such as training load volume, intensity, and the Acute:Chronic Workload Ratio (ACWR) -- a widely recognized metric for assessing injury risk.
The platform is designed around the concept of league weeks (7-day windows), allowing staff to review and compare data on a week-by-week basis aligned with the competitive schedule.
Player Management
RPE Tracking
Wellness Monitoring
ACWR Analysis
Data Visualization
Weekly Data Views
RPE Bar Chart -- daily training load visualization
RPE Norm Chart -- actual loads compared against daily reference norms
Wellness Chart -- daily wellness score overview
ACWR Analysis -- workload ratio trends across multiple weeks
Player Management -- squad roster administration
Player Data, RPE, Wellness and Management -- combined data entry view
RPE is a subjective measure of how hard a player perceives a training session to be. When combined with session duration, it produces the session RPE or total training load:
Players self-report four metrics daily, each on a 1-7 scale:
| Metric | Description |
|---|---|
| Muscle Status | Perceived muscle soreness and readiness |
| Recovery Status | General sense of physical recovery |
| Stress | Mental and emotional stress levels |
| Sleep | Sleep quality and duration |
The total wellness score ranges from 4 to 28. The platform also calculates a Wednesday-Thursday-Friday average, commonly used to assess recovery state heading into match day.
The ACWR compares the current week's training load against the rolling average of the previous four weeks:
| ACWR Range | Interpretation |
|---|---|
| Below 0.8 | Undertraining -- potential detraining risk |
| 0.8 - 1.3 | Safe zone -- optimal load management |
| 1.3 - 1.5 | Caution -- elevated injury risk |
| Above 1.5 | Danger zone -- high injury risk |
The system includes built-in daily RPE norms for a typical training week to compare against actual loads:
| Day | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|---|
| Reference RPE | 300 | 600 | 580 | 110 | 220 | 760 | 0 |
| Technology | Purpose |
|---|---|
| React 19 | UI framework |
| Vite | Build tool and dev server |
| React Router DOM | Client-side routing |
| React Bootstrap / Bootstrap 5 | UI component library and styling |
| Chart.js + react-chartjs-2 | Data visualization and charting |
| chartjs-plugin-datalabels | Chart label overlays |
| MSAL React + MSAL Browser | Microsoft Entra ID authentication |
| date-fns | Date manipulation and formatting |
| react-datepicker | Date selection component |
| react-select | Enhanced dropdown selects |
| react-toastify | Toast notifications |
| react-spinners | Loading indicators |
| Technology | Purpose |
|---|---|
| .NET 9 / ASP.NET Core | Web API framework |
| Entity Framework Core 9 | ORM and database migrations |
| PostgreSQL (via Npgsql) | Relational database |
| JWT Bearer Authentication | API security |
| Swashbuckle / Swagger | API documentation |
| Newtonsoft.Json | JSON serialization |
| Azure Key Vault | Secrets management |
| Azure Blob Storage | Structured operation logging |
| In-Memory Cache | Response caching with TTL-based invalidation |
| Technology | Purpose |
|---|---|
| Docker | Containerization with multi-stage builds |
| Nginx | Frontend reverse proxy and SPA routing |
| Azure Container Apps | Cloud hosting |
| Azure Key Vault | Centralized secrets management |
| Azure Blob Storage | Append-style daily log files |
| Technology | Purpose |
|---|---|
| xUnit | Test framework |
| Testcontainers | Integration testing with real PostgreSQL instances |
The project uses GitHub Actions for continuous integration and deployment. A workflow is triggered on every push to the main branch and performs the following steps:
This ensures that every merge to main is automatically tested, containerized, and deployed to production.
RSTracker uses Microsoft Entra ID (formerly Azure Active Directory) for authentication.
Authorization: Bearer {token} headerThe test suite uses xUnit with Testcontainers to spin up real PostgreSQL instances during integration tests, ensuring database operations are tested against actual database behavior rather than mocks.
Test coverage includes:
| Test File | Coverage |
|---|---|
| PlayerHelperTests | Player CRUD operations and data retrieval |
| RPEManagerTests | RPE calculations, weekly aggregation, volume, and intensity |
| WelnessManagerTests | Wellness scoring, weekly summaries, and mid-week averages |
Azure Blob Storage logging is mocked during tests to isolate database-focused assertions.
All rights reserved.
A staff management and time-tracking app built for a real cafe in my home city — it has actual daily users, not just a demo deployment. Next.js 16 with Google OAuth and MongoDB Atlas, using role-based access so standard staff can only edit their own recent entries while admins see every employee and the full wallet history. Covers shift scheduling, daily work logs, and business cash-flow tracking.
TypeScript 89.9%, CSS 8.6%, JavaScript 1.4% · 37 commits · updated 09/03/2026 · View on GitHub
A staff management and time-tracking web app for small businesses — built to track daily work inputs, cash flow, and shift schedules. Built for a small cafe in my home city.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) + React 19 + TypeScript |
| Auth | NextAuth v5 — Google OAuth |
| Database | MongoDB (Atlas) |
| UI | React Bootstrap 5 + Custom CSS Modules |
| Calendar | FullCalendar (day/week/month views) |
| Utilities | date-fns, react-spinners |
| Hosting | Vercel-ready (Next.js server actions) |
Access is controlled via environment-level email whitelists:
Authentication is handled through Google OAuth — only whitelisted emails can log in.
/walletTracks the business cash balance. Users can submit balance updates with a timestamp. Admins see the full history of all updates (shown in the História accordion); standard users see the current balance only.

/myinputsDaily work log table. Each entry records hours worked, start/end times (auto-calculates hours), cash and terminal turnover, day expenses, and start/end float amounts. Filterable by month. Admins can view entries for all staff. Older entries outside the edit window are masked with ****.

/timetableA color-coded shift calendar showing staff schedules. Powered by FullCalendar with day, week, and month views. Each employee is assigned a distinct color.

A household chore delegation app pairing a .NET 9 API with a React and TypeScript frontend over PostgreSQL and Entity Framework. The Azure infrastructure is provisioned with Terraform, secured with JWT and Google OAuth, and covered by xUnit and Testcontainers integration tests running in GitHub Actions.
TypeScript 49.9%, C# 42.7%, HCL 4.7% · 77 commits · updated 19/02/2026 · View on GitHub
A Simple Household Task Management System
Transform your chaotic chore routine into an organized experience!
Start PostgreSQL database:
docker-compose up -d
Create environment file:
Create a .env file in the backend directory with your connection string:
DATABASE_CONNECTION_STRING=your_connection_string_here
Run Entity Framework migrations:
dotnet ef database update
Start the backend:
dotnet build
dotnet run
Install dependencies:
npm install
Start the development server:
npm run dev
The app automatically uses http://localhost:5272/api for the backend in development.
Before deploying to production, configure the following secrets in your GitHub repository (Settings → Secrets and variables → Actions):
| Secret Name | Description |
|---|---|
DOCKERHUB_USERNAME | Your Docker Hub username |
DOCKERHUB_TOKEN | Your Docker Hub access token |
AZURE_CREDENTIALS | Azure service principal credentials (JSON format) |
PRODUCTION_API_URL | Your production API URL (e.g., https://api.yourapp.com) |
Login to Azure:
az login
Navigate to the infrastructure directory:
cd infrastructure
Initialize Terraform:
terraform init
Review the deployment plan:
terraform plan
Apply the infrastructure:
terraform apply
Push to main branch:
Once the infrastructure is set up, pushing to the main branch will trigger the CI/CD pipeline that:
A personal productivity app on Next.js and MongoDB with Google OAuth, covering daily tasks, work reports, workouts, and notes. Includes a built-in Pomodoro timer and rich-text editors throughout, deployed on Vercel with Atlas.
TypeScript 92.1%, CSS 4.6%, JavaScript 3.2% · 89 commits · updated 19/07/2026 · View on GitHub
A personal productivity application built with Next.js 14, featuring task management, work reports, and workout tracking. The app uses Google OAuth for authentication and MongoDB for data persistence.
/)/tasks)
/workreports)
/workouts)
/notes)
The AES-128 block cipher implemented from scratch in C#, validated against the official NIST SP 800-38A and FIPS 197 test vectors. Benchmarked with BenchmarkDotNet against .NET's native implementation to quantify the cost of a naive approach — roughly 5x slower on encryption, 9x on decryption. Written to understand the algorithm properly; explicitly not for production use.
C# 100.0% · 23 commits · updated 19/02/2026 · View on GitHub
A simple, educational implementation of the Advanced Encryption Standard (AES) algorithm in C#. This project demonstrates the core AES encryption and decryption processes with a focus on clarity and learning.
Educational Purpose Only: This implementation is intended for learning and educational purposes. Do NOT use this in production environments or for securing sensitive data.
Latest benchmark results on Ubuntu 24.04.3 LTS with Intel Core i5-12450H:
| Method | Mean | Error | StdDev | Ratio |
|---|---|---|---|---|
| Custom AES Encrypt | 4,048.8 ns | 74.34 ns | 62.07 ns | ~4.9x |
| Custom AES Decrypt | 7,394.6 ns | 31.49 ns | 29.46 ns | ~8.7x |
| .NET AES Encrypt | 832.0 ns | 3.82 ns | 3.58 ns | 1.0x |
| .NET AES Decrypt | 847.2 ns | 5.56 ns | 4.64 ns | 1.0x |
The implementation is thoroughly tested against NIST Special Publication 800-38A and FIPS 197 test vectors:
dotnet test --verbosity normal
All tests validate:
This project is for educational purposes only. Please refer to the license file for details.
This is an educational project. Feel free to fork and experiment, but remember this is not intended for production use.
A desktop Mandelbrot set explorer built with Avalonia UI on .NET 9, rendering the fractal to a 1000x1000 canvas. Supports keyboard pan and zoom, with an adaptive iteration count that scales as you magnify so detail stays sharp at depth.
C# 100.0% · 8 commits · updated 17/02/2026 · View on GitHub
A desktop application for rendering and exploring the Mandelbrot set, built with C# and Avalonia UI targeting .NET 9.

The Mandelbrot set is one of the most famous fractals in mathematics. A point in the complex plane belongs to the set if the sequence defined by:
remains bounded (does not diverge to infinity). This application renders the set on a 1000×1000 pixel canvas, coloring points that belong to the set in red.
Space to increase magnification| Key | Action |
|---|---|
Arrow Up | Pan up |
Arrow Down | Pan down |
Arrow Left | Pan left |
Arrow Right | Pan right |
Space | Zoom in |
You can scroll (zoom) into the set to explore its infinitely complex boundary, but be aware that performance degrades significantly after a few zoom levels. The rendering is not heavily optimized — each zoom step requires recalculating every pixel on the canvas, and as the iteration count increases with deeper zoom levels, the computation becomes substantially more expensive. This is a known limitation of the current implementation and would require significant optimization (e.g., multithreading, GPU acceleration, or perturbation theory) to handle deep zooms smoothly.
cd MandelBrot/MandelbrotApp
dotnet run
A small .NET utility that watches product pages and emails you when one hits your target price. Items are declared in XML with a URL, a price goal, and an extraction regex; the tool polls on a schedule and sends comparison summaries over Mailjet SMTP.
C# 100.0% · 11 commits · updated 19/02/2026 · View on GitHub
A .NET tool that monitors product prices on the web and notifies you by email when your target price is hit.
InputConfig.xml — each entry has a URL, a target price, and a regex to extract the current price.<root>
<Recipient>you@example.com</Recipient>
<ItemWebResource>
<url>https://example.com/product</url>
<priceGoal>49.99</priceGoal>
<regexPricePattern>price-regex</regexPricePattern>
</ItemWebResource>
</root>
Set your Mailjet SMTP keys as environment variables:
PUBLIC_KEY_PARSERTOOL=<your-public-key>
PRIVATE_KEY_PARSERTOOL=<your-private-key>
Then run:
dotnet run --project PriceChecker
A Facebook Messenger bot running as an Azure HTTP-triggered Function, handling Meta webhook verification and inbound message events. Anyone who messages the page gets a random cat photo back from TheCatAPI. Deliberately silly, but a clean end-to-end example of serverless webhook plumbing.
C# 100.0% · 10 commits · updated 17/02/2026 · View on GitHub
This Azure Function project implements a Facebook Messenger bot that automatically sends cute cat photos to users who message your Facebook page. The bot uses Azure HTTP-triggered functions to handle Meta webhooks and respond with adorable cat images.
messages and messaging_postbacks eventsDeploy Function: Deploy this project to your Azure Function App
Environment Variables: Configure the following app settings:
META_PAT: Page access token from FacebookMETA_APP_SECRET: Your webhook verification token (the secret)HTTP Endpoint: Note your function's HTTP trigger URL for webhook configuration