<?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: Quentin Dommerc</title>
    <description>The latest articles on DEV Community by Quentin Dommerc (@quentin23soleil).</description>
    <link>https://dev.to/quentin23soleil</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3662424%2F25d94ad9-13e4-4b04-abb3-83073f12a025.jpg</url>
      <title>DEV Community: Quentin Dommerc</title>
      <link>https://dev.to/quentin23soleil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/quentin23soleil"/>
    <language>en</language>
    <item>
      <title>AI without the hype: using LLMs to reduce noise, not replace thinking</title>
      <dc:creator>Quentin Dommerc</dc:creator>
      <pubDate>Sat, 20 Dec 2025 01:17:56 +0000</pubDate>
      <link>https://dev.to/quentin23soleil/ai-without-the-hype-using-llms-to-reduce-noise-not-replace-thinking-2pko</link>
      <guid>https://dev.to/quentin23soleil/ai-without-the-hype-using-llms-to-reduce-noise-not-replace-thinking-2pko</guid>
      <description>&lt;p&gt;This is part 4 of my series on &lt;a href="https://apprevie.ws" rel="noopener noreferrer"&gt;AppReviews&lt;/a&gt;.&lt;br&gt;
Part 1 is available &lt;a href="https://dev.to/quentin23soleil/from-i-should-check-the-reviews-to-a-saas-5bmn"&gt;here&lt;/a&gt;&lt;br&gt;
Part 2 is available &lt;a href="https://dev.to/quentin23soleil/from-feature-creep-to-focus-deciding-what-appreviews-would-never-be-9nh"&gt;here&lt;/a&gt;&lt;br&gt;
Part 3 is available &lt;a href="https://dev.to/quentin23soleil/building-appreviews-the-stack-the-choices-and-the-compromises-37jb"&gt;here&lt;/a&gt;&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%2Fkougf7vosi0yrcqgqhbr.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%2Fkougf7vosi0yrcqgqhbr.png" alt="Grouped reviews per topic" width="800" height="708"&gt;&lt;/a&gt;&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%2F7x1bzbc7zzp03jvvhjud.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%2F7x1bzbc7zzp03jvvhjud.png" alt="Topic nuage to see easily the most common topics" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At some point while building AppReviews, I started thinking about AI.&lt;/p&gt;

&lt;p&gt;Not in a &lt;em&gt;“this needs AI”&lt;/em&gt; way. More in a quiet, slightly reluctant way.&lt;/p&gt;

&lt;p&gt;I already had a system that fetched reviews, pushed them to Slack, and made sure feedback was not missed. That alone solved the core problem. But once reviews are always visible, a new issue appears.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There are a lot of them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some are useful.&lt;br&gt;&lt;br&gt;
Some are vague.&lt;br&gt;&lt;br&gt;
Some are emotional.&lt;br&gt;&lt;br&gt;
Some are duplicates of the same issue written slightly differently.&lt;/p&gt;

&lt;p&gt;Reading every single review works, up to a point. After that, you are back to scanning, skimming, and mentally filtering noise.&lt;/p&gt;

&lt;p&gt;That is when I started asking myself a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What if the system helped me understand reviews faster, without pretending to think for me?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What I did not want
&lt;/h2&gt;

&lt;p&gt;Before adding anything AI-related, I was very clear about what I did not want to build.&lt;/p&gt;

&lt;p&gt;I did not want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI-generated summaries pretending to be insights&lt;/li&gt;
&lt;li&gt;magic scores without explanation&lt;/li&gt;
&lt;li&gt;a chatbot answering users on my behalf&lt;/li&gt;
&lt;li&gt;another dashboard full of charts that look smart but do not help decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of all, I did not want &lt;strong&gt;AI to become the product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AppReviews exists to shorten the feedback loop between users and product teams.&lt;br&gt;&lt;br&gt;
AI should support that goal, not distract from it.&lt;/p&gt;

&lt;p&gt;So the bar was high.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If AI did not reduce cognitive load in a very concrete way, it did not belong.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The actual problem AI helps with
&lt;/h2&gt;

&lt;p&gt;The real problem is not understanding &lt;em&gt;one&lt;/em&gt; review.&lt;/p&gt;

&lt;p&gt;It is understanding &lt;strong&gt;many reviews over time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When ten users describe the same issue in ten different ways, humans are great at seeing the pattern. But only after reading all ten. That does not scale well when reviews keep coming in.&lt;/p&gt;

&lt;p&gt;What I wanted help with was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;grouping similar feedback&lt;/li&gt;
&lt;li&gt;spotting recurring topics&lt;/li&gt;
&lt;li&gt;getting a rough sense of sentiment trends&lt;/li&gt;
&lt;li&gt;surfacing urgency when something suddenly spikes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not answers.  &lt;strong&gt;Signals.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why embeddings first, not prompts everywhere
&lt;/h2&gt;

&lt;p&gt;The first building block I added was embeddings.&lt;/p&gt;

&lt;p&gt;Every review can be turned into a vector that captures its meaning. Once you have that, you can compare reviews semantically instead of relying on keywords or star ratings.&lt;/p&gt;

&lt;p&gt;That immediately unlocks useful things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;similar reviews can be grouped together&lt;/li&gt;
&lt;li&gt;topics emerge naturally instead of being predefined&lt;/li&gt;
&lt;li&gt;you can detect “this feels like the same problem again”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For embeddings, I use &lt;strong&gt;&lt;code&gt;nomic-embed-text&lt;/code&gt;&lt;/strong&gt;. It is fast, local, and good enough for this use case. Each review becomes a &lt;strong&gt;768-dimension vector&lt;/strong&gt; stored alongside the raw text.&lt;/p&gt;

&lt;p&gt;This step alone already adds value, even without a large language model generating text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where LLMs come in, carefully
&lt;/h2&gt;

&lt;p&gt;On top of embeddings, I added a second, &lt;em&gt;optional&lt;/em&gt; layer using a large language model.&lt;/p&gt;

&lt;p&gt;The model I use is &lt;strong&gt;&lt;code&gt;llama3.1:8b&lt;/code&gt;&lt;/strong&gt;, running locally via Ollama. This was an intentional choice.&lt;/p&gt;

&lt;p&gt;I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no per-token cost anxiety&lt;/li&gt;
&lt;li&gt;no external API dependency&lt;/li&gt;
&lt;li&gt;something that could run on my machine or a small server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM is used for very specific tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;estimating sentiment&lt;/li&gt;
&lt;li&gt;extracting high-level topics&lt;/li&gt;
&lt;li&gt;detecting tone such as angry, neutral, or positive&lt;/li&gt;
&lt;li&gt;flagging urgency when relevant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each review is processed independently.&lt;br&gt;&lt;br&gt;
No long context.&lt;br&gt;&lt;br&gt;
No agents.&lt;br&gt;&lt;br&gt;
No orchestration complexity.&lt;/p&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This entire pipeline is optional.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the AI processor is disabled or unavailable, AppReviews works exactly the same. Reviews are still fetched, stored, sent to Slack, and visible in the dashboard.&lt;/p&gt;

&lt;p&gt;AI is an enhancement, not a dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async, isolated, and easy to turn off
&lt;/h2&gt;

&lt;p&gt;From an architectural point of view, AI processing is &lt;strong&gt;completely decoupled&lt;/strong&gt; from the core flow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reviews are saved first&lt;/li&gt;
&lt;li&gt;only then are they queued for analysis&lt;/li&gt;
&lt;li&gt;processing happens asynchronously, in small batches&lt;/li&gt;
&lt;li&gt;failures are retried a few times and then dropped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Ollama is not running, nothing breaks. There is no user-facing error. The system simply skips analysis.&lt;/p&gt;

&lt;p&gt;This was non-negotiable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI systems fail in weird ways. None of that should impact the primary job of the product.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why not “AI-generated insights”
&lt;/h2&gt;

&lt;p&gt;This is probably the question I get the most.&lt;/p&gt;

&lt;p&gt;Why not generate summaries like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Users are unhappy about onboarding”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Most complaints are about performance”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The short answer is simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I do not trust them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Those summaries look nice, but they hide uncertainty. They compress nuance into something that feels authoritative, even when it is not.&lt;/p&gt;

&lt;p&gt;Instead, AppReviews surfaces raw signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;these reviews are similar&lt;/li&gt;
&lt;li&gt;this topic appears often&lt;/li&gt;
&lt;li&gt;sentiment around this feature dropped last week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there, a human can decide what it means.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI should help you see where to look, not tell you what to think.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cost, control, and boring decisions
&lt;/h2&gt;

&lt;p&gt;Running everything locally with Ollama is not the most scalable choice. But it fits the constraints perfectly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no variable costs&lt;/li&gt;
&lt;li&gt;no surprises&lt;/li&gt;
&lt;li&gt;no API keys to rotate&lt;/li&gt;
&lt;li&gt;no privacy questions about sending user feedback elsewhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If AppReviews grows, swapping the AI backend is relatively easy. The interface is already isolated.&lt;/p&gt;

&lt;p&gt;For now, this setup is predictable and controllable.&lt;br&gt;&lt;br&gt;
That matters more than squeezing out the last percentage of accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI does not do, on purpose
&lt;/h2&gt;

&lt;p&gt;To be very clear, AppReviews does &lt;strong&gt;not&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reply to reviews automatically&lt;/li&gt;
&lt;li&gt;decide which feedback matters&lt;/li&gt;
&lt;li&gt;replace reading reviews&lt;/li&gt;
&lt;li&gt;predict user behavior&lt;/li&gt;
&lt;li&gt;generate product decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI does not talk to users.&lt;br&gt;&lt;br&gt;
AI does not act on their behalf.&lt;br&gt;&lt;br&gt;
AI does not override human judgment.&lt;/p&gt;

&lt;p&gt;It just reduces repetition and helps patterns emerge faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The outcome so far
&lt;/h2&gt;

&lt;p&gt;In practice, this approach works surprisingly well.&lt;/p&gt;

&lt;p&gt;You still read reviews.&lt;br&gt;&lt;br&gt;
You still reply yourself.&lt;br&gt;&lt;br&gt;
You still make decisions.&lt;/p&gt;

&lt;p&gt;But you do it with &lt;strong&gt;more context&lt;/strong&gt; and &lt;strong&gt;less noise&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And that is the only promise I am comfortable making.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Start with the human workflow.&lt;br&gt;&lt;br&gt;
Figure out where attention is wasted.&lt;br&gt;&lt;br&gt;
Then see if AI can help reduce that cost.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not the other way around.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>llm</category>
      <category>productivity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building AppReviews: the stack, the choices, and the compromises</title>
      <dc:creator>Quentin Dommerc</dc:creator>
      <pubDate>Tue, 16 Dec 2025 10:30:53 +0000</pubDate>
      <link>https://dev.to/quentin23soleil/building-appreviews-the-stack-the-choices-and-the-compromises-37jb</link>
      <guid>https://dev.to/quentin23soleil/building-appreviews-the-stack-the-choices-and-the-compromises-37jb</guid>
      <description>&lt;p&gt;This is part 3 of my series on &lt;a href="https://apprevie.ws" rel="noopener noreferrer"&gt;AppReviews&lt;/a&gt;.&lt;br&gt;
Part 1 is available &lt;a href="https://dev.to/quentin23soleil/from-i-should-check-the-reviews-to-a-saas-5bmn"&gt;here&lt;/a&gt;&lt;br&gt;
Part 2 is available &lt;a href="https://dev.to/quentin23soleil/from-feature-creep-to-focus-deciding-what-appreviews-would-never-be-9nh"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After talking about why AppReviews exists and how I forced myself to ship a focused v1, it feels natural to talk about the technical side.&lt;/p&gt;

&lt;p&gt;Not in a “here’s my shiny stack” way, but as a snapshot of the decisions I made as a solo developer, working nights and weekends, with limited time and a very clear goal: build something reliable, understandable, and good enough to run in production without turning into a second full-time job.&lt;/p&gt;

&lt;p&gt;This post isn’t about best practices. It’s about trade-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A boring architecture on purpose
&lt;/h2&gt;

&lt;p&gt;At a high level, AppReviews is a monolith.&lt;/p&gt;

&lt;p&gt;It’s a single Next.js 16 application using the App Router. Frontend, API routes, background jobs, and scheduling all live in the same codebase and are deployed together as one unit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No microservices.
&lt;/li&gt;
&lt;li&gt;No separate worker processes.
&lt;/li&gt;
&lt;li&gt;No distributed queues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs in one process.&lt;/p&gt;

&lt;p&gt;That was a very conscious choice.&lt;/p&gt;

&lt;p&gt;The problem AppReviews solves doesn’t require a complex architecture. Reviews are fetched on a schedule, stored, optionally processed, and pushed to Slack. Latency isn’t critical. If a review shows up a few seconds later, nobody cares.&lt;/p&gt;

&lt;p&gt;What matters more is reliability and simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend: TypeScript, Next.js, and in-process jobs
&lt;/h2&gt;

&lt;p&gt;The backend is written in TypeScript, running on Node.js 20+, using ESM modules.&lt;/p&gt;

&lt;p&gt;I chose Next.js App Router for everything, including APIs. All HTTP endpoints are standard route handlers living under &lt;code&gt;src/app/api&lt;/code&gt;. It’s REST-style, straightforward, and easy to reason about.&lt;/p&gt;

&lt;p&gt;Background work is handled with &lt;code&gt;node-cron&lt;/code&gt;, started inside Next.js instrumentation when the server boots. This is probably the most “controversial” choice, but also one of the most pragmatic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There’s no Redis.
&lt;/li&gt;
&lt;li&gt;No BullMQ.
&lt;/li&gt;
&lt;li&gt;No external queue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cron jobs run in-process.&lt;/p&gt;

&lt;p&gt;Review fetching runs every 5 minutes in development and every 30 minutes in production. Weekly Slack summaries go out on Monday mornings. Rating checks run at different frequencies depending on the subscription plan. Export cleanup runs hourly.&lt;/p&gt;

&lt;p&gt;Is this horizontally scalable? &lt;strong&gt;No.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Is it good enough for v1? &lt;strong&gt;Absolutely.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the process crashes, Coolify restarts it and the jobs resume on the next tick. For this use case, that’s acceptable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching reviews: pragmatic over perfect
&lt;/h2&gt;

&lt;p&gt;For the App Store, there are two paths.&lt;/p&gt;

&lt;p&gt;If users want to see appStore reviews, they can configure App Store Connect API credentials and the system will fetch them.&lt;/p&gt;

&lt;p&gt;For Google Play, it uses the official Google Play Developer API with service account authentication.&lt;/p&gt;

&lt;p&gt;Since it's going to be needed to reply to reviews anyway, why bother with scrappers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrations everywhere, but kept simple
&lt;/h2&gt;

&lt;p&gt;AppReviews integrates with a few external services, but each one is intentionally scoped.&lt;/p&gt;

&lt;p&gt;Slack is used to send new reviews, weekly summaries, and rating changes. It uses &lt;code&gt;@slack/web-api&lt;/code&gt;. Messages are fire-and-forget. There’s no retry system yet. If Slack is down, the world doesn’t end.&lt;/p&gt;

&lt;p&gt;Stripe handles subscriptions, checkout, and webhooks. This is one area where I didn’t try to be clever. Stripe’s patterns are well-documented and battle-tested, so I followed them closely.&lt;/p&gt;

&lt;p&gt;Translations are handled via DeepL, optionally.&lt;/p&gt;

&lt;p&gt;Transactional emails are sent using Gmail SMTP via Nodemailer. Not SendGrid. Not Postmark. Just something I already had access to and that works.&lt;/p&gt;

&lt;p&gt;Analytics are tracked with Umami. Simple, privacy-friendly, and enough to know if people are using the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data layer: Prisma and “good enough” modeling
&lt;/h2&gt;

&lt;p&gt;The database is PostgreSQL in production and SQLite locally. Prisma abstracts the difference, which makes local development painless.&lt;/p&gt;

&lt;p&gt;Schema changes are handled through Prisma migrations. There are already quite a few of them, which tells the real story: the model evolved over time.&lt;/p&gt;

&lt;p&gt;The data model covers tenants, apps, reviews, replies, embeddings, analysis, rating history, teams, subscriptions, exports, and more.&lt;/p&gt;

&lt;p&gt;One evolution I’m happy about is the introduction of an &lt;code&gt;AppData&lt;/code&gt; model to deduplicate shared app metadata across tenants. That came later, once it became clear that multiple teams might track the same app.&lt;/p&gt;

&lt;p&gt;There’s no Redis. No cache layer. No fancy optimization. Just indexes on the columns that are queried often and trust in Prisma to generate reasonable queries.&lt;/p&gt;

&lt;p&gt;So far, it’s been fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend: speed first, elegance later
&lt;/h2&gt;

&lt;p&gt;The frontend is also built with Next.js App Router and React.&lt;/p&gt;

&lt;p&gt;Most of it is client-side. Server components exist, but I didn’t force myself to use them everywhere just because they’re “the new thing”.&lt;/p&gt;

&lt;p&gt;Authentication is handled by NextAuth v5 beta. OAuth providers include Google, Apple, GitHub, and LinkedIn. There’s also a custom email/password flow with bcrypt and email verification. The JWT strategy is mapped directly to the tenant model, which doubles as both user and organization.&lt;/p&gt;

&lt;p&gt;Styling is intentionally boring. Plain CSS and inline styles. No Tailwind. No CSS-in-JS. No component library.&lt;/p&gt;

&lt;p&gt;The main dashboard page is a single, very large file. Over 2,500 lines. All the state, effects, and UI live together.&lt;/p&gt;

&lt;p&gt;Is that ideal? No.&lt;br&gt;&lt;br&gt;
Is it fast to work with as a solo dev? Yes.&lt;/p&gt;

&lt;p&gt;Forms use React Hook Form and Zod. Charts use ApexCharts, dynamically imported to avoid SSR issues.&lt;/p&gt;

&lt;p&gt;This is very much a “get it working, clean it later if needed” frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment and infrastructure: minimal and cheap
&lt;/h2&gt;

&lt;p&gt;The app is built as a Docker image using Next.js standalone output. There’s a multi-stage Dockerfile and a small entrypoint script that runs Prisma migrations before starting the server.&lt;/p&gt;

&lt;p&gt;Secrets are managed via environment variables. There’s no dedicated secrets manager.&lt;/p&gt;

&lt;p&gt;Logging uses Winston. Analytics use Rybbit, and it's really great. There’s no APM, no Sentry, no Datadog. But I've setup a grafana with Loki. Yep being solo also means having to learn and setup those things.&lt;/p&gt;

&lt;p&gt;CI/CD isn’t visible in the repo. Deployments happen automatically on git push via Coolify.&lt;/p&gt;

&lt;p&gt;This setup is intentionally boring and cost-conscious. I mean, cost is close to zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constraints, compromises, and being honest about them
&lt;/h2&gt;

&lt;p&gt;This codebase has a lot of “solo developer energy”.&lt;/p&gt;

&lt;p&gt;There are no tests.&lt;br&gt;&lt;br&gt;
There’s no message queue.&lt;br&gt;&lt;br&gt;
There’s no horizontal scaling story.&lt;br&gt;&lt;br&gt;
There are big files.&lt;br&gt;&lt;br&gt;
There are shortcuts.&lt;/p&gt;

&lt;p&gt;All of that is intentional.&lt;/p&gt;

&lt;p&gt;I optimized for shipping something useful, keeping costs very low, and being able to maintain it alone.&lt;/p&gt;

&lt;p&gt;Some things will be easy to change later. Others won’t. That’s fine. Perfect architectures don’t ship products. Imperfect ones do.&lt;/p&gt;

&lt;p&gt;If AppReviews grows, the first things I’d revisit are the in-process cron jobs and the single-instance assumption. Background work would need a proper queue, Slack delivery would need retries, and monitoring would become more serious. The big dashboard page would also need to be split at some point.&lt;/p&gt;

&lt;p&gt;None of this is urgent today. They’re good problems to have, and I’d rather solve them when they’re real.&lt;/p&gt;

&lt;p&gt;And most importantly, &lt;strong&gt;I understand it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the next post, I’ll go deeper into the AI part: why it’s optional, how it’s implemented, and how I’m trying to use it to reduce noise instead of adding more dashboards.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>database</category>
    </item>
    <item>
      <title>From Feature Creep to Focus: Deciding What AppReviews Would Never Be</title>
      <dc:creator>Quentin Dommerc</dc:creator>
      <pubDate>Tue, 16 Dec 2025 10:30:42 +0000</pubDate>
      <link>https://dev.to/quentin23soleil/from-feature-creep-to-focus-deciding-what-appreviews-would-never-be-9nh</link>
      <guid>https://dev.to/quentin23soleil/from-feature-creep-to-focus-deciding-what-appreviews-would-never-be-9nh</guid>
      <description>&lt;p&gt;This is part 2 of my series on &lt;a href="https://apprevie.ws" rel="noopener noreferrer"&gt;AppReviews&lt;/a&gt;.&lt;br&gt;
Part 1 is available &lt;a href="https://dev.to/quentin23soleil/from-i-should-check-the-reviews-to-a-saas-5bmn"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I’m being honest, my first instinct with AppReviews was to keep adding more.&lt;/p&gt;

&lt;p&gt;There’s always this temptation when you build something yourself. The ideas start flowing.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Oh, this would be useful.”&lt;br&gt;&lt;br&gt;
“This would make it even better.”&lt;br&gt;&lt;br&gt;
“What if I also added this?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And before you realize it, you’re no longer building a product. You’re building a backlog.&lt;/p&gt;

&lt;p&gt;I wanted AppReviews to be useful, but I also wanted it to exist. And at some point, those two goals start to conflict.&lt;/p&gt;

&lt;h2&gt;
  
  
  The constant pull of “just one more feature”
&lt;/h2&gt;

&lt;p&gt;Once the core was working, it became very easy to imagine what AppReviews &lt;em&gt;could&lt;/em&gt; become.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A dashboard with charts.
&lt;/li&gt;
&lt;li&gt;Advanced filters.
&lt;/li&gt;
&lt;li&gt;More analytics.
&lt;/li&gt;
&lt;li&gt;More automation.&lt;/li&gt;
&lt;li&gt;More more more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these ideas were valid. Some of them are still on my list. The problem wasn’t the ideas themselves. The problem was that if I kept going down that path, I knew I would never ship.&lt;/p&gt;

&lt;p&gt;I’ve been there before. Spending weeks polishing details, adding features, tweaking UX, until the initial excitement slowly fades and the project stalls.&lt;/p&gt;

&lt;p&gt;I didn’t want that to happen here.&lt;/p&gt;

&lt;p&gt;So I forced myself to ask a very uncomfortable question over and over again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is this required for v1, or do I just enjoy building it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More often than not, the honest answer was the second one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipping v1 meant accepting that it wouldn’t be “complete”
&lt;/h2&gt;

&lt;p&gt;At some point, I had to decide what “good enough” meant.&lt;/p&gt;

&lt;p&gt;For AppReviews, v1 had to do a few things really well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviews should be fetched automatically.&lt;/li&gt;
&lt;li&gt;They should be visible without effort.&lt;/li&gt;
&lt;li&gt;They should reach people where they already are.&lt;/li&gt;
&lt;li&gt;And reacting to them should be fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;Everything else was optional.&lt;/p&gt;

&lt;p&gt;This was harder than it sounds, because as an engineer, it’s very tempting to keep improving things. To add safety nets. To add flexibility. To think ahead for every possible use case.&lt;/p&gt;

&lt;p&gt;But I kept coming back to the same thought: if v1 already solves the core problem, delaying the release doesn’t actually help users. It only satisfies my urge to keep building.&lt;/p&gt;

&lt;p&gt;So I shipped.&lt;/p&gt;

&lt;p&gt;Not because there was nothing left to do, but because there was already enough value there.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AppReviews would &lt;em&gt;not&lt;/em&gt; be (at least for v1)
&lt;/h2&gt;

&lt;p&gt;One of the most useful exercises for me was to explicitly define what AppReviews was not trying to become.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It wasn’t going to be a full review management platform.&lt;/li&gt;
&lt;li&gt;It wasn’t going to replace support tools.&lt;/li&gt;
&lt;li&gt;It wasn’t going to be a heavy analytics product.&lt;/li&gt;
&lt;li&gt;It wasn’t going to require hours of setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are already great tools that do those things. I wasn’t trying to compete with them.&lt;/p&gt;

&lt;p&gt;AppReviews is intentionally narrow in scope. Its job is to reduce friction and shorten the feedback loop between users and product teams.&lt;/p&gt;

&lt;p&gt;Anything that didn’t serve that goal directly was pushed back.&lt;/p&gt;

&lt;p&gt;Some of those ideas will probably come back later. Others might never make it. And that’s fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipping early changed how I think about the product
&lt;/h2&gt;

&lt;p&gt;Releasing v1 didn’t feel like “I’m done”. It felt more like opening a door.&lt;/p&gt;

&lt;p&gt;Once the product is out there, feedback becomes real. You stop guessing. You stop building in a vacuum. You start hearing what people actually care about.&lt;/p&gt;

&lt;p&gt;That’s a much better foundation for deciding what to build next than a long list of assumptions.&lt;/p&gt;

&lt;p&gt;Looking back, I’m glad I resisted the urge to keep adding features before launching. AppReviews is far from finished, but it’s already doing the job it was meant to do.&lt;/p&gt;

&lt;p&gt;And most importantly, it exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaving room to grow
&lt;/h2&gt;

&lt;p&gt;I still have a lot of ideas for AppReviews. Probably too many. Some of them will turn into features. Some won’t.&lt;/p&gt;

&lt;p&gt;But by shipping early, I made sure the product stays grounded in real usage, not just in my head.&lt;/p&gt;

&lt;p&gt;v1 was about focus.&lt;br&gt;
The next versions can be about refinement.&lt;/p&gt;

&lt;p&gt;In the next post, I’ll dive into the technical side of AppReviews: the stack, the architecture, and the choices I made to keep things simple and maintainable as a solo developer.&lt;/p&gt;

</description>
      <category>product</category>
      <category>programming</category>
      <category>uxdesign</category>
      <category>tooling</category>
    </item>
    <item>
      <title>From “I should check the reviews” to a SaaS</title>
      <dc:creator>Quentin Dommerc</dc:creator>
      <pubDate>Mon, 15 Dec 2025 10:49:01 +0000</pubDate>
      <link>https://dev.to/quentin23soleil/from-i-should-check-the-reviews-to-a-saas-5bmn</link>
      <guid>https://dev.to/quentin23soleil/from-i-should-check-the-reviews-to-a-saas-5bmn</guid>
      <description>&lt;p&gt;This is the first part of my journey to creating &lt;a href="//apprevie.ws"&gt;my SaaS AppReviews&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a long time, app reviews lived in a weird place for me.&lt;/p&gt;

&lt;p&gt;I knew they mattered. I knew they were important. I’ve been building Android apps for more than ten years, and I care a lot about product quality and user experience. Reviews are one of the rare places where users tell you, very directly, what they think.&lt;/p&gt;

&lt;p&gt;And yet, they were never really part of my day-to-day work.&lt;/p&gt;

&lt;p&gt;At work, reviews were something you checked “from time to time”. Or when something went wrong. Or when someone remembered. Which usually meant opening App Store Connect, then Google Play Console, logging in, clicking around, scrolling, trying to get a sense of what happened since the last time.&lt;/p&gt;

&lt;p&gt;Most of the time, it felt like &lt;strong&gt;a chore&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The real trigger for AppReviews came from a very practical need at work. We wanted to put some basic checks in place around user reviews. Nothing fancy. We didn’t want dashboards, charts, or weekly reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;We just wanted to know when a new review came in.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ideally, it should show up in Slack. Same place as deploy notifications, CI messages, and alerts. Somewhere we already look all day. Or a different channel.&lt;/p&gt;

&lt;p&gt;When we started looking at existing tools, it felt like everything was either too much or too expensive. Some solutions are clearly built for large companies with dedicated teams handling reviews and customer feedback. They’re powerful, but also overkill if all you want is a simple signal.&lt;/p&gt;

&lt;p&gt;For what we needed, the cost and complexity didn’t really make sense.&lt;/p&gt;

&lt;p&gt;So the alternative was manual checking.&lt;/p&gt;

&lt;p&gt;And that’s where things start to break down.&lt;/p&gt;

&lt;p&gt;Doing it manually is annoying, but worse than that, it’s easy to forget. You tell yourself “I’ll check later”. Later becomes tomorrow. Tomorrow becomes next week. Suddenly, you’re reading a review from seven days ago.&lt;/p&gt;

&lt;p&gt;By then, the moment is gone.&lt;/p&gt;

&lt;p&gt;That part bothered me more than I expected.&lt;/p&gt;

&lt;p&gt;A user who leaves a bad review is often still engaged. &lt;strong&gt;They’re annoyed, but they cared enough&lt;/strong&gt; to write something. If you reply quickly, you can clarify, ask questions, explain, sometimes even fix the issue before it turns into something bigger.&lt;/p&gt;

&lt;p&gt;Replying days later doesn’t have the same effect. It feels distant. Sometimes &lt;em&gt;pointless&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Missed replies aren’t just about ratings. They’re missed chances to understand what actually happened. Missed context. Missed feedback that could have helped avoid the same issue for the next user.&lt;/p&gt;

&lt;p&gt;After seeing this pattern repeat a few times, I did what I usually do when something annoys me enough: I hacked together a script.&lt;/p&gt;

&lt;p&gt;The first version was ugly. No UI. No configuration screen. It just fetched reviews and posted a message in Slack when something new appeared.&lt;/p&gt;

&lt;p&gt;That was it.&lt;/p&gt;

&lt;p&gt;And yet, &lt;strong&gt;the impact was immediate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Reviews stopped being something you had to remember to check. &lt;strong&gt;They just showed up.&lt;/strong&gt; Someone would notice a message in Slack and say “Oh, I saw that one” or “That explains the support ticket we got yesterday”.&lt;/p&gt;

&lt;p&gt;Sometimes it would start a conversation. Sometimes it would lead to a quick reply. Sometimes it would just sit there, but at least it was visible.&lt;/p&gt;

&lt;p&gt;It felt… healthier.&lt;/p&gt;

&lt;p&gt;What surprised me was how small the change was, compared to the effect it had. We didn’t analyze anything. We didn’t optimize. We just removed friction.&lt;/p&gt;

&lt;p&gt;That’s when I realized the core problem wasn’t access to reviews. Anyone can access them. The problem is that they live in places you have to actively go to, and anything that requires a recurring manual action will eventually be delayed.&lt;/p&gt;

&lt;p&gt;Around the same time, I noticed I was doing the exact same thing on my own projects.&lt;/p&gt;

&lt;p&gt;I’d ship something, feel good about it, then think “I should check the reviews”. Sometimes I would. Sometimes I wouldn’t. Sometimes I’d discover feedback way too late and think “I wish I had seen this earlier”.&lt;/p&gt;

&lt;p&gt;Same pattern. Different context.&lt;/p&gt;

&lt;p&gt;That’s when the idea of turning that script into something more serious started to feel obvious.&lt;/p&gt;

&lt;p&gt;At first, I didn’t think of it as a product. It was more like “this should exist”. Something simple, affordable, and focused. Something that doesn’t try to do everything, but does one thing well: make sure reviews reach you, without effort.&lt;/p&gt;

&lt;p&gt;Once I started building it properly, new questions came up.&lt;/p&gt;

&lt;p&gt;If you centralize reviews, how do you avoid creating another place people stop checking? If you have dozens of reviews, how do you quickly understand what’s going on without reading everything?&lt;/p&gt;

&lt;p&gt;I’ve always been more interested in reducing noise than adding features. Most tools fail not because they don’t do enough, but because they do too much. I didn’t want AppReviews to become another dashboard people open once and forget.&lt;/p&gt;

&lt;p&gt;So the focus stayed very narrow: visibility, timeliness, and context.&lt;/p&gt;

&lt;p&gt;Everything else was secondary.&lt;/p&gt;

&lt;p&gt;What I found interesting is that once reviews are always visible, your relationship with them changes. They stop being something slightly stressful you avoid, and become part of the feedback loop of the product.&lt;/p&gt;

&lt;p&gt;You don’t “check reviews” anymore. &lt;strong&gt;You react to them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That shift is small, but it matters.&lt;/p&gt;

&lt;p&gt;At some point, this side project started to take more shape. Nights, weekends, small iterations. A lot of decisions about what not to build. A lot of resisting the temptation to add features just because I could.&lt;/p&gt;

&lt;p&gt;I wasn’t trying to build the ultimate review platform. I was trying to fix a very specific, very human problem I kept running into.&lt;/p&gt;

&lt;p&gt;That moment where you think: “I should check the reviews.”&lt;/p&gt;

&lt;p&gt;In the next post, I’ll talk about how I decided what AppReviews should focus on, and why cutting features turned out to be one of the most important parts of the project.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
