<?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: zendev2112</title>
    <description>The latest articles on DEV Community by zendev2112 (@zendev2112).</description>
    <link>https://dev.to/zendev2112</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%2F1190825%2F4880278c-44b3-4ab3-a1c1-55f76aaa3ea8.png</url>
      <title>DEV Community: zendev2112</title>
      <link>https://dev.to/zendev2112</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zendev2112"/>
    <language>en</language>
    <item>
      <title>Prompts Aren't Enough: Enforcing Hard Constraints on LLM Output</title>
      <dc:creator>zendev2112</dc:creator>
      <pubDate>Thu, 18 Jun 2026 04:03:59 +0000</pubDate>
      <link>https://dev.to/zendev2112/prompts-arent-enough-enforcing-hard-constraints-on-llm-output-2hpo</link>
      <guid>https://dev.to/zendev2112/prompts-arent-enough-enforcing-hard-constraints-on-llm-output-2hpo</guid>
      <description>&lt;p&gt;Every LLM demo looks impressive until it encounters a requirement that cannot be left to probability. Models are remarkably good at producing convincing text, but production systems often need guarantees rather than likelihoods. I ran into that distinction while building an AI-powered publishing pipeline for Radio del Volga, a regional news outlet in Coronel Suárez, Argentina. The system automatically ingests articles from RSS feeds, rewrites them, generates headlines, image prompts, and social media copy, then sends everything to an editor for review before publication. Most of the pipeline worked exactly as expected. One requirement, however, refused to stay solved: Gemini kept writing in the wrong Spanish.&lt;/p&gt;

&lt;p&gt;For readers outside Argentina, the distinction might seem insignificant. In neutral Spanish, a sentence might read &lt;em&gt;"Puedes encontrar más información..."&lt;/em&gt;. In Argentina, the same sentence would naturally be &lt;em&gt;"Podés encontrar más información..."&lt;/em&gt;. Likewise, &lt;em&gt;tienes&lt;/em&gt; becomes &lt;em&gt;tenés&lt;/em&gt;, &lt;em&gt;eres&lt;/em&gt; becomes &lt;em&gt;sos&lt;/em&gt;, and &lt;em&gt;contigo&lt;/em&gt; becomes &lt;em&gt;con vos&lt;/em&gt;. None of these changes affect meaning, but they immediately signal whether a text feels local or imported. &lt;/p&gt;

&lt;p&gt;What made the problem frustrating was that Gemini clearly knew the dialect. Most of the time, a straightforward instruction to write in Rioplatense Spanish produced excellent results. The failures only appeared under specific conditions. Government press releases, institutional announcements, and legal communications consistently nudged the model back toward neutral Spanish. The stronger the source's formal register, the more likely Gemini was to revert to expressions like &lt;em&gt;puedes&lt;/em&gt; or &lt;em&gt;tienes&lt;/em&gt;, despite explicit instructions not to do so. Because the pipeline processes articles continuously throughout the day, "almost always correct" was not a meaningful success criterion. Even a small failure rate guaranteed that incorrect articles would eventually reach the editorial queue.&lt;/p&gt;

&lt;p&gt;The overall architecture of the system is simple. A Node.js API running on Vercel handles the ingestion of RSS feeds and orchestrates the generation pipeline. Gemini 2.5 Flash performs the content generation, Airtable serves as the editorial interface, and approved articles are published through a Next.js application backed by Supabase, while images are stored and delivered through Cloudinary. Editors never interact directly with the codebase; they simply review drafts, make any necessary edits, and click Publish. Keeping a human approval step turned out to be the right architectural decision, but I still wanted every draft to arrive as close to publication-ready as possible.&lt;/p&gt;

&lt;p&gt;My first attempt was the obvious one: improve the prompt. Rather than giving Gemini a generic instruction to "write in Argentine Spanish," I made the requirements deliberately repetitive. The prompt explicitly prohibited neutral Spanish, listed the most common forbidden forms, provided their Rioplatense equivalents, and instructed the model to reread its own output before returning it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write in formal Rioplatense Spanish.

Never use neutral Spanish.

Use voseo throughout.

Forbidden forms:
- puedes
- tienes
- quieres
- haces
- eres

Before returning your response, read it again and replace any remaining neutral forms.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That extra self-review step noticeably improved consistency. Asking the model to inspect its own output before responding eliminated many of the mistakes that slipped through in earlier versions. Nevertheless, the improvement plateaued. The remaining failures were not random outliers; they were systematic. Formal source material continued to bias the model toward neutral Spanish, and no amount of additional emphasis or increasingly elaborate prompt engineering completely eliminated the problem.&lt;/p&gt;

&lt;p&gt;At that point, I stopped treating the issue as a prompting problem and started treating it as a validation problem. Some constraints are inherently probabilistic: tone, style, or structure benefit from an LLM's flexibility. Others are entirely deterministic. If the generated text contains the word &lt;em&gt;puedes&lt;/em&gt;, the output is incorrect. There is no ambiguity to resolve, no interpretation required, and no reason to ask the model to fix a mistake that ordinary code can identify with certainty.&lt;/p&gt;

&lt;p&gt;The second layer of the solution is therefore a lightweight post-processing step that runs after every generation. Instead of attempting to rewrite arbitrary grammar, it focuses exclusively on a carefully curated set of expressions whose replacements are unambiguous.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;puedes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;podés&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tienes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tenés&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quieres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;querés&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;haces&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hacés&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contigo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;con vos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;enforceRioplatense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rioplatense&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The replacement list is intentionally conservative. I do not attempt to transform every grammatical construction in Spanish because rule-based systems quickly become fragile when they expand beyond clearly defined cases. For example, &lt;em&gt;puedes&lt;/em&gt; should always become &lt;em&gt;podés&lt;/em&gt;, but &lt;em&gt;puede&lt;/em&gt; is already perfectly valid in Rioplatense Spanish and should remain untouched. Restricting the post-processor to a small set of deterministic transformations makes it reliable, easy to maintain, and unlikely to introduce unintended side effects.&lt;/p&gt;

&lt;p&gt;Looking back, the interesting lesson had very little to do with Spanish. It was about recognizing the limits of prompt engineering. Like many developers working with LLMs, my initial instinct was to assume that incorrect outputs meant the prompt needed further refinement. That assumption held true until it reached its limit. Prompting dramatically improved the model's performance, but it could never provide the guarantee that the production system required. Once I accepted that reality, the architecture became much simpler: let the model generate, then let deterministic code enforce the rules that are objectively verifiable.&lt;/p&gt;

&lt;p&gt;That pattern extends well beyond language localization. Brand terminology, regulatory wording, formatting conventions, structured outputs, naming rules, and countless other production requirements share the same characteristic: they are finite, stable, and testable. Those constraints are often better enforced after generation than delegated entirely to the model. LLMs excel at producing fluent, context-aware text, but they should not be responsible for guaranteeing rules that conventional software can verify with absolute certainty.&lt;/p&gt;

&lt;p&gt;The most valuable insight from this project was not learning how to write a better prompt. It was learning where prompting should end. Production systems become more reliable when responsibilities are clearly divided: the model generates possibilities, deterministic code validates the parts that must never be wrong, and humans remain responsible for the final editorial judgment. In my experience, that combination produces far more dependable systems than expecting the model alone to satisfy every requirement.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Listen First, Code Later: Case Study of a Dental App</title>
      <dc:creator>zendev2112</dc:creator>
      <pubDate>Sat, 11 Oct 2025 14:15:14 +0000</pubDate>
      <link>https://dev.to/zendev2112/listen-first-code-later-case-study-of-a-dental-app-1d74</link>
      <guid>https://dev.to/zendev2112/listen-first-code-later-case-study-of-a-dental-app-1d74</guid>
      <description>&lt;p&gt;Recently, a dentist reached out to us with the need to modernize his digital workflow for recording odontograms. His previous software was rigid, unintuitive, and didn’t integrate with his patient management system built on Airtable. The challenge was clear: to create a robust, user-friendly, and extensible solution that respected his existing habits and integrated seamlessly with his current tools, including Softr.io.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the challenge
&lt;/h2&gt;

&lt;p&gt;Our client, an active dentist, relied on digital odontograms for his daily practice but was frustrated by the limitations of his old software. His main requirements were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A familiar and intuitive interface&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Precise dental surface-level recording (based on FDI)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-tooth notes and a dual-layer annotation system (existing and required)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple export and direct integration with Airtable and Softr.io&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We held several meetings to observe his workflow, identify pain points, and ensure the new app fit naturally into his daily routine without a learning curve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scope and integration context
&lt;/h2&gt;

&lt;p&gt;It’s worth noting that the integration with &lt;strong&gt;Softr.io&lt;/strong&gt; (a no-code platform for building frontends on top of Airtable) was already planned and managed by the client.&lt;br&gt;
Our responsibility was solely to design and implement the odontogram web application, ensuring it could export and upload both images and structured data to Airtable, where Softr.io would handle visualization and record management.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is FDI and why does it matter?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FDI&lt;/strong&gt; stands for &lt;em&gt;Fédération Dentaire Internationale&lt;/em&gt; (World Dental Federation). It’s a universal two-digit dental numbering system that identifies each tooth and its quadrant. This standard allows dental findings to be recorded and communicated accurately and internationally, improving interoperability among professionals and systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technologies used
&lt;/h2&gt;

&lt;p&gt;This project combined a complete and modern web stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript (ES6+)&lt;/strong&gt; – Core application logic, event handling, and data processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jQuery&lt;/strong&gt; – DOM manipulation, event delegation, and odontogram plugin integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 Canvas&lt;/strong&gt; – Odontogram rendering and generation of high-resolution PNG reports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS3&lt;/strong&gt; – Responsive styles and professional clinical design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jQuery Odontogram Plugin&lt;/strong&gt; – Interactive odontogram engine (&lt;a href="https://github.com/Adhiana46/jquery-odontogram" rel="noopener noreferrer"&gt;Adhiana46/jquery-odontogram&lt;/a&gt;), extended for our needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; – Data structure for export and backend integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js &amp;amp; Express&lt;/strong&gt; – Backend API to receive and store PNG/JSON files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudinary API&lt;/strong&gt; – Secure, scalable image upload and storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Airtable API&lt;/strong&gt; – Attaching images and structured data to patient records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Softr.io&lt;/strong&gt; – No-code platform used by the client to build the frontend on Airtable and manage patient data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser APIs&lt;/strong&gt; – File handling, image generation, and client-side processing.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FDI anatomical mapping: clinical precision
&lt;/h2&gt;

&lt;p&gt;One of the main technical challenges was implementing &lt;strong&gt;FDI-based anatomical mapping&lt;/strong&gt;. In dentistry, the same position on the canvas (e.g., “left”) can represent “mesial” or “distal” depending on the tooth quadrant.&lt;br&gt;
We developed a system that translates canvas positions (top, bottom, left, right, center) into actual anatomical surfaces (buccal, palatal/lingual, mesial, distal, occlusal/incisal) according to the FDI quadrant—ensuring clinical accuracy and clear communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7mmz9rjh5srv7f3aomx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7mmz9rjh5srv7f3aomx.png" alt=" " width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Dual-layer annotation: mirroring real clinical practice
&lt;/h2&gt;

&lt;p&gt;The app supports two annotation layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-existing (red):&lt;/strong&gt; Conditions or treatments already present&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Required (blue):&lt;/strong&gt; Treatments to be performed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dentist can switch between layers with a single click, and all annotations are color-coded for instant recognition—replicating real-world clinical workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Per-tooth notes: simple clinical documentation
&lt;/h2&gt;

&lt;p&gt;Each tooth allows adding specific notes, with auto-save and manual save/delete options. These notes are included in both the JSON export and the PNG report, ensuring complete clinical documentation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data export: structured JSON and professional PNG reports
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON Export:&lt;/strong&gt; The app exports all odontogram data in a structured format, including date, patient name, annotated teeth, conditions, treatments, and notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PNG Export:&lt;/strong&gt; Generates a professional A4 report containing the odontogram, treatments, notes, patient name, and timestamp. The layout is optimized for clarity and clinical use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxvfj2sk1shwanoux4x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxvfj2sk1shwanoux4x4.png" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Integration with Cloudinary and Airtable: frictionless workflow
&lt;/h2&gt;

&lt;p&gt;A key aspect was integrating with &lt;strong&gt;Cloudinary&lt;/strong&gt; and &lt;strong&gt;Airtable&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a PNG report is generated, the image is uploaded to Cloudinary via its API, ensuring secure and scalable storage.&lt;/li&gt;
&lt;li&gt;The backend (Node.js/Express) attaches the Cloudinary image URL and the structured JSON data to the corresponding patient record in Airtable using the Airtable API.&lt;/li&gt;
&lt;li&gt;As a result, all odontogram images and notes become instantly available within the patient’s record.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Softr.io: no-code frontend for the professional
&lt;/h2&gt;

&lt;p&gt;The client already used &lt;strong&gt;Softr.io&lt;/strong&gt; to build a no-code frontend on top of Airtable. This allows him to manage patient data, visualize odontogram images and notes, and interact with the system without technical barriers. Our app integrates seamlessly into this workflow, ensuring everything appears automatically in his Softr.io dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Maintaining familiarity: respecting user habits
&lt;/h2&gt;

&lt;p&gt;Throughout development, we regularly shared progress with the dentist to ensure the app remained familiar and easy to use. We preserved his existing flow for selecting and annotating treatments while adding modern enhancements like auto-saving notes, color-coded layers, and professional document generation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User-centered design is essential:&lt;/strong&gt; Frequent feedback from the dentist kept the project aligned and ensured adoption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Innovate without losing familiarity:&lt;/strong&gt; New features are valuable only if they remain usable for non-technical users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration is key:&lt;/strong&gt; Adapting to the client’s existing tools (Airtable + Softr.io) made the app truly enhance productivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source accelerates development:&lt;/strong&gt; Building on a solid open-source foundation let us focus on real client needs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The result is a modern, lightweight odontogram web application—powerful yet accessible. By listening to the client and leveraging a complete tech stack (JavaScript, jQuery, HTML5 Canvas, CSS3, Node.js, Express, Cloudinary API, Airtable API, Softr.io), we delivered a tool that integrates seamlessly into the dentist’s daily workflow, making clinical documentation faster, more accurate, and easier to manage.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Project repository:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/zendev2112/odontograma" rel="noopener noreferrer"&gt;https://github.com/zendev2112/odontograma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open-source base:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/Adhiana46/jquery-odontogram" rel="noopener noreferrer"&gt;https://github.com/Adhiana46/jquery-odontogram&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technologies used:&lt;/strong&gt;&lt;br&gt;
JavaScript (ES6+), jQuery, HTML5 Canvas, CSS3, jQuery Odontogram Plugin, JSON, Node.js, Express, Cloudinary API, Airtable API, Softr.io, Browser APIs.&lt;/p&gt;

&lt;p&gt;If you’re building for real users, remember: &lt;strong&gt;listen first, then code!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>css</category>
      <category>jquery</category>
    </item>
    <item>
      <title>Listen First, Code Later: Case Study of a Dental App</title>
      <dc:creator>zendev2112</dc:creator>
      <pubDate>Sun, 28 Sep 2025 16:01:01 +0000</pubDate>
      <link>https://dev.to/zendev2112/escuchar-primero-programar-despues-case-study-de-una-app-odontologica-248o</link>
      <guid>https://dev.to/zendev2112/escuchar-primero-programar-despues-case-study-de-una-app-odontologica-248o</guid>
      <description>&lt;p&gt;Recently, a dentist reached out to us with the need to modernize his digital workflow for recording odontograms. His previous software was rigid, unintuitive, and didn’t integrate with his patient management system built on Airtable. The challenge was clear: to create a robust, user-friendly, and extensible solution that respected his existing habits and integrated seamlessly with his current tools, including Softr.io.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the challenge
&lt;/h2&gt;

&lt;p&gt;Our client, an active dentist, relied on digital odontograms for his daily practice but was frustrated by the limitations of his old software. His main requirements were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A familiar and intuitive interface&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Precise dental surface-level recording (based on FDI)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-tooth notes and a dual-layer annotation system (existing and required)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple export and direct integration with Airtable and Softr.io&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We held several meetings to observe his workflow, identify pain points, and ensure the new app fit naturally into his daily routine without a learning curve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scope and integration context
&lt;/h2&gt;

&lt;p&gt;It’s worth noting that the integration with &lt;strong&gt;Softr.io&lt;/strong&gt; (a no-code platform for building frontends on top of Airtable) was already planned and managed by the client.&lt;br&gt;
Our responsibility was solely to design and implement the odontogram web application, ensuring it could export and upload both images and structured data to Airtable, where Softr.io would handle visualization and record management.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is FDI and why does it matter?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FDI&lt;/strong&gt; stands for &lt;em&gt;Fédération Dentaire Internationale&lt;/em&gt; (World Dental Federation). It’s a universal two-digit dental numbering system that identifies each tooth and its quadrant. This standard allows dental findings to be recorded and communicated accurately and internationally, improving interoperability among professionals and systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technologies used
&lt;/h2&gt;

&lt;p&gt;This project combined a complete and modern web stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript (ES6+)&lt;/strong&gt; – Core application logic, event handling, and data processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jQuery&lt;/strong&gt; – DOM manipulation, event delegation, and odontogram plugin integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 Canvas&lt;/strong&gt; – Odontogram rendering and generation of high-resolution PNG reports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS3&lt;/strong&gt; – Responsive styles and professional clinical design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jQuery Odontogram Plugin&lt;/strong&gt; – Interactive odontogram engine (&lt;a href="https://github.com/Adhiana46/jquery-odontogram" rel="noopener noreferrer"&gt;Adhiana46/jquery-odontogram&lt;/a&gt;), extended for our needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; – Data structure for export and backend integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js &amp;amp; Express&lt;/strong&gt; – Backend API to receive and store PNG/JSON files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudinary API&lt;/strong&gt; – Secure, scalable image upload and storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Airtable API&lt;/strong&gt; – Attaching images and structured data to patient records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Softr.io&lt;/strong&gt; – No-code platform used by the client to build the frontend on Airtable and manage patient data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser APIs&lt;/strong&gt; – File handling, image generation, and client-side processing.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FDI anatomical mapping: clinical precision
&lt;/h2&gt;

&lt;p&gt;One of the main technical challenges was implementing &lt;strong&gt;FDI-based anatomical mapping&lt;/strong&gt;. In dentistry, the same position on the canvas (e.g., “left”) can represent “mesial” or “distal” depending on the tooth quadrant.&lt;br&gt;
We developed a system that translates canvas positions (top, bottom, left, right, center) into actual anatomical surfaces (buccal, palatal/lingual, mesial, distal, occlusal/incisal) according to the FDI quadrant—ensuring clinical accuracy and clear communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7mmz9rjh5srv7f3aomx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7mmz9rjh5srv7f3aomx.png" alt=" " width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Dual-layer annotation: mirroring real clinical practice
&lt;/h2&gt;

&lt;p&gt;The app supports two annotation layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-existing (red):&lt;/strong&gt; Conditions or treatments already present&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Required (blue):&lt;/strong&gt; Treatments to be performed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dentist can switch between layers with a single click, and all annotations are color-coded for instant recognition—replicating real-world clinical workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Per-tooth notes: simple clinical documentation
&lt;/h2&gt;

&lt;p&gt;Each tooth allows adding specific notes, with auto-save and manual save/delete options. These notes are included in both the JSON export and the PNG report, ensuring complete clinical documentation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data export: structured JSON and professional PNG reports
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON Export:&lt;/strong&gt; The app exports all odontogram data in a structured format, including date, patient name, annotated teeth, conditions, treatments, and notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PNG Export:&lt;/strong&gt; Generates a professional A4 report containing the odontogram, treatments, notes, patient name, and timestamp. The layout is optimized for clarity and clinical use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxvfj2sk1shwanoux4x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxvfj2sk1shwanoux4x4.png" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Integration with Cloudinary and Airtable: frictionless workflow
&lt;/h2&gt;

&lt;p&gt;A key aspect was integrating with &lt;strong&gt;Cloudinary&lt;/strong&gt; and &lt;strong&gt;Airtable&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a PNG report is generated, the image is uploaded to Cloudinary via its API, ensuring secure and scalable storage.&lt;/li&gt;
&lt;li&gt;The backend (Node.js/Express) attaches the Cloudinary image URL and the structured JSON data to the corresponding patient record in Airtable using the Airtable API.&lt;/li&gt;
&lt;li&gt;As a result, all odontogram images and notes become instantly available within the patient’s record.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Softr.io: no-code frontend for the professional
&lt;/h2&gt;

&lt;p&gt;The client already used &lt;strong&gt;Softr.io&lt;/strong&gt; to build a no-code frontend on top of Airtable. This allows him to manage patient data, visualize odontogram images and notes, and interact with the system without technical barriers. Our app integrates seamlessly into this workflow, ensuring everything appears automatically in his Softr.io dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Maintaining familiarity: respecting user habits
&lt;/h2&gt;

&lt;p&gt;Throughout development, we regularly shared progress with the dentist to ensure the app remained familiar and easy to use. We preserved his existing flow for selecting and annotating treatments while adding modern enhancements like auto-saving notes, color-coded layers, and professional document generation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User-centered design is essential:&lt;/strong&gt; Frequent feedback from the dentist kept the project aligned and ensured adoption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Innovate without losing familiarity:&lt;/strong&gt; New features are valuable only if they remain usable for non-technical users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration is key:&lt;/strong&gt; Adapting to the client’s existing tools (Airtable + Softr.io) made the app truly enhance productivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source accelerates development:&lt;/strong&gt; Building on a solid open-source foundation let us focus on real client needs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The result is a modern, lightweight odontogram web application—powerful yet accessible. By listening to the client and leveraging a complete tech stack (JavaScript, jQuery, HTML5 Canvas, CSS3, Node.js, Express, Cloudinary API, Airtable API, Softr.io), we delivered a tool that integrates seamlessly into the dentist’s daily workflow, making clinical documentation faster, more accurate, and easier to manage.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Project repository:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/zendev2112/odontograma" rel="noopener noreferrer"&gt;https://github.com/zendev2112/odontograma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open-source base:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/Adhiana46/jquery-odontogram" rel="noopener noreferrer"&gt;https://github.com/Adhiana46/jquery-odontogram&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technologies used:&lt;/strong&gt;&lt;br&gt;
JavaScript (ES6+), jQuery, HTML5 Canvas, CSS3, jQuery Odontogram Plugin, JSON, Node.js, Express, Cloudinary API, Airtable API, Softr.io, Browser APIs.&lt;/p&gt;

&lt;p&gt;If you’re building for real users, remember: &lt;strong&gt;listen first, then code!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>ui</category>
      <category>ux</category>
    </item>
  </channel>
</rss>
