Got tired of debugging webhooks

Hi guys, I have been debugging Stripe/Razorpay webhooks by console.logging everything and praying. Built a thing to fix that.
webhookdog.live, paste the URL into your webhook config, and every request shows up live in your browser. Full headers, body, query params. Click replay to resend any past request without triggering a real payment.
Free, no signup needed to try it.
Would love to know if this solves a real pain for anyone else, and what’s missing.

My Local RAG article went viral. The product it promoted sold 1 copy in 6 months.

Six months ago, I published a Dev.to article called “How I built a 100% offline Second Brain for engineering docs using Docker + Llama 3 (No OpenAI).”

It worked.

  • 380 reads on day one
  • 7 bookmarks, 11 reactions, the works
  • Top Docker Author Badge of the week 🏆
  • A comment thread that actually went somewhere — someone suggested docling, someone else brought up the EU AI Act

For a brand-new Dev.to account with two articles to its name, this is the kind of result that makes you think you’ve cracked something.

The product it linked to — a $59 Dockerized RAG toolkit on Gumroad — has sold 1 copy in the six months since.

This isn’t a “how I failed” post. The article didn’t fail. The product didn’t really fail either — it just didn’t do what the article suggested it would. The gap between those two outcomes is the entire post.

How the article went viral

Looking back, the article hit three buzzwords that the Dev.to algorithm loves stacked together: Llama 3, Docker, and “No OpenAI.” Add #python, #ai, #docker, #automation as tags and you’re hitting four high-traffic feeds at once.

The contrarian framing helped. “No OpenAI” isn’t a neutral technical choice — it’s a position. Positions get bookmarks.

The structure was clean: a relatable pain (you can’t paste NDA-protected schematics into ChatGPT), a clear stack (Ollama + ChromaDB + Streamlit), a docker-compose snippet that looked copy-pasteable, and an honest section about the hard parts (PDF parsing, context window limits, Docker networking on GPU).

I’m not going to pretend the article was lucky. It was structurally good content. The reads were earned.

What I want to talk about is what I thought those reads meant.

Here’s the part most “building in public” posts skip

I didn’t start with a problem. I started with a market.

As an indie maker with a full-time job and two kids, I have maybe 8–12 hours a week for side projects. I needed a product that could actually sell. I noticed Local LLM tutorials were getting strong traction on Dev.to, and I made what felt like an obvious assumption:

Engineers handle sensitive datasheets every day. Privacy must be a real pain point. So a self-hosted RAG with no cloud dependency must be something they’d pay for.

That assumption felt obvious. It wasn’t.

I want to be specific about what was wrong with it, because the error wasn’t “Local LLM is a bad market” — it might be a fine market for someone else. The error was that I confused a problem I could imagine engineers having with a problem engineers actually pay to solve.

Those aren’t the same thing.

Three signals I missed at the time

Signal 1: I wasn’t using my own product

The first signal I should have noticed was the most embarrassing one. I built a Local RAG to keep engineering datasheets off the cloud. My own company has zero IT restrictions. We paste datasheets into ChatGPT every day. Nobody cares.

If I had genuinely needed the product, I would have used it for six months and refined it from real friction. I didn’t. After the initial demos, the Docker stack sat there.

This is the founder version of writing a recipe you’ve never cooked.

Signal 2: Six months, one sale

The product launched alongside the article. Six months later: one paying customer at $59.

One.

Not “low-conversion-funnel” one. Just one.

Signal 3: The feedback from that one customer was sharper than the badge

A few months in, that customer sent me an email. Two points, paraphrased but accurate to his original frustration:

  1. The demo video shows a Mandarin UI, but the Python product is in English. They don’t match up.
  2. “Enterprise-grade”? I assumed it included auth and permission management. It doesn’t. This is just for solo / small-office use, right?

Now, here’s the thing: I never literally used the word “enterprise-grade” in the title. The product is called “Local AI Knowledge Base: Dockerized RAG — Lite Edition.”

But “Knowledge Base” + “Lite Edition” implies a Pro / Enterprise tier exists. He’s not wrong to expect that. The naming wrote a check the product couldn’t cash.

He wasn’t being hostile. He was correcting me. And he was right on both counts:

  • A Mandarin demo video for a product sold globally on Gumroad is a localization gap I never even thought about.
  • “Lite Edition” implies a ladder. There was no ladder. There was just one rung labeled “Lite.”

That email taught me more about my product than the Top Docker Author Badge did.

What the data actually says

Let me lay both metrics side by side, because once you see them together the lesson is hard to miss:

Metric Result
Reads 380+ (day one), still trickling
Reactions 11 (7 bookmarks)
Top Docker Author Badge Yes
Reading list saves 11 logged readers
Paying customers 1
That customer’s price point $59
That customer’s feedback Naming was misleading, localization was off

The first five rows measure how good the article is. The last three measure whether the product is worth paying for.

These are unrelated experiments. Bookmarks don’t predict sales. Badges don’t predict sales. Reading list saves don’t predict sales. A great article can sit on top of a product nobody wants, and a mediocre article can promote a product people actually need.

I knew this in theory before I wrote the article. I didn’t know it know it until I had six months of data showing the gap.

The cognitive trap I want to name

Here is the trap, stated plainly, so the next indie maker writing a Local LLM Dev.to article can skip it:

Content engagement validates that the article resonates. It does not validate that the product solves a problem people pay for.

What would have actually validated the product? A few things I didn’t do:

  • Pre-sell before building. Post the landing page and a waitlist before writing a line of code. If 50 engineers from the article’s traffic don’t drop their email, the demand probably isn’t there.
  • Watch for unprompted referrals. Did any of the 11 bookmarkers share the product with a colleague without me asking? No. That’s the cleanest demand signal you can get, and it was silent.
  • Talk to the one customer who bought. I waited until he emailed me. I should have reached out the day his receipt was opened.

None of these are clever. They’re standard indie-maker advice. I skipped them because the article numbers felt like enough validation. They weren’t.

What I’m doing differently now

I’m not pulling the product down. The one paying customer is still using it, and the article still brings in occasional reads that send the right people to my Gumroad. It’s a small, real, working channel.

But the next product won’t start from “what’s trending on Dev.to.” It’ll start from a problem I personally hit at work, often enough that I’d pay $59 to make it go away.

My latest tool, an IIoT Alarm Engine, came out of that filter. I needed real-time alerts from Modbus and MQTT devices, routed to Slack and Telegram. I built it because I was missing the feature myself, not because the tag was trending. It’s too early to say whether it will sell better. But at least the assumption it’s built on is one I can verify by using it.

If you take one thing from this post

Reads, bookmarks, and badges measure your writing.
Sales measure your product.

They aren’t the same axis. Don’t read one and feel validated about the other.

That’s a six-month, one-sale lesson written down so you can have it for free.

By Phil Yeh — Senior Automation Engineer specializing in Industrial Python and developer tools. I publish post-mortems and engineering case studies on real problems shipping to factories — not the hype. If you want future post-mortems in your inbox: Phil’s Industrial Notes. If you’ve made the same mistake, the comments are open.

Tools I’ve built since: IIoT Alarm Engine, J1939 Decoder GUI, Modbus Logger. Browse the rest: philyeh.gumroad.com.

Mirabile – Land your dream job at top tech companies

Guys, be honest!

Just imagined one day while you are brewing a hot matcha latte in the morning and all of a sudden,.. Ting! You heard the familiar sound of an email notification from your phone. You open and see a big title: “Congratulations! You have been offered a decision to work at Google.”

Being able to do that not only takes an insane amount of efforts, but also a detailed and clear roadmap as well.

But have you ever noticed in today’s digital world there are a huge amount of information, but most of them are just generic and somewhat unrelated to what you are looking for.

That’s why Mirabile is born, an AI-powered career roadmap platform that generates personalized, company-specific learning journeys for engineering roles. You tell it your career goal, your target company, and your timeline — it builds you a complete 18-step roadmap tailored to that exact combination.

Don’t just dream, wake up and actually learn!

-> Live Demo: https://github.com/Stewie-pixel/mirabile.git
-> Try it at: https://stewie-pixel.github.io/mirabile/
-> Github: https://github.com/Stewie-pixel/mirabile.git
-> Youtube: https://youtu.be/drpfJTEzSRI

New Google AI Studio integrations with database and auth using gemini 3.5

This is a submission for the Google I/O Writing Challenge

Google AI Studio now supports native Kotlin to vibe code Android apps. With Google AI studio this is now easy to make and with Firebase services to make into a fullstack app which can be downloadable or published with the model 3.5 gemini is something i find intriguing.

1) So I used the new model to build an alarm app that runs in interval in 10mins and it cam uo with designs which is this I choosed you can customize the design set up and it took me up to 282 seconds for the alarm to be completed


This is the preview of it when it was officially time and I set up differnt times and another imperssive thing was the firebase additon i could litterlay turn this up to a fullstack application use it and vibecode my way to have a little android appliaction

This is the preview of the code of the native kotlin from the new kotlin which is now faster and smarter compared to earlier version of gemini which I give credit to

der how it will fare with bery complex applications in the near future

An impressive thing it did was this brought options to add snooze functionality and multiple alarms and asedk for permissions which was perfectly simulating an andrioid app while working on just one app which will give somoene with little or no tech skills in kotlin to understand what is pertectly going on

using api key and will switch back when back in quota is something I find impressive hold things in memory for you when out of credit and get back to work as expected which is awesome for me seems everyone will become a vibecoder these modern days and just understand the architecture of how things work

Using this model its just like writing on a book understanding the basics and just using the knowledge to bid simple apps, I won

2) Next up the migration agents the basic file vibecoded in vscode in reactive native with the new model was able to migreate this into Kotlin native app which is impressive based on what model you want to use

I focused mainly on the Google Developer Keynote and I cant wait to see what it has install for the next model and how far AI research will go

Thanks for reading my little contribution the Google AI challenge

I built Norway’s EV charging map with Next.js and MapLibre GL JS — and hit a race condition that took me three sessions to fix

I recently shipped StrømVei — an
interactive EV charging map and route planner for Norway, built with Next.js 16,
TypeScript, MapLibre GL JS, and the free Nobil API.

It plots 10,000+ charging stations across Norway, lets you filter by connector
type and speed, and runs a greedy algorithm to calculate optimal charging stops
for long-distance routes.

This post covers the four things that actually taught me something while building
it: the library choice, the clustering solution, a nasty MapLibre race condition
I did not see coming, and the geospatial algorithm. The live demo and source are
at the bottom.

1. Why MapLibre GL JS instead of Mapbox

My original plan was Mapbox GL JS. It is the industry standard for interactive
maps, the documentation is excellent, and every tutorial uses it.

Then I tried to create a free account.

Mapbox requires a credit card even on the free tier. For a portfolio project
deployed publicly, that felt like unnecessary risk — what if demo traffic spiked?
What if I forgot to set a spending cap?

I switched to MapLibre GL JS, the open-source fork of Mapbox GL JS. It was
created in 2021 when Mapbox changed its licence. The API is nearly identical —
same sources, same layers, same events, same clustering. No account required. No
credit card. No API key at all.

For map tiles I used OpenFreeMap (tiles.openfreemap.org/styles/liberty),
which serves free OSM-based vector tiles with no rate limits for reasonable usage.

For routing I used the OSRM public API (router.project-osrm.org) — free,
no key, covers all of Norway.

For geocoding I used Nominatim (nominatim.openstreetmap.org) — free, no
key, with Norway filtering via countrycodes=no.

Total API cost: $0.00. All the map capability of a paid stack, none of the
billing anxiety.

2. Rendering 10,000 markers without crashing the browser

Norway has over 10,000 EV charging stations. My first instinct was to render each
one as a React component on the map. This is the approach most tutorials use for
small datasets.

For 10,000 markers it is catastrophically slow. React re-renders all of them on
any state change. The browser grinds to a halt.

The correct approach for large datasets is MapLibre’s built-in GeoJSON cluster
source
. You add a single source with cluster: true, and MapLibre handles
grouping, rendering and unclustering entirely in WebGL — no React involved.


typescript
map.addSource('stations', {
  type: 'geojson',
  data: stationsGeoJSON,
  cluster: true,
  clusterMaxZoom: 13,
  clusterRadius: 50,
});


Then you add three layers on top of that source: one for cluster circles, one
for the cluster count labels, and one for individual dots at high zoom. Each
layer uses MapLibre expressions to style by data properties — connector speed in
my case:

map.addLayer({
  id: 'unclustered-point',
  type: 'circle',
  source: 'stations',
  filter: ['!', ['has', 'point_count']],
  paint: {
    'circle-color': [
      'case',
      ['>', ['get', 'maxSpeedKw'], 50], '#0066FF', // rapid — blue
      ['>=', ['get', 'maxSpeedKw'], 22], '#1A7A4A', // fast — green
      '#6B7280',                                    // slow — grey
    ],
    'circle-radius': 7,
    'circle-stroke-width': 2,
    'circle-stroke-color': '#ffffff',
  },
});
The result: 10,000 stations render instantly, zoom and pan at 60fps, and
cluster/uncluster smoothly. The difference versus React markers is not subtle —
it is the difference between a working app and a broken one.

3. The race condition that took three sessions to fix
This one hurt.

After the user enters a route and clicks "Finn rute", the app fetches geometry
from OSRM and tries to draw a blue line on the map. For two full sessions I could
not get the route line to appear. No errors. The fetch succeeded. The GeoJSON was
valid. But the map showed nothing.

Here is the simplified version of what I had:

useEffect(() => {
  const map = mapRef.current;
  if (!map) return;

  const update = () => {
    // remove old layers, add new source + layers with route data
  };

  if (map.isStyleLoaded()) {
    update();
  } else {
    map.once('load', update); // ← this was the bug
  }
}, [route]);
The logic looks reasonable. If the style is loaded, run immediately. Otherwise
wait for the load event.

The problem is that map.once('load') only fires once — at initial startup.
If the user pans or zooms the map before clicking "Finn rute", MapLibre starts
fetching new tiles. During tile fetching, isStyleLoaded() returns false. But
load has already fired and will never fire again. So update() is never called.
The route is silently dropped.

The fix is one word: replace 'load' with 'idle'.

if (map.isStyleLoaded()) {
  update();
} else {
  map.once('idle', update); // ← fires whenever rendering completes
}

return () => {
  map.off('idle', update); // clean up if route changes before idle fires
};
The idle event fires whenever MapLibre finishes rendering — after tiles load,
after panning stops, after anything. It always fires eventually. Once I understood
this, I applied the same fix to the stations effect too, since it had the same
latent bug.

The cleanup map.off('idle', update) in the effect return is also important: if
the route changes before idle fires, you want to cancel the pending callback
and let the next effect run instead.

The lesson: isStyleLoaded() is not a simple boolean. It also checks whether
source data is done loading. 'load' is a one-time startup event. For any
deferred map update, 'idle' is the correct fallback.

4. Layer ordering in OpenFreeMap
A second issue with the route line: even when it did appear, it was sometimes
invisible because it rendered underneath the base map's fill layers.

In MapLibre you can insert a layer before an existing one using the beforeId
parameter. Many tutorials suggest finding the first symbol layer in the style and
inserting before that:

const firstSymbolId = map.getStyle().layers
  .find(l => l.type === 'symbol')?.id;

map.addLayer({ id: 'route-line', ... }, firstSymbolId);
In OpenFreeMap's liberty style, the first symbol layer is positioned quite low in
the stack — below fill layers. The route line appeared to insert correctly but was
hidden under polygons.

The fix was to use a known layer I added myself as the anchor instead:

const beforeId = map.getLayer('clusters') ? 'clusters' : undefined;
map.addLayer({ id: 'route-line', ... }, beforeId);
This inserts the route below the station cluster circles but above all base map
layers. Reliable regardless of how the tile style orders its own layers.

5. The greedy charging stop algorithm
The route planner takes an origin, destination, car range (km) and minimum charge
percentage, then calculates where you need to stop to charge.

The algorithm runs on the OSRM route geometry — a GeoJSON LineString with
hundreds of coordinate points tracing the actual road. The core of it uses
Turf.js:

import { nearestPointOnLine, length, point } from '@turf/turf';

// Project each station onto the route line
const projected = stations.map(station => {
  const pt = point([station.position.lng, station.position.lat]);
  const snapped = nearestPointOnLine(routeLine, pt, { units: 'kilometers' });
  return {
    station,
    kmAlongRoute: snapped.properties.location, // distance in km from route start
    distanceFromLine: snapped.properties.dist,
  };
});

// Keep only stations within 5km of the route
const corridor = projected.filter(s => s.distanceFromLine <= 5);
corridor.sort((a, b) => a.kmAlongRoute - b.kmAlongRoute);
One non-obvious detail: when you call nearestPointOnLine with
{ units: 'kilometers' }, the returned feature's properties.location is the
distance in kilometres from the start of the line — not a 0–1 fraction. This
is not clearly documented. Getting it wrong produces completely nonsensical stop
ordering.

The greedy algorithm itself:

const effectiveRange = carRangeKm * (1 - minChargePct / 100);
let currentKm = 0;
const stops: ChargingStop[] = [];

while (currentKm + effectiveRange < totalRouteKm) {
  // Find all stations reachable from current position
  const reachable = corridor.filter(s =>
    s.kmAlongRoute > currentKm &&
    s.kmAlongRoute <= currentKm + effectiveRange
  );

  if (reachable.length === 0) {
    return { ok: false, error: 'no_station_in_range' };
  }

  // Pick the one furthest along the route
  const best = reachable.reduce((a, b) =>
    a.kmAlongRoute > b.kmAlongRoute ? a : b
  );

  stops.push({ station: best.station, distanceFromStartKm: best.kmAlongRoute });
  currentKm = best.kmAlongRoute;
}

return { ok: true, stops };
"Furthest reachable" is the greedy choice — it minimises the number of stops by
always jumping as far forward as possible. For the Oslo–Bergen route (about 480
km) with a 400 km range and 20% minimum charge, the algorithm correctly picks one
stop at Fortum Eidfjord around km 309.

The Norwegian-specific parts
The data source is Nobil — Norway's national EV charging station database,
operated by the Norwegian Electric Vehicle Association. It is free for
non-commercial use and contains live availability data for ~10,000 stations. I
proxy the API server-side to hide the key and add a 15-minute cache:

// src/app/api/nobil/stations/route.ts
let cache: { data: NobilStation[]; cachedAt: number } | null = null;
const CACHE_TTL = 15 * 60 * 1000;

export async function GET() {
  if (cache && Date.now() - cache.cachedAt < CACHE_TTL) {
    return Response.json({ stations: cache.data, cached: true });
  }
  // fetch from Nobil, parse, store in cache
}
Norway has the highest EV adoption rate in the world — around 90% of new car
sales in 2024. Long-distance route planning with charging stops is a real,
everyday problem for Norwegian drivers, which is what made this worth building.

What I would do differently
Move Turf.js to a Web Worker. With the current 18 mock stations it runs in
under 5ms. With the real 10,000-station dataset, projecting each station onto the
route line becomes a meaningful computation. It should not run on the main thread.

Add streaming to the route result. Right now the panel waits for the full
OSRM response before showing anything. A streaming approach would show the route
drawing progressively, which feels faster even if it isn't.

Real-time availability. The Nobil API includes live connector status but I
used the static snapshot. A polling interval or WebSocket connection would make
the availability dots actually meaningful.

Links
Live demo: stromvei-project.vercel.app
Source code: github.com/adyelmoro/stromvei-project
If you hit the MapLibre idle vs load issue and this helped, or if you're
building something with Norwegian APIs and want to compare notes — drop a comment.

Next up: DokumentAI — a Norwegian business document Q&A app using RAG,
pgvector, and the Claude API. Same stack, very different problem.

---
That's the full article — paste it directly into dev.to, preview it, and publish. A few quick notes:
- The **cover image** line at the top uses your og-image.svg — dev.to will pull it automatically
- The **code blocks** will syntax-highlight automatically on dev.to
- Estimated read time: about **8 minutes** — that's the sweet spot for technical articles that rank well
- The `idle` vs `load` section is the strongest part — that specific problem has almost no good documentation online, so this article will genuinely show up in Google searches

My Internship Experience at Mantis Software Company

Over the past few weeks during my internship, I had the opportunity not only to write code but also to learn how AI-assisted software development processes actually work. Working with large language models, understanding the logic behind prompt engineering, and transforming an idea into a functioning project was an incredibly educational experience for me. In this article, I will talk about both the AI-based RPG project we developed and the technical concepts I learned throughout the process.

What is Prompt Engineering?

Prompt engineering is the process of designing commands or instructions given to an AI model in a way that produces the most accurate results. At first, it may seem like simply “asking questions,” but in reality, it has a significant impact on how the model behaves.

For example, there is a huge difference between telling the same model:

“Write a story.”

and saying:

“Create an interactive RPG story set in the Middle Ages with a dark atmosphere and three selectable actions.”

In the second example, the model’s:

  • tone,
  • environment,
  • output format,
  • and user experience

become much more controlled.

Prompt engineering was especially important in our RPG project because the AI needed to:

  • generate consistent characters,
  • maintain story continuity,
  • produce outputs in JSON format,
  • preserve the same atmosphere throughout the game.

What Did We Pay Attention to While Writing Prompts?

One of the most important things I learned while writing prompts was that vague commands produce vague results. It is essential to clearly define what the model is expected to do.

Some of the main points we focused on were:

  • Clearly defining the output format
  • Specifying the role of the model
  • Avoiding unnecessary freedom
  • Adding rules to maintain consistency
  • Considering error scenarios
  • Keeping user experience in mind

For example, since we wanted the model to generate JSON instead of plain text, we explicitly defined the required fields inside the prompt:

{
  "karakterAdi": "Kaptan Armand Devereux",
  "karakterArkaplan": "1692 yılında Karayipler’de ün salmış eski bir Fransız korsanıdır. Genç yaşta donanmadan ayrılmış ve kendi mürettebatını kurarak tehlikeli sularda yaşamaya başlamıştır. Altın ticaret gemilerine yaptığı baskınlarla tanınır ancak son yıllarda kayıp bir hazineyi bulmaya takıntılı hale gelmiştir.",
  "karakterDt": "17. yüzyıl, Karayipler",
  "olaylar": "Fırtınalı bir gecede geminizle terk edilmiş bir adaya yaklaşıyorsunuz. Mürettebatınız huzursuz görünüyor çünkü adanın lanetli olduğuna dair söylentiler duyulmuş durumda. Ancak eski bir harita, kayıp hazineye ulaşmanın yalnızca burada mümkün olduğunu gösteriyor.",
  "muhtemelAksiyonlar": [
    "Mürettebatı toplayıp gece hemen adaya çık.",
    "Sabaha kadar gemide bekleyip adayı uzaktan gözlemle.",
    "Haritadaki işaretleri tekrar inceleyerek farklı bir rota belirle."
  ]
}

This structure allowed us to process the data much more efficiently on the application side.

Our Project: Past Life Simulator

During the internship, we developed an AI-powered RPG game called Past Life Simulator.

In the game, the user selects a character such as:

  • Pirate
  • Knight
  • Explorer
  • Monsieur

and enters a dynamic story generated entirely by AI.

At each turn, the player is presented with three different actions. Depending on the selected choice, the story changes completely. Unlike traditional branching scenario systems, the content here is generated instantly by artificial intelligence.

In the project, we used:

  • Mistral AI API
  • Python & Flask
  • HTML/CSS
  • Vanilla JavaScript

We also paid close attention to mobile compatibility and user experience.

Why Did We Create an SRS Document?

Before starting development, we did not immediately begin coding. First, we prepared an SRS (Software Requirements Specification) document.

At first, I thought this step was unnecessary, but as the project progressed, I understood why it was so important.

The SRS document helped us:

  • clarify the project scope,
  • define requirements clearly,
  • determine which features would be implemented,
  • anticipate possible problems,
  • provide more accurate guidance to AI tools.

Our SRS document included:

  • functional requirements,
  • user scenarios,
  • API structure,
  • interface requirements,
  • performance expectations,
  • error handling,
  • security details.

For example, the document explicitly specified that:

  • the game would run in a single Python file,
  • no JS framework would be used,
  • Mistral API would handle AI interactions,
  • game progress would not be stored.

Because of this planning process, we were able to move forward more systematically instead of constantly deciding what to do next.

Converting the SRS Document into AGENTS.md / CLAUDE.md

One of the most interesting experiences was converting the SRS document into a technical planning document that AI tools could understand.

For this process, we used Claude.ai.

A standard SRS document is written for humans, but AI coding tools work better with documents that are:

  • shorter,
  • more technical,
  • more task-oriented.

Because of this, we simplified information such as:

  • project goals,
  • technical requirements,
  • tasks,
  • file structures,
  • API behaviors

and converted them into AGENTS.md formats.

During this transformation process, we:

  • removed unnecessary explanations,
  • organized technical tasks into structured lists,
  • created clear commands that AI tools could execute.

In a way, prompt engineering logic was involved here as well.

Developing the Application with OpenCode Desktop

Afterward, we started developing the project using OpenCode Desktop.

The most impressive part of OpenCode was its ability to assist development through natural language commands.

For example, commands like:

  • “Fix this error”
  • “Move to the next step”
  • “Improve mobile compatibility”
  • “Reorganize the buttons”

could be used to modify the project.

During this process, I realized something important: AI tools do not create miracles on their own. If they are not guided correctly, they can produce incomplete or incorrect results. That is why understanding software development logic is still extremely important.

Human control remains essential, especially in areas such as:

  • debugging,
  • performance optimization,
  • user experience,
  • code organization.

What Did I Learn from This Process?

This experience taught me not only about artificial intelligence but also about software development discipline itself.

Some of the most important lessons I learned were:

  • Planning comes before coding.
  • Writing good prompts is a serious skill.
  • AI tools can guide developers, but control should still remain with humans.
  • Documentation is much more important than I initially thought.
  • User experience is just as valuable as technical success.

Especially the SRS preparation and prompt engineering aspects completely changed my perspective on software development.

During this internship, I improved both my technical skills and my understanding of how important AI-assisted software development processes will become in the future.

Dijital vesayete karşı uyarı: Algoritmalara teslim olmayacağız

“Dijital dünyanın, dezenformasyon başta olmak üzere birçok konunun farkında olmamızı gerektirdiği bir noktadayız. Algoritmalar tarafından yönlendirilmeyeceğiz. Dijital vesayetin farkında olmadan dominasyonu altında kalmayacağız. Biz veri üreteceğiz”
– “Artık yapay zekayı biz de kullanarak yapay zeka ile üretilmiş olan dezenformasyonları tespit ediyoruz. CİMER ve dezenformasyon bildirim servisi üzerinden yine bu gayretimizi devam ettiriyoruz”

Balıkesir Teknokent Özbekistan'da irtibat ofisi açtı

Balıkesir Üniversitesi Teknokent, Özbekistan’ın başkenti Taşkent’te Uluslararası İrtibat Ofisi açtı. Ofis, Türkiye ile Özbekistan arasında teknoloji, AR-GE, inovasyon ve girişimcilik alanlarında işbirliği köprüsü oluşturmayı hedefliyor.

Azimle Engelleri Aşan Aileye Vali Ziyareti

Eskişehir Valisi, işitme engelli bilgisayar mühendisi Burak Uyanık ve eşi matematik öğretmeni Gizem Uyanık’ı evlerinde ziyaret ederek başarı hikayelerini dinledi. Vali Yılmaz, azimle engelleri aşan aileyi örnek gösterdi.