<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Priyadharshiny J</title>
    <description>The latest articles on DEV Community by Priyadharshiny J (@priyadharshiny13).</description>
    <link>https://dev.to/priyadharshiny13</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4068692%2F90857061-2860-45ec-af0f-90b0e83c1c78.png</url>
      <title>DEV Community: Priyadharshiny J</title>
      <link>https://dev.to/priyadharshiny13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/priyadharshiny13"/>
    <language>en</language>
    <item>
      <title>Building an ATS Resume Scorer API with FastAPI, Celery, and Docker</title>
      <dc:creator>Priyadharshiny J</dc:creator>
      <pubDate>Fri, 30 Oct 2026 11:00:34 +0000</pubDate>
      <link>https://dev.to/priyadharshiny13/building-an-ats-resume-scorer-api-with-fastapi-celery-and-docker-3e8k</link>
      <guid>https://dev.to/priyadharshiny13/building-an-ats-resume-scorer-api-with-fastapi-celery-and-docker-3e8k</guid>
      <description>&lt;p&gt;Most resumes are filtered by ATS software before a human ever reads them. This project is a backend API that checks how well a resume matches a job description and suggests how to improve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PDF resume parsing:&lt;/strong&gt; extracts text from uploaded resumes using pdfplumber&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ATS keyword matching:&lt;/strong&gt; compares the resume against a job description and calculates a match score&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart suggestions:&lt;/strong&gt; generates actionable tips to improve the resume for a specific role&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT authentication:&lt;/strong&gt; secured endpoints with role-based access for Job Seekers and Recruiters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch scoring:&lt;/strong&gt; recruiters can score many resumes at once, handled in the background by Celery + Redis&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python, FastAPI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;JWT (python-jose, passlib)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;MySQL 8.0, SQLAlchemy ORM, Alembic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task queue&lt;/td&gt;
&lt;td&gt;Celery + Redis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF parsing&lt;/td&gt;
&lt;td&gt;pdfplumber&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps&lt;/td&gt;
&lt;td&gt;Docker, Docker Compose, AWS EC2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Pytest&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Design highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Background processing:&lt;/strong&gt; batch scoring runs through a Celery queue, so the API stays responsive while many resumes are processed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role-based access:&lt;/strong&gt; Job Seekers and Recruiters get separate permissions on the same API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproducible setup:&lt;/strong&gt; the whole stack (API, MySQL, Redis) starts with a single Docker Compose command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated deployment:&lt;/strong&gt; a GitHub Actions pipeline deploys automatically to AWS EC2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database migrations:&lt;/strong&gt; schema changes are managed with Alembic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/priyadharshiny13/ats-resume-scorer" rel="noopener noreferrer"&gt;https://github.com/priyadharshiny13/ats-resume-scorer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback is welcome. If you were using a tool like this, what would matter more: a more accurate match score or more detailed improvement suggestions?&lt;/p&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>docker</category>
      <category>backend</category>
    </item>
    <item>
      <title>Building Smart Health API: A Production-Style REST API with CNN-Based Risk Prediction</title>
      <dc:creator>Priyadharshiny J</dc:creator>
      <pubDate>Sat, 08 Aug 2026 11:06:09 +0000</pubDate>
      <link>https://dev.to/priyadharshiny13/building-smart-health-api-a-production-style-rest-api-with-cnn-based-risk-prediction-d7g</link>
      <guid>https://dev.to/priyadharshiny13/building-smart-health-api-a-production-style-rest-api-with-cnn-based-risk-prediction-d7g</guid>
      <description>&lt;p&gt;&lt;em&gt;By Priyadharshiny J — &lt;a href="https://github.com/priyadharshiny13" rel="noopener noreferrer"&gt;GitHub: priyadharshiny13&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Smart Health API is a backend platform I built to explore how a real healthcare product might structure its API layer: role-based access for different user types, secure authentication, database migrations that don't break production, and a machine learning model wired into an async pipeline instead of blocking the request thread.&lt;/p&gt;

&lt;p&gt;The result is a FastAPI service that lets Patients, Doctors, and Admins interact with the same system through different permission levels, and that returns CNN-based oral cancer risk scores without making the caller wait on model inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API layer:&lt;/strong&gt; FastAPI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; MySQL, with SQLAlchemy ORM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrations:&lt;/strong&gt; Alembic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth:&lt;/strong&gt; JWT-based authentication with Role-Based Access Control (RBAC)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ML:&lt;/strong&gt; TensorFlow CNN model for oral cancer risk prediction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async processing:&lt;/strong&gt; Celery + Redis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infra:&lt;/strong&gt; Docker, deployed toward AWS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD:&lt;/strong&gt; GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture Decisions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why RBAC with three roles instead of a single user type?&lt;/strong&gt;&lt;br&gt;
Healthcare data access isn't uniform — a Patient should only see their own records, a Doctor needs read/write access to their assigned patients, and an Admin needs oversight without clinical permissions. I modeled this directly into the JWT claims and enforced it at the route-dependency level in FastAPI, rather than checking roles inside each endpoint's business logic. This keeps permission logic in one place and out of the individual handlers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Alembic migrations instead of &lt;code&gt;create_all()&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;SQLAlchemy.create_all()&lt;/code&gt; is fine for a prototype, but it can't handle schema evolution — adding a column, renaming a table, backfilling data. Alembic gave the project versioned, reversible migrations, which is the same discipline a real production service needs the moment more than one person touches the schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Celery + Redis for the CNN inference?&lt;/strong&gt;&lt;br&gt;
Running a CNN prediction synchronously inside an HTTP request handler blocks the worker for however long inference takes, which doesn't scale under concurrent load. I moved prediction into a Celery task queue backed by Redis: the API accepts the image, enqueues the job, and returns a task ID immediately. The client polls (or would be pushed a webhook/notification in a fuller version) for the result. This separates the request/response cycle from the compute-heavy ML work.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real Debugging Story
&lt;/h2&gt;

&lt;p&gt;Wiring up SQLAlchemy models across multiple modules (&lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Patient&lt;/code&gt;, &lt;code&gt;Doctor&lt;/code&gt;, &lt;code&gt;Prediction&lt;/code&gt;) introduced circular import errors once relationships started referencing each other — &lt;code&gt;Patient&lt;/code&gt; needed &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt; needed &lt;code&gt;Prediction&lt;/code&gt;, and Python's import system didn't like the cycle. The fix was restructuring model definitions to use string-based relationship references (&lt;code&gt;relationship("Patient", back_populates=...)&lt;/code&gt;) instead of direct class imports, which lets SQLAlchemy resolve the relationship lazily at mapper-configuration time rather than at import time.&lt;/p&gt;

&lt;p&gt;Small detail, but it's the kind of thing that only shows up once a schema has enough interrelated tables — and it's a good reminder that ORM relationship design needs the same intentionality as the schema itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add automated tests for the RBAC permission boundaries (currently manually verified)&lt;/li&gt;
&lt;li&gt;Expose Celery task status through a WebSocket instead of polling&lt;/li&gt;
&lt;li&gt;Add rate limiting on the prediction endpoint given its compute cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;

&lt;p&gt;Code and setup instructions: &lt;a href="https://github.com/priyadharshiny13" rel="noopener noreferrer"&gt;github.com/priyadharshiny13&lt;/a&gt; — see the &lt;code&gt;smart-health-api&lt;/code&gt; repository.&lt;/p&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>backend</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
