Ricardo Rojas
Backend / Full-Stack Engineer
Full-Stack · APIs · Automation · System Design
Selected Projects
toggle display
KanbAnpp — Kanban Web Application
Context
A web-based Kanban application designed to support collaborative task management with real-time updates and role-based access control.
Architecture Overview
Features
- Real time updates
- Attachments
- Tag
- Roles
- JWT authentication
System Key Decisions
- Django + DRF for backend, and quick REST API development
- Serializers for data validation and transformation
- JWT authentication for stateless API usage
- WebSockets for collaborative real-time updates
- Daphne chosen for simplicity; Nginx + Uvicorn planned when horizontal scaling becomes necessary.
- React as frontend for dynamic user interfaces
- TanStack Query for data fetching and caching
- Pytest for testing
- Employed SQLite for quick prototyping
SessionBook — Clean Architecture REST API
Context
Inpired by my hobby as a guitarist when practicing songs. It's used to track progress of song you want to learn. A web application exposing a REST API designed following clean architecture principles, with strong separation between domain, application, and infrastructure layers.
Architecture Overview
Features
- Guitar tab scraping.
- Song practice catalogue
- JWT authentication
System Key Decisions
- Spring Boot for a robust and scalable backend framework
- Explicit layering to enforce separation of concerns
- DDD for clear domain modeling
- DTO pattern to decouple domain models from API representations
- Async for scraping guitar tabs and heavy lifting tasks
- JWT authentication for stateless clients
- MySQL for relational data storage
- React for building user interfaces
- TypeScript for frontend development
DevEnvCheck — Windows Developer Environment Auditor
Context
A lightweight Java-based CLI tool built after a real recovery incident to diagnose, audit, and validate Windows developer environments. Designed to quickly identify missing tools, broken PATHs, and misconfigured environment variables during onboarding or incident response.
Features
- Detect installed developer tools and SDKs
- Version detection via CLI or file metadata
- Recursive project type scanning (Node, Java, .NET, Python)
- Safe cleanup of
node_modulesdirectories - Environment variable diagnostics
- Exportable audit reports
Key Decisions
- Java 8 for maximum compatibility with enterprise environments
- PicoCLI for composable subcommands and argument parsing
-
Windows-native tooling (
where,wmic, filesystem probing) instead of fragile heuristics - File metadata inspection for GUI tools without CLI version flags (Visual Studio, SSMS)
- Defensive execution model, avoids launching GUI applications or modifying system state
Usage
clean-node-modules path #asks for confirmation y/N before deleting
clean-node-modules path --silent #no confirmation
clean-node-modules path --dry-run #lists what would be deleted but doesn't delete
check-installation
scan-projects path
env-check path
KeyScala — Secure CLI Password Manager
Context
Type-safe CLI password manager focused on security and correctness, using modern cryptographic methods.
Architecture Overview
Features
- Simple CLI usage
- AES/GCM Encryption
- Custom Serialization
Key Decisions
- AES/GCM for authenticated encryption
- Secure key management practices
- Domain-driven modeling to avoid invalid states
- Minimal dependencies for portability
Usage
# Add an entry
sbt "run --add example.com mykey"
# Edit an entry, you will be prompted for a password again
sbt "run --edit example.com mykey"
# Delete an entry
sbt "run --del example.com mykey"
# List all entries
sbt "run --list"
# Search for an entry (password copied temporarily to clipboard)
sbt "run --search mykey"
# Display help
sbt "run --help"
AssetFLOW — Asset Transformation Library
Context
Scala library focused on scalable image transformations, including format conversion, thumbnail generation, palette extraction and preprocessing for OCR pipelines.
Architecture Overview
Features
- Thumbnail generation
- OCR preprocessing fixes
- Image transformations
- Palette extraction
- Web image guidelines reference
Key Decisions
- Strong DDD principles for clear domain modeling
- Functional programming principles for composable transformations
- Modular design for easy extension with new transformations
Usage
//helpers
Pipe()
.from("in")
.to("out")
.inspect("after load") { img =>
println(img.width, img.height)
}
.step(TransformationStep("grayscale", OCR.grayscale))
.inspect("after grayscale") { img =>
println("ok")
}
.dryRun()
Batch()
.from("in")
.to("out")
.foreach("convert") { (file, out, in) =>
ImageTransforms.convertTo(file, out, ImageTransforms.Webp)
}.dryRun()
//folders setup
val inputDir = new File("input")
val outputDir = new File("output")
outputDir.mkdirs()
//listing images
val images = ImageTransforms.listImages(inputDir)
println(s" ${images.size} found ${inputDir.getPath}:")
images.foreach(f => println(s" - ${f.getName}"))
//converting to webp
val webpResults = ImageTransforms.convertTo(images, outputDir, Webp)
webpResults.foreach {
case Right(f) => println(s"WebP at: ${f.getName}")
case Left(err) => println(s"Error: $err")
}
//making thumbnails
val thumbsDesktop = ImageTransforms.createThumbnail(images, outputDir, Desktop)
val thumbsMobile = ImageTransforms.createThumbnail(images, outputDir, Mobile)
println("Thumbnails desktop:")
thumbsDesktop.foreach {
case Right(f) => println(s" - ${f.getName}")
case Left(err) => println(s" - Error: $err")
}
println("Thumbnails mobile:")
thumbsMobile.foreach {
case Right(f) => println(s" - ${f.getName}")
case Left(err) => println(s" - Error: $err")
}
//now placeholders
val placeholders = ImageTransforms.generatePlaceholders(
number = 3,
width = 200,
height = 200,
fillColor = Some(Color.RED),
applyBlur = true,
outputDir = outputDir
)
placeholders.foreach {
case Right(f) => println(s"placeholder generated: ${f.getName}")
case Left(err) => println(s"Error: $err")
}
//test OCR preprocessing
images.headOption.foreach { imgFile =>
println("testing ocr processing...")
val image = ImmutableImage.loader().fromFile(imgFile)
val processed = OCR.optimize(
image,
tilt = 5.0,
contrastFactor = 1.3,
threshold = 128,
doBinarize = true
)
val (name, ext) = Common.getNameAndExtension(imgFile.getName)
val key = Common.timestamp
val outPath = new File(outputDir, s"${name}_$key${ext.getOrElse("")}").getPath
processed.output(WebpWriter.MAX_LOSSLESS_COMPRESSION, new File(outPath))
println(s"OCR processed stored at: $outPath")
}
//create a color
val redColor = RGBColor(100, 50, 200)
println(s"initial color: $redColor, hex=${redColor.toHex}")
//increase channels
val brighter = redColor.increaseAll(50, 30, -100)
println(s"adjusted color: $brighter, hex=${brighter.toHex}")
//mix 'em up
val blueColor = RGBColor(0, 0, 255)
val mixed = redColor.mixWith(blueColor, 0.5)
println(s"50% mix: $mixed, hex=${mixed.toHex}")
//from hex
val fromHex = RGBColor.fromHex("#ff00cc")
println(s"from hex '#ff00cc': $fromHex")
//random color
val randomColor = RGBColor.random()
println(s"random color: $randomColor, hex=${randomColor.toHex}")
val cmyk = CMYKColor(20, 40, 60, 10)
val rgb = RGBColor(100, 150, 200)
//increase specific channel by 10 (using currying)
val brighterMagenta = cmyk.modifyChannel(Magenta)(_ + 10)
println(brighterMagenta)
//using the shortcut increaseChannel
val brighterRed = rgb.increaseChannel(Red, 20)
println(brighterRed)
//more complex HOF: halve yellow
val lessYellow = cmyk.modifyChannel(Yellow)(_ / 2)
println(lessYellow)
WebsiteImageType.summary()
WebsiteImageType.fromName("logo_square") match {
case Some(img) => println(s"square logo found guidelines for desktop: ${img.desktop} " +
s" for mobile: ${img.mobile}, ratio=${img.ratio}")
case None => println("square logo not found")
/*
initial color: RGBColor(100,50,200), hex=#6432C8
adjusted color: RGBColor(150,80,100), hex=#965064
50% mix: RGBColor(50,25,227), hex=#3219E3
from hex '#ff00cc': RGBColor(255,0,204)
random color: RGBColor(75,123,240), hex=#4B7BF0
Type Desktop (WxH) Mobile (WxH) Ratio
----------------------------------------------------------------------
background 2560x1400 360x640 64:35
hero 1280x720 360x200 16:9
banner 1200x400 360x120 3:1
blog 1200x800 360x240 3:2
logo_rectangle 400x100 160x40 4:1
logo_square 100x100 60x60 1:1
favicon 16x16 16x16 1:1
social_icon 32x32 48x48 1:1
lightbox 1920x1080 360x640 16:9
thumbnail 300x300 90x90 1:1
product_thumbnail 300x300 150x150 1:1
square logo found guidelines for desktop: 100x100 for mobile: 60x60, ratio=1:1
*/
JpnUtils — Unicode-Aware Text Utilities
Architecture Overview
Features
- Zero-dependency
- String transformations
Context
Small, zero-dependency utility library for Japanese string handling, providing Unicode-aware and language-specific transformations.
Key Decisions
- Zero-dependency for easy integration
- Comprehensive Unicode support
- Focus on Japanese text processing needs
Usage
//using the JapaneseUtils singleton
println(JapaneseUtils.containsHiragana("込める")) //true
println(JapaneseUtils.containsKatakana("淋しい")) //false
println(JapaneseUtils.containsKanji("淋しい")) //true
println(JapaneseUtils.isHiragana('込')) //false
println(JapaneseUtils.isKatakana('淋')) //false
println(JapaneseUtils.isKanji('い')) //false
//using implicits
//hasX methods, works on string
println("当てのない僕は".hasHiragana) //true
println("満月".hasKanji) //true
println("オカエリナサイ".hasKanji) //false
//isX, works on char
println('そ'.isHiragana) //true
println('た'isKatakana) //false
println('林'.isKanji) //true
//miscellaneous methods
val testStr = """"this is a test!? yes? it is sir.""""
val strWithReplacedPunctuation = JapaneseUtils
.Punctuation
.replacePunctuation(testStr)
println(strWithReplacedPunctuation) //"this is a test!? yes? it is sir。"
//「wrap me in single quotes」 and 『wrap me in double quotes』 respectively
println(JapaneseUtils.Punctuation.wrapInSingleQuotes("wrap me in single quotes"))
println(JapaneseUtils.Punctuation.wrapInDoubleQuotes("wrap me in double quotes"))
//2025 update KanaDiacritics
//true
println("俺はテストだぞ".hasDakuten)
//true
println("いっぱいに静かがっぽい".hasHandakuten)
//カタカナ ABC123&%
val s = "カタカナ ABC123&%"
println(HalfWidthConverter.toHalfWidth(s))
Chordal — Type-Safe Musical DSL
Context
A weekend project that turned into something bigger. Internal DSL for modeling harmonic structures and chord progressions, separating declarative syntax, semantics, and domain invariants.
Architecture Overview
Features
- Library support for music theory concepts
- EDSL syntax for musical expressions
- Zero-dependency for easy integration
Key Decisions
- Strong modeling for musical concepts
- Functional programming principles for composable constructs
- Type safety to prevent invalid musical states
Lessons Learned
Over-engineering DSLs too early increased cognitive load. I now bias toward simpler models and evolve abstractions only when pressure exists.Usage
//on progress, subject to changes
val C = Note("C")
val D = Note("D")
val Eb = Note("Eb")
val cMajor = Triad.major(C)
val dMinor = Triad.minor(D)
val ebDim = Triad.diminished(Eb)
println(cMajor.name) // "C"
println(dMinor.name) // "Dm"
println(ebDim.name) // "E°"
println(cMajor.asNotes) // List(C, E, G)
println(dMinor.asNotes) // List(D, F, A)
val csus2 = cMajor.sus2
val csus4 = cMajor.sus4
println(csus2.name) // "C D"
println(csus2.asNotes) // List(C, D, G)
println(csus4.asNotes) // List(C, F, G)
val cAdd9 = cMajor.add9
val cAdd6 = cMajor.add6
println(cAdd9.name) // "Cadd9"
println(cAdd9.asNotes) // List(C, E, G, D)
println(cAdd6.asNotes) // List(C, E, G, A)
val c5 = cMajor.toPowerChord
println(c5.name) // "(C5)"
println(c5.asNotes) // List(C, G)
val cMaj7 = cMajor.withSeventh(MajorSeventh)
val d7 = dMinor.withSeventh(MinorSeventh)
println(cMaj7.name) // "Cmaj7"
println(cMaj7.asNotes) // List(C, E, G, B)
println(d7.name) // "Dm7"
println(d7.asNotes) // List(D, F, A, C)
val cMaj9 =
cMajor
.withSeventh(MajorSeventh)
.addExtension(Ninth)
println(cMaj9.name) // "Cmaj79"
println(cMaj9.asNotes) // List(C, E, G, B, D)
val key = Triad.major("C".note)
val ii = Triad.minor("D".note)
val V = Triad.major("G".note)
val I = Triad.major("C".note)
val ii7 = ii.withSeventh(MinorSeventh)
val V7 = V.withSeventh(MinorSeventh)
val Imaj7 = I.withSeventh(MajorSeventh)
println(List(ii7, V7, Imaj7).map(_.name))
val c1 =
chord {
root(C)
quality(MajorTriad)
withExtensions(Ninth)
}
println(c1)
val c2 =
chord {
root("D".note)
sus(Sus4)
}
println(c2)
val c3 =
chord {
root("E".note)
}
println(c3)
/*
C
Dm
Eb°
(C,E,G)
(D,F,A)
Csus2
(C,D,G)
(C,F,G)
Cadd9
(C,E,G,D)
(C,E,G,A)
(C5)
(C,G)
Cmaj7
(C,E,G,B)
Dm7
(D,F,A,C)
Cmaj79
(C,E,G,B,D)
List(Dm7, G7, Cmaj7)
TriadDesc(C,MajorTriad,List(Ninth))
SuspendedDesc(D,sus4,List())
PowerDesc(E)
*/
ScalaCron — Cronjob DSL
Context
ScalaCron is an EDSL for generation of Cronjob expressions in a zero-dependency library.
Architecture Overview
Features
- Library support for Cronjob expressions
- EDSL syntax for easy expression creation
- Pretty print support
- Lightweight and zero-dependency
Key Decisions
- Robust AST for Cronjob concepts
- Functional programming principles for composable constructs
- Prioritized flexibility and ease of use
Usage
import domain.Models.*
import domain.Models.Minute.given
import dsl.CronDSL.{to, *}
import Days.*
import scala.language.postfixOps
object Main :
def main(args: Array[String]): Unit =
val job2 = cron { c =>
c.minute(* / 5)
c.hour(9.h to 17.h)
c.dom(1.dom)
c.dow(Friday)
} >> "/usr/bin/backup.sh"
println(job2?) //same as job.schedule
println(job2) //whole expression as string
/* Output:
- Minute : every 5 minutes
- Hour : at 12
- Day of Month : at 1
- Day of Week : Monday
*/5 12 1 1 /usr/bin/backup.sh
*/
Skills
Backend
- API Development (Node, Django, DRF, Java)
- Web Portals (Laravel, Django)
- Scala (Scripting, DSLs, JVM libraries)
Frontend
- React.js (SPA, Routing)
- API integration, UI development
- React Native (Mobile)
Databases
- PostgreSQL, MySQL, SQL Server, SQLite
- MongoDB, Redis
Data & Distributed Processing
- Apache Spark (PySpark, Scala)
Cloud & DevOps
- AWS (EC2, S3)
- Docker, Linux, Bash
- GitHub Actions (CI/CD)
Testing
- Pytest, Jest, JUnit, MUnit
APIs & Protocols
- REST APIs, JSON, XML
- OpenAPI / Swagger, Scaladoc
- WebSockets
Concepts
- Asynchronous programming
- Object-Oriented & Functional Programming
- Clean Architecture, DDD basics
- Agile / Scrum
About me
Work Experience
Full-Stack Web Developer — TONY Super Papelerías Corp.
- Migrated a multi-branch logistics system from ASP.NET to Django, improving maintainability while preserving compatibility with legacy scanner hardware.
- Designed and implemented backend services and validations in Django for internal and supplier-facing platforms, progressively replacing legacy .NET modules.
- Built a Laravel microservice integrating VTEX APIs to automate order processing and eliminate recurring manual interventions.
- Developed internal automation tools in C#/.NET to feed and synchronize data across systems.
- Delivered frontend and mobile solutions when required, including a React.js logistics web app and a React Native inventory auditing application.
- Engineered a Vue.js + Express.js order intake system for the 2024 TONY EXPO, outperforming the previous .NET solution in speed and reliability.
- Built a semi-automated package label validation tool using QR scanning to detect supplier inconsistencies and reduce manual errors.
Software Programmer — Grupo Inversor Veracruzano S.A.P.I
- Maintained and optimized the PROCEDA clearance request platform, used daily by hundreds of customers.
- Refactored legacy PHP code and complex SQL queries, improving stability and response times.
- Ensured uptime and reliability for business-critical operations across multiple departments.