Case Studies

Automating Annual Training Reviews for a Compliance Platform (Positive Duty)

Role: Full-Stack & Platform Engineer | Duration: platform version 2 built

Context

Positive Duty is a multi-tenant compliance training platform built to support Australia's Respect at Work legislation. Clients need employees to re-complete key training modules on an annual basis to stay compliant, but earlier workflows relied on manual exports and spreadsheets, making it easy to miss overdue reviews as tenant and user counts grew.

Challenges

  • Deriving annual review due dates from historical completion data instead of static fields.
  • Designing an anniversary rule (11-month reminder, 12-month due date) that is correct and explainable.
  • Ensuring reminders are idempotent at scale so users do not receive duplicate emails.
  • Surfacing reminders across channels (email and in-portal UI) without overwhelming users.
  • Providing diagnostics and admin tools to seed data, test behavior, and debug specific users.

Solution

I implemented an annual review engine that scans training completions daily, computes who is due for review, and delivers reminders via email and in-product notifications, with guardrails for idempotency and operational visibility.

  • Extended the Prisma schema with ReminderDispatch and UINotification models to track which reminders have been sent and to persist in-app notifications for each user and module.
  • Built a daily scanner in anniversaryReminder.js that aggregates the last completion per user and module from ViewerModuleCertification, computes 11-month reminder and 12-month due dates, and skips users who are not yet due.
  • Implemented composite idempotency keys on (email, moduleId, completionAt, reminderType) so repeated runs of the job do not send duplicate reminders.
  • Integrated the scanner with existing cronJobs.js infrastructure using file-based locks in a .locks directory to prevent overlapping executions and to log summary metrics for each run.
  • Added anniversary-specific API endpoints (scan, diagnose, seed, mark-read) so admins can trigger scans, backfill test data, and inspect why a particular user did or did not receive a reminder without direct database access.
  • Surfaced the reminder count in the portal via an AnniversaryContext React context and a NotificationBanner component that announces when modules are pending review, updating on navigation, focus, and visibility changes.

Impact

The annual review engine replaced a manual, spreadsheet-based renewal process with a repeatable and auditable workflow. Compliance teams now have higher confidence that employees due for review receive timely reminders, while admins and stakeholders can diagnose behavior through internal tools and persisted reminder records. This reduces operational overhead and helps Positive Duty tenants maintain ongoing training compliance at scale.

Go to project page


Building a Soundbank Pipeline for an Online Bandoneon Library (Extended Bandoneon)

Role: Full-Stack Developer | Duration: Ongoing project

Context

Extended Bandoneon is a research and performance project around the bandoneon instrument. A key goal of the web app is to publish a curated online soundbank of high-quality bandoneon samples that musicians, producers, and researchers can browse, preview, and download.

Challenges

  • Modeling sounds and soundpacks across MySQL and Cloudinary while keeping metadata in sync.
  • Supporting WAV uploads for quality while serving performant MP3 files to users.
  • Designing a tagging and filtering system that works across both sounds and soundpacks.
  • Building a responsive soundbank UI with waveform playback that scales with many sounds.
  • Making the soundbank discoverable with structured data without duplicating business logic.

Solution

I implemented an end-to-end soundbank pipeline that ingests audio into Cloudinary, normalizes metadata in MySQL, and exposes a filterable, SEO-friendly sound library with waveform playback and gated downloads.

  • Modeled sounds, soundpacks, and hashtags in a relational schema, with a thin db wrapper for queries and mutations so the Next.js API routes could stay focused on behavior rather than connection management.
  • Built an admin-only upload endpoint that accepts WAV or MP3 files, uploads them to Cloudinary, converts WAV to MP3 when needed, and stores duration, size, and canonical MP3 URLs in the sounds table.
  • Implemented soundpack management and tagging so editors can define soundpacks with shared tags; individual sounds inherit those tags and can add their own, all persisted via a normalized hashtags/entity_hashtags model.
  • Exposed a public /api/sounds endpoint that performs cursor-based pagination, joins soundpacks and tags, filters to soundbank MP3 assets, and returns a frontend-friendly shape for the React Query client on the soundbank page.
  • Built the soundbank frontend with infinite scroll, soundpack and tag filters, and a custom SoundPlayer component using WaveSurfer.js to render waveforms and control playback without relying on browser-native controls.
  • Added JSON-LD structured data for the soundbank using a generateSoundbankStructuredData helper so search engines can index the collection as a set of AudioObject resources.

Impact

The soundbank pipeline turned a static collection of audio files into a structured, explorable library. Editors can upload new bandoneon sounds and organize them into soundpacks without touching code, while visitors get fast waveform playback, meaningful filters, and gated downloads. This makes the Extended Bandoneon project more useful to performers, producers, and researchers and provides a solid foundation for future tooling such as datasets or analysis tools.

Go to project page


Automating Spanish Freelancer Accounting with a CLI-First Workflow (Conta)

Role: Backend & Tooling Engineer | Duration: Ongoing personal project

Context

As a self-employed professional in Spain, I needed to manage invoices, deductible expenses, social security contributions, and quarterly and annual tax obligations (IVA and IRPF). My existing workflow involved spreadsheets and manual calculations before filing official forms like Modelos 130, 303 and 390, which was error-prone and time-consuming.

Challenges

  • Centralizing invoices, expenses, and tax-related payments in a consistent data model.
  • Encoding Spanish tax rules (quarters, IVA devengado/deducible, IRPF base and retentions) in code.
  • Designing a CLI workflow that was fast to use but still guided and safe for everyday bookkeeping.
  • Generating exports and backups that could be shared with an accountant or used for audits.

Solution

I designed and implemented Conta, a Python-based command-line application that models the accounting domain explicitly and automates the most repetitive parts of my freelancer workflow.

  • Built a typed domain model with SQLModel and SQLite for entities like issued invoices, deductible expenses, social security payments, and fractioned IRPF payments.
  • Implemented a Typer-powered CLI with focused commands for recording invoices (emite), expenses (gasto), and listing data by year or quarter, using Rich tables for readable terminal output.
  • Encapsulated IVA and IRPF logic in dedicated services that compute quarterly snapshots based on real data, mirroring the structure of official Spanish tax forms.
  • Added CSV exports for VAT books and a backup-db command so the SQLite database can be safely archived or handed off to an accountant.

Impact

With Conta, I replaced a fragile spreadsheet-based workflow with a repeatable CLI routine. Recording invoices and expenses is now a matter of running a few commands, and quarterly IVA and IRPF snapshots can be generated on demand. This reduces manual calculation errors, shortens the time I spend preparing tax forms, and gives me a clearer view of my financial position throughout the year.

Go to project page