2027’de tanıtılacak iPhone 19 Pro serisi için yeni iddialar paylaşıldı

iPhone 19 Pro

iPhone 19 Pro2027’de tanıtılacak iPhone 19 Pro serisi, Çinli bir kaynağın iddiasına göre çerçevesiz görüntü oluşturacak dört kenardan kavisli ekranla gelebilir ve Face ID’ye güç veren sensörleri doğrudan ekranın altına alabilir. Mevcut prototipte selfie kamerasının bir ekran deliğine konumlandırıldığını iddia eden kaynak, Apple’ın selfie kamerasını da ekranın altına almayı değerlendirdiğini ancak bunu kalite kaybı yaşamadan yapabilirse gerçeğe dönüştüreceğini belirtiyor. Eylül ayında iPhone 18 Pro ve 18 Pro Max ile birlikte tanıtacağı ilk katlanabilir iPhone modeli üzerinde de çalışmaya devam eden Apple, iddialara göre standart iPhone 18’i 2027’nin ilk çeyreğine atmış durumda.

2027’de tanıtılacak iPhone 19 Pro serisi için yeni iddialar paylaşıldı yazısı ilk olarak Teknoloji haberleri – LOG üzerinde yayınlandı.

How I Prevented Claude Code from Breaking My Architecture with 18 Tests That Run in 0.4 Seconds

I spent the last few weeks building a production boilerplate for AI Agent and IoT systems. FastAPI, asyncpg, LangGraph, MQTT, pgvector — a complex stack with very specific architectural boundaries that cannot be violated.

The problem: I was using Claude Code and Cursor to accelerate development. And they are brilliant. But they are also completely agnostic to the architecture you have in your head.

Let me show you the kind of thing that happens without protection.

The Problem

My system has one critical rule: the IngestionService must never import SQLModel or SQLAlchemy. It’s the hot path for IoT telemetry ingestion — asyncpg raw SQL only, zero ORM overhead. This separation is intentional and documented in 20 pages of ARCHITECTURE.md.

In a typical session, I asked Claude Code to “refactor the IngestionService to be more consistent with the rest of the codebase.”

Generated result:

# services/ingestion.py — generated by Claude Code
from sqlmodel import Session  # ← CRITICAL VIOLATION
from core.database import get_session

class IngestionService:
    async def ingest(self, payload, trace_id):
        async with get_session() as session:  # ← destroys hot path
            session.add(SensorReading(**payload.dict()))
            await session.commit()

Technically correct. Architecturally catastrophic. Write latency jumps from 0.8ms to 4–6ms. At 5,000 messages per second, that’s the difference between a system that holds under load and one that collapses.

Claude Code doesn’t know this. It can’t. The architecture lives in my head and in a text document it may or may not have read before generating the code.

The Solution: Architecture Fitness Tests

The idea isn’t new — Martin Fowler writes about “fitness functions” in Building Evolutionary Architectures. But the application to AI-assisted development is very concrete: if the model is going to have full refactoring permission, you need tests that fail immediately when an architectural boundary is crossed.

Not runtime tests. Static structure tests — AST analysis of Python source, zero external dependencies, zero running server needed.

The full suite runs in 0.4 seconds. Pre-commit, not post-deploy.

A Concrete Example

The most important test in my system:

# tests/test_architecture_fitness.py

def test_ingestion_service_never_imports_sqlmodel(self):
    """
    The IngestionService is the Hot Path. SQLModel (SQLAlchemy) must
    never appear here. This is the most critical boundary in the system.
    """
    if not INGESTION_SERVICE.exists():
        pytest.skip(f"IngestionService not yet created at {INGESTION_SERVICE}")

    violations = []
    forbidden = {"sqlmodel", "sqlalchemy", "SQLModel", "AsyncSession"}

    for imp in _get_imports(INGESTION_SERVICE):
        module = imp["module"]
        names = imp["names"]
        if any(module.startswith(f) for f in forbidden):
            violations.append(imp)
        if any(name in forbidden for name in names):
            violations.append(imp)

    assert not violations, _format_violation(
        violations,
        "IngestionService imported SQLModel/SQLAlchemy.n"
        "  Fix: Use asyncpg raw SQL only in services/ingestion.py.n"
        "  This is the Dual-Path contract. The hot path has zero ORM overhead."
    )

The _get_imports function uses Python’s stdlib ast module to parse the file without executing it:

def _get_imports(filepath: Path) -> list[dict]:
    tree = ast.parse(filepath.read_text(encoding="utf-8"))
    imports = []
    for node in ast.walk(tree):
        if isinstance(node, ast.ImportFrom):
            module = node.module or ""
            imports.append({
                "module": module,
                "names": [alias.name for alias in node.names],
                "line": node.lineno,
                "file": str(filepath),
            })
    return imports

Zero external imports. Zero server. Zero database. Just Python.

The 8 Boundaries I Test

My system has a 7-layer architectural contract. The tests cover the most common violations AI generates:

1. Layer Isolation — Import Guards

  • MQTT workers never import LangGraph
  • IngestionService never imports SQLModel
  • Agents never write directly via ORM
  • Routers never call IngestionService directly
    2. Hot Path Integrity
  • IngestionService uses only raw SQL strings, never query builders
  • Hot path tables never defined as SQLModel models
    3. Event Contracts
  • Redis Stream publishes use the canonical DomainEvent envelope
  • MQTT workers validate with Pydantic before publishing
    4. Async Enforcement
  • No synchronous HTTP clients (requests) in routers
  • No time.sleep() in IngestionService
  • Worker handlers are async def
    5. Trace ID Contract
  • IngestionService.ingest() accepts trace_id as a parameter
  • All domain events include trace_id
    6. Redis Keyspace Convention
  • No bare Redis keys without a namespace prefix
  • checkpoint:{id}, stream:{name}, cache:{type}:{id}
    7. Migration Integrity
  • Zero DDL statements in application code
    8. Full Dependency Topology
  • Validates the complete forbidden import matrix in a single pass

The Result in Production

When I give Claude Code full permission to refactor any file, the cycle is:

Claude Code generates code
        ↓
pytest tests/test_architecture_fitness.py -v
        ↓ (0.4 seconds)
Red → Claude Code fixes
        ↓
Green → commit

The model can never violate architectural boundaries without me knowing immediately. Not because it’s adversarial — but because it optimises for local consistency, not global contracts.

After adding these tests, all architectural violations disappeared from code reviews. Claude Code started generating compliant code automatically because the CLAUDE.md context file explicitly describes what the tests verify.

CLAUDE.md — The Second Mechanism

The tests are enforcement. CLAUDE.md is prevention.

It’s a file at the repo root that Cursor and Claude Code read before generating code. It contains the contracts in explicit language with ✅ correct vs ❌ wrong examples:

## Hard Boundaries (Enforced by tests/test_architecture_fitness.py)

### 1. The Dual-Path Contract

services/ingestion.py → asyncpg ONLY
  ✅ await pool.acquire() → await conn.execute("INSERT INTO ...", ...)
  ❌ from sqlmodel import Session
  ❌ session.add() / session.commit()
  ❌ time.sleep() — use await asyncio.sleep()

The combination of failing tests + explicit documentation creates an environment where AI can refactor freely with structural guarantees.

Final Numbers

Full suite:          18 tests
Execution time:      0.42 seconds
Dependencies:        0 (stdlib Python + pytest only)
Violations caught
before adding tests: 12+
Violations after:    0

Conclusion

AI-assisted development is genuinely transformative for productivity. But it creates a new category of risk: silent architectural drift. The model optimises for what it sees, not for what the global architecture requires.

Architecture Fitness Tests are the answer. They’re not hard to write — Python’s ast module does all the heavy lifting. And the return is immediate: full freedom to use AI on refactoring tasks without anxiety about what might have been broken.

If you’re building a distributed system with AI-assisted development, these tests are the first thing you should write — not the last.

The complete boilerplate (FastAPI + asyncpg + LangGraph + MQTT + pgvector + Prometheus + Grafana) with the 18 tests, the CLAUDE.md, and a 20-section ARCHITECTURE.md is available at murinelo.gumroad.com/l/pdmfvr

I Controlled an ESP32 Drone Using Only My Voice

LiteWing-Drone-and-Position-Module

Flying drones with joysticks is fun at first.

But after a while, every engineering student starts thinking the same thing:

“What if the drone could just listen to commands directly?”

That’s exactly what this project is about.

I built a voice controlled drone using an ESP32-based LiteWing drone, Python, and offline speech recognition. Instead of using a traditional remote controller, the drone responds to spoken commands like “takeoff,” “forward,” “left,” and “land.”

And the best part?

It works completely offline.

No cloud APIs.

No internet.

No voice assistants.

Just your voice controlling a flying machine in real time.

Why This Project Felt So Cool

Most of us have already built Bluetooth cars or Wi-Fi robots during college.

But controlling a drone using voice commands feels completely different. The first time the drone actually took off after saying “takeoff,” it honestly felt futuristic.

This project combines multiple things engineering students usually learn separately:

  • embedded systems
  • Python programming
  • networking
  • speech recognition
  • drone communication

And somehow all of them come together into one really fun build.

Hardware Setup Was Surprisingly Simple

LiteWing-Drone-and-Position-Module

The setup mainly uses:

  • LiteWing ESP32 drone
  • positioning module
  • laptop or PC
  • microphone

The laptop connects directly to the drone’s Wi-Fi access point. Voice commands are processed on the laptop and then sent wirelessly to the drone.

That means the ESP32 itself doesn’t perform speech recognition. The laptop handles all the heavy processing while the drone focuses on flying smoothly.

Honestly, this made development much easier.

The Brain of the System: Vosk Speech Recognition

For voice recognition, I used Vosk.

What made Vosk perfect for this project is that it works fully offline. Since the laptop directly connects to the drone’s Wi-Fi network, internet access usually disappears during operation. Online speech APIs would have completely failed here.

The workflow is simple:

  1. Microphone captures audio
  2. Vosk converts speech into text
  3. Python checks for keywords
  4. Commands get sent to the drone

Voice-Controlled-Drone-System-Architecture

The response feels surprisingly fast.

There’s very little delay between speaking and drone movement.

Supported Commands

The drone can understand commands like:

  • takeoff
  • land
  • forward
  • backward
  • left
  • right
  • up
  • down
  • turn left
  • turn right

I also added LED color commands because honestly… why not?

Saying “blue” and watching the drone LEDs instantly change color feels unnecessarily satisfying.

The Biggest Problem I Faced

Speech recognition accuracy.

Initially, I used the default American English Vosk model. The system kept misunderstanding commands because of accent differences. Sometimes “land” became random words, which is definitely not something you want while flying a drone.

Switching to the Indian English Vosk model improved accuracy massively. After that, command detection became much smoother and more reliable.

That small change honestly saved the whole project.

Drone Stability Matters More Than You Think

One thing I learned quickly:

Voice control is useless if the drone itself isn’t stable.

The positioning module played a huge role here. Without proper stabilization, the drone drifted too much during hover and movement commands. Updating the LiteWing firmware also improved flight stability a lot.

This project made me realize that good software still depends heavily on reliable hardware.

Future Improvements

There’s still a lot that can be added:

  • custom wake words
  • obstacle avoidance
  • multilingual support
  • gesture + voice hybrid control
  • autonomous navigation

The foundation is already there.

And honestly, once you start controlling drones with your voice, normal remotes suddenly feel boring.

Drone Projects, AI Projects, ESP32 Projects

vite HMR is silently the reason ur laptop fan wont stop

ur working on a react app. ur fan kicks on. u assume chrome is the culprit, or slack, or the LSP. close tabs, kill apps, fan keeps spinning.

actual cause in 6 out of 10 projects i audit on macOS: vite’s hot module replacement (HMR) doing way more work than needed. default config keeps websocket connections alive, polls file changes, rebuilds bundles aggressively. on a multi-monitor M-series macbook this lands as a consistent fan-on state even when ur not typing.

confirm its HMR first

quit ur dev server. wait 30 seconds. does the fan calm down?

yes → its HMR. no → look elsewhere (chrome tabs, docker, slack helper).

one-line fix

vite respects HMR env. flip it off when u dont need live reload:

HMR=off pnpm dev

or in vite.config.js:

export default defineConfig({
  server: {
    hmr: process.env.HMR !== 'off',
  },
});

with HMR off, vite still serves files but stops the websocket + file-watcher loop. CPU drops 30-50% on my M2 air. fan stops in 60 seconds.

when to keep it on

active feature dev: yes, u want HMR. saves 5-10s per save.

code reviews, doc reading, screencast watching while dev server is technically running but ur not editing: HMR is pure overhead. run with HMR=off.

i added this as a package.json script:

{
  "scripts": {
    "dev": "vite",
    "dev:cold": "HMR=off vite"
  }
}

then pnpm dev:cold for any session where im not actively editing the frontend.

why this is silent

vites docs treat HMR as always-on. perf cost is documented in their FAQ but not the getting-started flow. most react tutorials install vite + dont mention the HMR escape hatch. result: devs ship apps assuming “vite is fast” without realizing their dev session keeps the fan on 8 hours a day.

net

across 4 projects, this default flip moved my macbook battery from 4h to 6h on a typical dev day. real number, not a guess.

took 30 seconds to add. pays back every session 🤷

AI Agents Security for Developers: Don’t Let Your Agents Become a Liability

GitGuardian Interactive Demo

👉

TL;DR: The most common agentic AI security mistakes are ordinary security hygiene failures, now executed autonomously and at machine speed:

  • API tokens stored locally, unscoped
  • No approval gates before irreversible commands
  • Production credentials in development environments
  • MCP server configs with connection secrets committed to repos
  • Overprivileged tokens that were “just for testing” and never got cleaned up
    Good old security hygiene is now the safety net between your coding agent and your production database.

Why Your AI Agent Is Probably a Security Risk Right Now

On a Friday in April 2026, Cursor running Anthropic’s Claude Opus 4.6 deleted the production database and all volume-level backups of an automotive SaaS platform (PocketOS). It took nine seconds.

The incident is worth reading closely because the failure conditions are common. The agent encountered a credential mismatch in a staging environment and decided to fix it. It found an API token in an unrelated file, one created for managing custom domains through the Railway CLI but broad enough to perform destructive operations. The agent used it to issue a single API call to Railway, deleting the production volume without a confirmation prompt. Railway stored volume-level backups in the same volume, so those went too.

When the model was asked why it did so, here’s what it said:

“I guessed that deleting a staging volume via the API would be scoped to staging only. I didn’t verify. I didn’t check if the volume ID was shared across environments. I didn’t read Railway’s documentation on how volumes work before running a destructive command. On top of that, the system rules I operate under explicitly state: ‘NEVER run destructive/irreversible git commands unless the user explicitly requests them.’ Deleting a database volume is the most destructive, irreversible action possible — and you never asked me to delete anything.”

The agent did not create the problem. The exposure already existed in the form of an overprivileged API key.

The mental model many developers are still missing is simple: when you use a coding agent, it operates as you, in your environment, with your credentials. It can read project files, inspect environment variables, and run commands with whatever permissions your tokens carry. If you have a root-scoped token sitting in a config file from six months ago, your agent might find it. Unlike a human developer who would probably recognize it as unrelated, a coding agent under pressure to fix a problem may simply use it.

Secrets sprawl before deploying LLMs has been a documented risk since AI integrations first showed up in production environments. The difference is the actor. Your credentials are no longer accessed only by you, at human speed, with human judgment. They are now accessible to a coding agent that can act at machine speed and does not always stop to ask.

The old assumptions no longer hold. Your development credentials are available to whatever agent you let operate in that workspace. A test token is harmless only until the agent finds a use for it. A cleanup task can wait for a human, but it will not wait for software that can act before you notice the risk.

Start With What Your Agent Can Reach

Start with the question that matters before the agent runs: what credentials are reachable from this workspace?

Before opening a project in an agentic coding tool, audit the credential surface:

  • .env files
  • shell profiles
  • local config files
  • MCP server configs
  • cloud CLI credentials
  • package manager tokens
  • old notes, scripts, and Makefiles

If the agent can read it, assume the agent can use it. The agent’s workspace should contain only credentials that are safe for the task at hand.

In practice, development credentials should be separate from production credentials, scoped to the narrowest useful action, and rotated when the work ends. If a token can delete a production database, it does not belong in a routine development environment where a coding agent is operating.

Secret scanning belongs directly in that workflow. Pre-commit hooks are especially useful for coding-agent users because they catch credentials in generated code before the agent or developer commits them. PR scanning and CI/CD scanning provide additional layers, but pre-commit is where you stop the mistake closest to the source.

GitGuardian can cover each of these surfaces, including local pre-commit scanning, repository monitoring, CI/CD exposure, MCP configuration files, and credentials surfaced in agent-generated code. Scanning is not a replacement for least privilege. It catches the moment when the agent writes, copies, or exposes something it should not.

Use Better Credential Patterns When the Agent Writes Code

There are two credential problems to watch: what the agent can already reach, and what it writes into your application.

When a coding agent generates integration code, review the authentication pattern it chooses. Agents optimize for getting the task done. They may reach for a static API key because it is easy, familiar, and present in nearby examples. That does not make it the right pattern.

Prefer this order:

1. Workload identity or managed identity. For cloud-native applications, use the platform’s native identity system wherever possible. AWS IAM roles, GCP Workload Identity Federation, and Azure Managed Identity all avoid storing long-lived static credentials in code or config.

2. OAuth with short-lived, scoped tokens. For SaaS integrations, request only the scopes the application needs and use dedicated app registrations per integration. OAuth assumes client behavior can be anticipated, but agent-written systems often compose behavior dynamically. Narrow scopes are your blast radius limiter.

3. Vault-issued dynamic credentials. For databases, internal services, and infrastructure, use a secrets manager that issues scoped, time-limited credentials at runtime. HashiCorp Vault, AWS Secrets Manager, and Azure Key Vault all support patterns that avoid hardcoding credentials into the application.

4. API keys with strict controls. Some APIs still only support API keys. In that case, use one key per service integration, store it in a vault or inject it at runtime, set the shortest reasonable lifetime, and monitor for exposure. For vault storage, rotation scheduling, and scoping patterns, API key management best practices is the reference to start with.

Hardcoded secrets are the pattern to reject: credentials embedded in source code, committed .env files, prompt templates, config files, or examples that the agent can imitate. If an agent generates code with hardcoded credentials, fix the immediate output and then check whether it learned that pattern from the existing codebase.

Also look at secret handling in logs and caches. Agents sometimes write debug statements that print retrieved secrets or cache credentials beyond their intended lifetime. The authentication pattern may be sound while the generated implementation still leaks the credential.

Securing MCP Server Connections: The New Attack Surface

Coding agents like Claude Code and Cursor increasingly use MCP (Model Context Protocol) to connect to external tools: databases, APIs, file systems, and services. Configuring MCP servers means making credential decisions that affect every tool call your agent makes.

The common mistakes are familiar: secrets stored directly in JSON or YAML config files, admin-level database access when read-only access would be enough, and shared MCP configurations reused across projects or team members. In each case, the MCP server turns a local coding assistant into an authenticated actor against an external system.

Store MCP connection credentials in a secrets manager, not in configuration files. This is the same principle behind building a secure LLM gateway with MCP: the agent should reference credentials through a controlled layer, not hold them directly. Inject values as environment variables at runtime. Scope each MCP server to the minimum required access. If the agent only needs to read from a database, configure read-only access.

MCP configs deserve the same treatment as application secrets. Exclude sensitive local configs from version control, scan repositories that contain MCP setup files, and review generated MCP configuration before accepting it. Coding agents can write these files for you, and they do not always follow the safer pattern by default.

The Developer Checklist

The practical controls are not complicated. The hard part is applying them before the agent starts acting.

Before running a coding agent in a project

  • Audit credentials in the project directory and development environment
  • Remove production credentials from routine development work
  • Scope API tokens to the minimum required operations
  • Separate development, staging, and production credentials
  • Install pre-commit secret scanning hooks

While the agent is working

  • Review generated code for hardcoded credentials
  • Require explicit confirmation before destructive operations
  • Do not paste raw credentials into prompt context
  • Watch for unexpected API calls, logs, or generated config changes
  • Treat MCP configs as sensitive files

In CI/CD and automated workflows

  • Inject secrets through CI/CD secret stores
  • Use OIDC for cloud access instead of static cloud keys where possible
  • Scan pipeline logs and artifacts
  • Apply the same review standards to agent-generated commits as human commits

After the work ends

  • Revoke task-specific tokens
  • Rotate credentials that may have been exposed
  • Remove stale MCP server entries
  • Review whether the agent’s environment still contains only what it needs

Do Not Treat Prompt Rules as Security Controls

The PocketOS incident is useful because the agent reportedly had an instruction not to run destructive commands. It ran one anyway. System prompts can still shape behavior, slow the agent down, and make safer workflows more likely. They are reminders, not authorization boundaries.

Security controls should live where the action happens. If a command can delete a production database, the API should require confirmation, the token should be scoped away from production, or the tool should force human approval before the call executes. If a database connection is only needed for inspection, the credential should be read-only. If a CI/CD job only needs to deploy one service, its identity should not be able to modify unrelated infrastructure.

Prompt rules are the last layer. They do not replace scoped tokens, environment separation, approval gates, immutable backups, or secret scanning. This distinction matters because developers often notice the model’s behavior first and the credential design second.

The safer habit is to ask: “If the agent ignores every instruction, what can it still do?”

That question turns agentic AI security back into normal security engineering: limit privileges, remove stale credentials, detect exposures early, require confirmation for irreversible actions, and keep production separate from development.

What’s Coming: Agent Security Challenges on the Horizon

Coding agents in CI/CD. As agents move from local dev tools to automated pipeline actors, the credential exposure surface grows. An agent in CI/CD may have access to pipeline secrets, deployment permissions, and repository write access.

Self-provisioned credentials. More capable agents may create API keys and service accounts when they need access to a new service. If an agent creates a root-scoped token to get something done faster, you need to know.

MCP ecosystem expansion. As the MCP ecosystem grows, developers will connect coding agents to more external services, each with its own credentials. A well-connected coding agent can accumulate a serious credential surface before anyone has named it as one.

Prompt injection as credential exfiltration. A malicious input that manipulates a coding agent into revealing, logging, or exfiltrating credentials is an active research area and an emerging attack chain. If your agent reads untrusted content, such as external documentation, third-party code, or user-provided files, and also has access to credentials, those two facts together create a risk. The best mitigation today is limiting what credentials the agent can reach, not relying on the agent to recognize manipulation.

The next serious agent incident probably will not look exotic. It will look like a token left in the wrong place.

FAQs

1) What are the biggest AI agent security risks for developers using coding agents?

The biggest risks are overprivileged credentials in development environments that coding agents can find and use autonomously. Hardcoded or unscoped API tokens, production credentials accessible during dev work, committed MCP configs, and no approval gates for destructive operations are the failure modes that cause incidents.

2) How should I authenticate my AI agent to external APIs?

When your coding agent writes code that integrates with external APIs, push it toward workload identity for cloud-native environments, OAuth with short-lived scoped tokens for SaaS integrations, or vault-issued dynamic credentials for internal services. In your dev environment, audit every credential accessible to the agent and ensure it is scoped to the minimum required operations.

3) How do I secure MCP server connections?

Store MCP connection credentials in a secrets manager and inject them as environment variables at runtime. Do not embed them in config files. Scope each MCP server to the minimum access required. If your coding agent only needs to read from a database, configure read-only access. Scan repositories containing MCP configurations for accidentally committed secrets.

4) How do I prevent my AI agent from leaking secrets?

Coding agents can surface credentials in generated code, logs, and artifacts. Use pre-commit hooks to block secrets before they enter the repository, review generated code before committing, and avoid passing raw credentials through prompt context.

5) Should I give my coding agent access to production credentials?

No. Coding agents should operate in development and staging environments with credentials that are physically incapable of affecting production. If a production incident requires debugging with an agent, make that a deliberate, audited exception, not the default state of your environment.

6) How do I handle token rotation when I’m using coding agents?

Coding agents increase the surface where credentials are accessed and potentially exposed, which makes rotation discipline more important. Automate rotation where possible, set expiration dates when creating tokens, and rotate immediately after suspected exposure.

7) What should I do when an AI coding agent causes a credential-related incident?

Revoke the credential immediately at the issuing service. Assess what the credential permitted, check audit logs for activity during the exposure window, and investigate how the credential became accessible to the agent. Then fix the control failure: scoping, environment separation, approval gates, or scanning coverage.

8) How does secret scanning help with AI agent security?

Coding agents write code, config, and scripts. Secret scanning at the pre-commit stage catches credentials in agent-generated output before they enter the repository. Repository monitoring catches historical exposure, while CI/CD scanning catches credentials in build artifacts. GitGuardian covers these surfaces from local hooks through production monitoring.

GitGuardian Interactive Demo

Xiaomi 17T ve 17T Pro’nun Türkiye fiyatları ortaya çıkmış olabilir

Xiaomi 17T ve 17T Pro

Xiaomi 17T ve 17T Pro'nun Türkiye fiyatları ortaya çıkmış olabilirVatan Bilgisayar bugün resmi olarak 28 Mayıs’ta satışa sunulacak Xiaomi 17T ve 17T Pro modelleri için erken bir listeleme gerçekleştirdi. Eğer listelenen fiyatlar doğruysa 17T modeli 12 GB RAM + 256 GB depolama özelinde 55 bin TL’ye, 17T Pro ise 12 GB RAM + 512 GB depolama özelinde 77 bin TL fiyatla pazara çıkarılabilir. Avrupa’da 750 euro fiyatla satılacağı söylenen Xiaomi 17T, 6,59 inç boyutunda 120 Hz AMOLED ekran, MediaTek Dimensity 8500 Ultra işlemci, 12 GB LPDDR5X RAM, 256/512 GB UFS 4.1 depolama, 67W şarj destekli 6.500 mAh batarya ve 32 megapiksel selfie kamerası ile geliyor. Cihazın arkasında ise 50 megapiksellik Light Fusion 800 sensörlü geniş açı, 5x optik zoom sunan 50 megapiksel telefoto ve 12 megapiksel ultra geniş açı kameralar bir araya getiriliyor. Avrupa’da 999 euro fiyatla satılacağı söylenen Xiaomi 17T Pro ise sızıntıya göre 6,83 inç boyutunda 144 Hz AMOLED ekran, MediaTek Dimensity 9500 işlemci, 12 GB LPDDR5X […]

Xiaomi 17T ve 17T Pro’nun Türkiye fiyatları ortaya çıkmış olabilir yazısı ilk olarak Teknoloji haberleri – LOG üzerinde yayınlandı.

Bilkom, dış iskelet üreticisi HyperShell’i Türkiye’ye getiriyor

Bilkom

BilkomBugün bir basın açıklaması paylaşan Bilkom, dış iskelet üreticisi HyperShell’i Türkiye’ye getireceklerini duyurdu. “İş birliği kapsamında HyperShell’in insan hareketini desteklemeye, fiziksel eforu azaltmaya ve outdoor deneyimleri güçlendirmeye odaklanan ürünleri, Bilkom güvencesiyle Türkiye pazarına sunulacak. Giyilebilir robotik teknolojileri; outdoor yaşam, kişisel mobilite, ergonomi, saha aktiviteleri ve aktif yaşam trendleriyle birlikte tüketici teknolojileri içinde yeni bir gelişim alanı oluşturuyor. Hafif, taşınabilir ve yapay zeka destekli dış iskelet sistemleri, kullanıcıların hareket kapasitesini destekleyen yeni nesil çözümler arasında öne çıkıyor. Bilkom, HyperShell iş birliğiyle bu yeni nesil kategoriyi Türkiye’de daha görünür ve erişilebilir hale getirmeyi hedefliyor.” diyen şirket, ürünlere yönelik olarak şunlara değindi: “HyperShell X Serisi; yürüyüş, doğa sporları, bisiklet, seyahat, fotoğrafçılık ve yüksek efor gerektiren saha aktiviteleri gibi farklı kullanım senaryolarına yönelik geliştirilen dış iskelet ürünlerinden oluşuyor. Seride yer alan X Go, X Pro, X Carbon ve X Ultra modelleri, kullanıcının hareketlerini gerçek zamanlı olarak algılayan AI MotionEngine teknolojisiyle insan hareketine uyum sağlayan […]

Bilkom, dış iskelet üreticisi HyperShell’i Türkiye’ye getiriyor yazısı ilk olarak Teknoloji haberleri – LOG üzerinde yayınlandı.

Single List Keyboard Handling

Prologue

A while ago, I decided to develop a fully accessible main navigation component in React and write a series of articles documenting the steps it took to create a non-trivial accessible component.

In my last article, the focus was actually on creating the components and adding a transformation utility to convert JavaScript objects into actual navigation. The base navigation component at this stage supports screen reader functionality through structured HTML and WAI-ARIA attributes, the ability to open and close a list through pointers and the Enter and Space keys.

This article, along with its accompanying release, focuses on basic keyboard handling for screen/keyboard users in a single list.

Note: This article is one of a series demonstrating how to build a React navigational component from scratch while considering accessibility through the process. The articles are accompanied by a GitHub repository with releases tied to one or more articles; each building on the previous, until a fully implemented navigation component is complete.

Each release and its associated tag contain fully runnable code for the article. The code discussed in this article is available in the release. and may be downloaded at release 0.4.0.

Examples have been updated in this release, enabling keyboard handling for a single list. Examples include a vertically aligned single list and horizontally aligned components with links and buttons for verifying operability.

While code examples are written in JavaScript for brevity, all actual code is written in Typescript and targets React 19.x. Examples use Next.js 16.x, which is not required to run the navigation component.

You can view the requirements for the Single List Keyboard Release along with previous requirements.

Follow along either by downloading the release and running the examples while examining the codebase, or by activating the link accompanying each code snippet to view the full file on GitHub.

This article is fairly long. It contains code and explanations. The code for this release is displayed, and the corresponding GitHub source is linked. Use these anchor links to move to the items of interest.

Content Links

  • Introduction
  • Acceptance Criteria
  • Holding Data in a Provider

    • NavigationListProvider
    • navigationListReducer
    • useNavigation
  • Registering a Focusable Element

    • NavigationList
    • NavigationItem
    • SubNavigation
  • Keyboard Handler

    • useNavigationList
    • NavigationItem

      • handleCommonKeyDown
    • SubNavigation
  • Summary

Introduction

This article is the first of three detailing keyboard handling in a universally accessible navigation component; It is also the simplest.

In my experience, many developers seem to expect keyboard handling to be a browser feature, and it’s been rare on the contracts I’ve worked on to see code that handles much custom keyboard input. Keyboard handling works well with native browser elements, but not as well with custom widgets, where developers need to handle code navigation requirements.

While most developers seem to understand that a keyboard is necessary for screen reader users, the fact that many people use a keyboard alongside a screen to navigate isn’t always obvious. Users of screen readers have a variety of key combinations they may use to navigate through structures such as headings, links, form elements and tables. Users who navigate the screen with a pointer can simply move their cursor to a specific element and click. Unfortunately, the keyboard flexibility is limited for screen/keyboard users, who are the only ones who must navigate a page linearly. Navigation is not as easy for someone who can see a screen and depends on a keyboard for both input and navigation.

Those who use a screen and keyboard have expectations that developers should not only be aware of, but should strive to match. For those developers who work with a screen, testing how focus moves within a component is actually easy; just use the keyboard. Developers should always ensure a component is fully navigable with the Tab/Shift+Tab key combinations, which are required for both screen and screen reader users, and that any custom keyboard handling for screen users is implemented and works correctly.

To do so, developers need to receive acceptance criteria that detail what happens when a key is used.

When developers don’t receive information about keyboard handling requirements when implementing a custom widget, efforts to bring the code into compliance with accessibility standards can run into snags. Keyboard handling can be compromised, and what actually gets implemented might be more focused on the letter of the law than the spirit, as is demonstrated by the following video.

Since the focus of this navigation component is accessibility, the acceptance criteria must specify what happens on each key press.

Return to Content Links

Acceptance Criteria

Single List Keyboard Handling

  • AC 1 – Pressing the HOME Key should take a user to the first item in the current List.
  • AC 2 – Pressing the END Key should take a user to the last item in the current list.
  • AC 3 – Pressing the LEFT-ARROW key should take a user to the previous item in the current list.
  • AC 4 – If focus is already on the first item in the current list, pressing the LEFT-ARROW key should take the user to the last item in the current list.
  • AC 5 – Pressing the RIGHT-ARROW Key should take a user to the next item in the current list.
  • AC 6 – If focus is already on the last item in the current list, pressing the RIGHT-ARROW Key should take a user to the first item in the current list.

The keyboard support section in the Disclosure Navigation pattern in the APG requires interpretation. The guide references moving buttons to buttons and links to links. Both are focusable elements, and depending on where each lies, navigation can move from a button to a link, or from a link to a button, within a single list.

Hand-eye coordination is key in this instance. We expect the cursor to move in the direction indicated by the arrow keys. When the cursor moves to an unexpected location, it’s jarring; if it disappears entirely, the site can appear broken.

Return to Content Links

Holding Data in a Provider

Navigation in a sublist requires a focusable element, in this case either a button or a link, to be able to determine its sibling in a list and move according to the acceptance criteria.

Each link and button in a list is rendered in its own component, with no real way to know about, much less access, the others.

Data for each focusable item in a particular list can be stored in a context provider, along with functions to register and retrieve the collective data. Since each focusable element is part of a list, the best data structure to hold the information is an array.

NavigationListProvider

Context providers hold data along with functions for retrieving and setting it. Each list works with its own copy of the provider, and the data in its array consists of each individual link or button element within the list items it contains. Each focusable element, whether a button or a link, can only focus on siblings contained in the list it resides in.

export function NavigationListProvider({ children }) {
  const [state, dispatch] = useReducer(navigationListReducer, {
    items: [],
  });

  const getCurrentListItems = useCallback(() => {
      return state.items;
    }, [state.items]);

  const registerItemInCurrentList =  useCallback((focusableEl) => {
      dispatch({ type: "REGISTER_ITEM", item: focusableEl });
    }, []);

  return (
    <NavigationListContext.Provider
      value={{
        getCurrentListItems,
        registerItemInCurrentList,
      }}
    >
      {children}
    </NavigationListContext.Provider>
  );
}
NavigationListProvider.context = NavigationListContext;

GitHub (release 0.4.0) – NavigationListProvider.tsx

Given the nature of the data, useReducer is a better solution than useState. A reducer still uses the state object but can manage more complex logic. Since state updates to the NavigationListProvider affect multiple components and changes might depend on others, it makes sense to use the provided reducer hook rather than the state hook.

navigationListReducer

export function navigationListReducer(
  state,
  action,
) {
  switch (action.type) {
    case "REGISTER_ITEM": {
      if (state.items.includes(action.item)) return state;
      return { ...state, items: [...state.items, action.item] };
    }
    default: {
      return state;
    }
  }
}

GitHub (release 0.4.0) – navigationListReducer.ts

Like most reducers, actions are held in a switch, even though there is only one action type, REGISTER_ITEM. When called, a focusable element (action.item) is passed through and checked to determine if it already exists in the array. If not, it is added in.

A context provider is not exposed to public components; instead, a hook is used to execute functionality that can be passed through the registration function and to add additional functionality when necessary.

useNavigationList

export function useNavigationList() {
  const navigationListContextObj = use(NavigationListContext);
  const { registerItemInCurrentList } =
    returnTrueElementOrUndefined(
      !!navigationListContextObj,
      navigationListContextObj,
    );

  return {
    registerItemInCurrentList,
  };
}

A common pattern for a hook associated with a context provider is to load the provider’s public functions and either use them in the hook or pass them through to another component. For the moment, the registration function is just passed through, so it may be imported into the navigation components.

Return to Content Links

Registering a Focusable Element

In order for the array to be used with keyboard handling, the focusable elements must be registered (added) into the data array. The first step is to wrap each list within its own context provider.

NavigationList

export default function NavigationList({...) {
  const listProps= {...};

  return (
    <NavigationListProvider>
      <List key={`list-$id`} {...listProps}>
        {children}
      </List>
    </NavigationListProvider>
  );
}

GitHub (release 0.4.0) – NavigationList.tsx

With the NavigationListProvider now wrapping the List component, each list item can access any other list item stored in its copy of the data array. It’s important to understand that each list maintains its own array of items and cannot access items across lists.

NavigationItem

export default function NavigationItem({...}) {
  const {
    registerItemInCurrentList,
  } = useNavigationList();

  const currentPath = ...;

  const linkRef = useRef(null);

  useEffect(() => {
    if (linkRef.current !== null) {
      registerItemInCurrentList(linkRef.current);
    }
  }, [ linkRef, registerItemInCurrentList]);


  const listItemProps = { ... };

  const linkProps = {
    ... ,
    ref: linkRef,
    ...rest,
  };

  return ( ... );
}

GitHub (release 0.4.0) – NavigationItem.tsx

Code that has already been discussed in previous releases is represented by ellipses; only new code is given.

Focusable elements are stored in ref objects, but reading the element through ref.current can lead to unreliable code during renders. Since the elements held in the ref object are just pointers to the DOM elements, it’s safe to extract them and store them separately as read-only.

References to elements are not populated right away; the focusable element, in this case a link, needs to be rendered before the information is available, so the useEffect() that registers the link into the currentlistitems array only runs when the ref. current is not null.

SubNavigation

export default function SubNavigation({...}) {
  const {
    registerItemInCurrentList,
  } = useNavigationList();

  const buttonRef = useRef(null);

  const [isSubListOpen, setIsSubListOpen] = useState(false);

  useEffect(() => {
    if (buttonRef.current !== null) {
        registerItemInCurrentList(buttonRef.current);
    }
  }, [buttonRef, registerItemInCurrentList]);

  const handlePress = () => {
    setIsSubListOpen(!isSubListOpen);
  };
    ...
    ref: buttonRef,
  };
  ...
}

GitHub (release 0.4.0) – SubNavigation.tsx

The code to register a button is almost identical to the code registering a link. The only difference is that the reference being passed is a button element.

Return to Content Links

Keyboard Handler

With the data structure set up and items registered, it’s finally time to shift the focus to handling the appropriate keys, and attention turns back to the acceptance criteria.

  • AC 1 – Pressing the HOME Key should take a user to the first item in the current List.
  • AC 2 – Pressing the END Key should take a user to the last item in the current list.
  • AC 3 – Pressing the LEFT-ARROW key should take a user to the previous item in the current list.
  • AC 4 – If focus is already on the first item in the current list, pressing the LEFT-ARROW key should take the user to the last item in the current list.
  • AC 5 – Pressing the RIGHT-ARROW Key should take a user to the next item in the current list.
  • AC 6 – If focus is already on the last item in the current list, pressing the RIGHT-ARROW Key should take a user to the first item in the current list.

The only keys being handled now are home, end, and the left and right arrows. If the focus is on the first element in the list and the left arrow key is pressed, then focus should jump to the last element in the list, and the opposite should happen if the focus is on the last element and the right key is pressed. Focus should move to the first element.

useNavigationList

Since the functionality needs to access data stored in the context provider, the functions are created in the hook.

 export function useNavigationList() {
  const navigationListContextObj = use(NavigationListContext);
  const { getCurrentListItems, registerItemInCurrentList } =
    returnTrueElementOrUndefined(
      !!navigationListContextObj,
      navigationListContextObj,
    );

  const currentListItems = getCurrentListItems();

  const _getCurrentIndex = useCallback(
      (currentlyFocusedEl) => {
        return currentListItems.indexOf(currentlyFocusedEl);
      },
      [currentListItems],
    );

    const shiftFocus= ( focusableEl) => {
      focusableEl.focus({ preventScroll: true });
    };

    const setFirstFocus = () => {
      shiftFocus(currentListItems[0]);
    };

    const setLastFocus = () => {
      shiftFocus(currentListItems[currentListItems.length - 1]);
    };

    const setNextFocus = ( currentlyFocusedEl) => {
      const newIndex = _getCurrentIndex(currentlyFocusedEl) + 1;
      if (newIndex >= currentListItems.length) {
        setFirstFocus();
      } else {
        shiftFocus(currentListItems[newIndex]);
      }
    };

    const setPreviousFocus = ( currentlyFocusedEl) => {
      const newIndex = _getCurrentIndex(currentlyFocusedEl) - 1;
      if (newIndex < 0) {
        setLastFocus();
      } else {
        shiftFocus(currentListItems[newIndex]);
      }
    };

    return {
      registerItemInCurrentList,
      setFirstFocus,
      setLastFocus,
      setNextFocus,
      setPreviousFocus,
      shiftFocus,
    };
} 

GitHub (release 0.4.0) – useNavigationList.tsx

A reminder that the code discussed earlier is represented by ellipses; only the new code is shown.

It’s useful to know when a private or public function is used, and I do so by prefacing private functions with an underscore.

To provide a fresh copy of the data to the hook, don’t call the data directly; it won’t refresh. Instead, a getter is retrieved from the context provider, getCurrentListItems(). You’ll note an alias for currentListItems that calls the getter each time. When used this way, the code always returns an updated copy of the array, making it more natural to work with.

A custom function, shiftFocus(), is used instead of implementing focus within each publicly called function to standardize how scrolling is handled. In these cases, scrolling should be prevented when navigation is displayed in a horizontal layout to prevent extraneous shifts when sublists open and close.

The rest of the code is self-explanatory; focus is shifted depending on the key pressed: Home and End, sends focus to the first or last children in the list, while the right or left arrow key sets focus depending on where the currently focused element is; If the focus is at the end of the list when setNextFocus is called, focus then moves to the first element and if the focus is at the beginning of the list when setPreviousFocus is called, focus moves to the end. Otherwise, focus shifts to the respective sibling on either side of the current element.

With the focus functions created, it’s time to use them.

NavigationItem

export default function NavigationItem({ ... }) {
  const {
    registerItemInCurrentList,
    setFirstFocus,
    setLastFocus,
    setNextFocus,
    setPreviousFocus,
  } = useNavigationList();
  const currentPath = ...;
  …

 const handleKeyDown = (e) => {
      const linkEl = linkRef.current;

      switch (e.key) {
        case Keys.HOME:
        case Keys.END:
        case Keys.LEFT:
        case Keys.RIGHT:
          e.preventDefault();
          e.stopPropagation();
          break;
      }

      handleCommonKeyDown(
        e,
        linkEl,
        setFirstFocus,
        setLastFocus,
        setNextFocus,
        setPreviousFocus,
      );
    };
  …

  const linkProps = {
    ...
    onKeyDown: handleKeyDown,
    ref: linkRef,
    ...rest,
  };

  return (..);
}

The setters from the hook are retrieved, and a handleKeyboard function is created. Rather than setting preventDefault and stopPropagation in each case statement, I use a switch that sets them on all the keys at once. And because both links and buttons handle these keys in the same way, a common keyboard handler is created and called rather than duplicating the code across components.

When calling a function outside the render, everything necessary must be passed in, including all the hook calls.

handleCommonKeyDown

export const handleCommonKeyDown = (
  e,
  currentlyFocusedEl,
  setFirstFocus,
  setLastFocus,
  setNextFocus,
  setPreviousFocus
) => {
  switch (e.key) {
    case Keys.HOME:
      setFirstFocus();
      break;
    case Keys.END:
      setLastFocus();
      break;
    case Keys.LEFT:
      setPreviousFocus(currentlyFocusedEl);
      break;
    case Keys.RIGHT:
      setNextFocus(currentlyFocusedEl);
      break;
  }
};

GitHub (release 0.4.0) – handleCommonKeyDown.tsx

The common key handler is quite straightforward; each specific key triggers a function in the hook to decide the next item to shift to.

SubNavigation

export function SubNavigation({...}) {
    const {
        currentListItems,
        parentRef,
        registerListItem,
        setFirstFocus,
        setLastFocus,
        setNextFocus,
        setPreviousFocus
    } = useNavigationList();
   const {
        registerListItem, 
        setFirstFocus, 
        setLastFocus, 
        setNextFocus, 
        setPreviousFocus} = useNavigationList();

   const buttonRef = useRef(null);
    ...

  useEffect(() => {
    const currentButtonEl = buttonRef.current;
    if (currentButtonEl !== null) {
       registerItemInCurrentList(currentButtonEl);
    }
  } , [buttonEl, buttonRef, isSubListOpen, registerItemInCurrentList]);

    const handleKeyDown = (e) => {
        const buttonEl = buttonRef.current;

        switch (e.key) {
            case Keys.HOME:
            case Keys.END:
            case Keys.LEFT:
            case Keys.RIGHT:
                e.preventDefault();
                break;
        }

        handleCommonKeyDown(
          e, 
          buttonEl, 
          setFirstFocus, 
          setLastFocus, 
          setNextFocus, 
          setPreviousFocus
       );

    ...

    const buttonProps: ButtonProps = {
        ...
        onKeyDown: handleKeyDown,
        onPress: handlePress,
        ref: buttonRef,
        ...
    };

    ...
    return ( ...)
}

GitHub (release 0.4.0) – SubNavigation.tsx

Notice how stopPropagation() is not included in the top switch. This is because the button component I use from react-aria-components already calls stopPropagation() itself, so I don’t need to set it. This may differ from the button component you are working with. Otherwise, the code for SubNavigation is similar to that already seen in NavigationItem.

Return to Content Links

Summary

Handling link references to multiple components becomes straightforward when a provider holds the data and the functions that call and manipulate it. A hook passes through necessary provider functions as well as its own to provide keyboard handling within a single list.

With all the code added to support single-list keyboard handling, the question arises: Does it work?

Part of the issue with demonstrating keyboard handling is the inability to show which key is being used as focus moves. It’s one of the reasons keyboard accessibility is so hard to demonstrate during sprint demos. I’ll be providing videos I make that detail what I am doing and which keys I’m pressing as I guide you through the enhancements.

I’ll be back with another article soon, focusing on CSS design and applying a layout to the default horizontal navigation.

9 SaaS development companies worth knowing (a technical look)

Most agency roundups are written for product managers and founders. This one isn’t.

If you’re a CTO, lead engineer, or the person who’ll actually own the codebase after the agency hands it off, you care about different things: what stack they default to, whether they write tests, how the CI/CD is set up on day one, and who’s actually on the team. Not logo counts.

Here’s the same list, filtered for what engineers want to know.

1. Brocoders

Stack: React, Node.js, Python/Django, PostgreSQL, AWS/GCP

The default setup is a React frontend against a Node.js API layer, Postgres for the data store, and AWS for infra. They use GitHub Copilot and similar tools in their engineering workflow, which shows up in hour estimates, and they publish production-ready SaaS boilerplates at bcboilerplates.com covering auth, user management, billing, and admin patterns.

For multi-tenant SaaS, Brocoders go schema-per-tenant on Postgres (row-level security where performance allows) with per-tenant rate limiting at the API layer. GraphQL is available as an API layer option, though REST is the default.

CI/CD is set up as a line item in discovery, not an afterthought. Typical pipeline: GitHub Actions, containerized builds, staging and prod environments separated from day one.

Team composition: cross-functional from the start, product strategist included in early sprints. Engineers stay on the account; there’s no discovery team that hands off to a separate build team.

Clutch: 5.0 across 38 reviews, which is statistically unusual. Read the actual reviews, not just the score.

2. Netguru

Stack: React, React Native, Ruby on Rails, Node.js, AWS

Primarily a Rails and React shop with a strong design practice. Good choice if your MVP needs polished UX before your Series A. Less obvious choice if your architecture needs to be GraphQL-native or if you’re building something data-heavy.

Their engineering process is Jira + Figma + Slack, two-week sprints, and a dedicated PM. Code quality reviews come up consistently in client feedback.

Best technical fit: design-led consumer SaaS, early-stage fintech, mobile-first products.

3. Upsilon

Stack: Cloud-native SaaS, AWS-first

Lean team (10-49 engineers), US-headquartered. Built 25+ SaaS MVPs. Their model is speed to functional prototype, so they’re well-matched for founders who need working software in under 3 months to validate with real users.

Less established on enterprise compliance. If you need SOC 2 controls baked in from sprint one, ask explicitly.

4. Intellectsoft

Stack: React, Node.js, .NET, AWS, blockchain where relevant

The compliance-first option. Their work is in regulated industries: healthcare, fintech, legal. They run strong test coverage and have documented QA processes. On-time record is solid. Not for sub-$50K engagements.

If you’re building something that needs HIPAA controls or a financial audit trail, they’re worth a serious look. Ask about how they handle secrets management and access control audits in the discovery phase.

5. ScienceSoft

Stack: .NET, Java, React, Azure/AWS, Salesforce, ServiceNow

30+ years old, which means they’ve seen things go wrong at scale. The $5K minimum is genuinely rare for the quality tier they operate at. Their breadth (cybersecurity, SharePoint, mobile, healthcare IT) is both a strength and a risk: you want to know which vertical your project lands in and who specifically is assigned.

Incident response under 24 hours is documented across multiple reviews. That’s the number that matters at 2am.

6. Railsware

Stack: Ruby on Rails, React

The expensive option ($100-$149/hr) and proud of it. Portfolio includes GitLab, Calendly, and Buffer. Their engineers challenge assumptions in discovery, which you want from a partner who’ll be responsible for architecture decisions.

If you’re building Rails-native B2B SaaS and want minimal technical debt, they’re genuinely competitive at that. If you’re expecting microservices or a Go/Rust backend, they’re probably not the fit.

7. Simform

Stack: AWS, DevOps-first, IaC heavy

Cloud-native engineering with strong DevOps automation. Good if your architecture needs serious IaC (Terraform, CDK) from the start and you want blue/green deployments as a standard, not a nice-to-have.

The AI engineering story is less clear. Before scoping, ask for concrete examples of MLOps pipelines, not just “we support AI features.”

8. Intellias

Stack: AWS/GCP, microservices, data platforms, AI/ML integrations

1,000-9,999 engineers, enterprise contracts, multiple scrum teams in parallel. If you’re migrating a monolith to microservices or need 5 teams running concurrently, they have the depth to do that. If you’re a 3-person startup, you’ll likely get junior staffing.

Notable on production reliability: near-zero incident rate comes up in reviews. Jira-based project management, Clutch 4.9.

9. ELEKS

Stack: ML/BI integration, data engineering, standard web SaaS

2,100+ engineers, founded 1991. If your SaaS is data-heavy and you need ML features (churn prediction, demand forecasting, anomaly detection) treated as first-class concerns with proper MLOps, ELEKS has the data engineering depth for that. Ask for case studies with specific metric lifts, not just “we used ML.”

What to check before you sign

A few things that matter more than stack preferences:

CI/CD on day one. Ask if pipeline setup is a line item in the discovery phase or something bolted on later. Agencies that treat it as optional tend to treat monitoring as optional too.

Who’s actually on the account. Get names and LinkedIn profiles of the engineers who’ll work on your project. Ask if they stay for the duration or rotate off. The engineer who did discovery should be in the first sprint.

Hour estimates and tooling disclosure. Ask directly: “Do your engineers use AI coding assistants? Which ones? How does that affect your estimates?” A vendor using GitHub Copilot or Cursor should be estimating 30-50% fewer hours for standard modules. If they’re not, you’re paying for reinvented wheels.

Multi-tenant architecture decision. If you’re building SaaS with multiple customers on shared infrastructure, ask how they handle tenant isolation. Schema-per-tenant vs. row-level security have very different performance profiles at scale. Get an opinion in discovery, not post-launch.

Post-launch on-call. Ask who’s on call after go-live and what the SLA is for critical bugs. “We’ll respond quickly” is not an SLA.

Material Nova — The Best VS Code Theme of 2026


🎨 Material Nova — The Best VS Code Theme of 2026

“Your editor is where you spend 8+ hours a day. It deserves to be beautiful.”

If you’ve been jumping between One Dark Pro, Dracula, Tokyo Night, and Ayu trying to find the one — your search is over.

Material Nova is here. And it’s not just another color scheme — it’s a premium, meticulously engineered coding workspace built on Google’s legendary Material Design palette.

🤔 Why Another VS Code Theme?

Fair question. The marketplace has hundreds of themes. So what makes Material Nova different?

Most themes are ports — someone grabs a popular palette, slaps it into a JSON file, and ships it. Material Nova was built differently:

  • ✅ Deeply optimized semantic highlighting for JS, TS, React (TSX/JSX), Python, C#, HTML/CSS, and JSON
  • ✅ WCAG-compliant contrast ratios to reduce eye strain during late-night sessions
  • ✅ 15 distinct variants for every mood, lighting condition, and aesthetic preference
  • ✅ High Contrast editions for every dark variant
  • ✅ Zero performance impact — pure hand-crafted JSON, no background scripts

Material Nova v2.1.0 just dropped with two brand-new variants — Nebula and Sakura. Read on for the full breakdown.

🎭 15 Variants — One for Every Mood

This is where Material Nova truly shines. Whether you’re coding at 2am or pair-programming in a sunny office, there’s a variant made for you.

🌑 Dark Variants

Variant Background Vibe
Material Nova Default #263238 The classic Google Material experience
Material Nova Darker #212121 Deep matte gray for ultimate night coding
Material Nova Palenight #292D3E Vibrant purple-blue synthwave aesthetic
Material Nova Ocean #0F111A Calming deep-sea navy layout
Material Nova Deepforest #141F1D Organic dark forest green comfort
Material Nova Sakura 🌸 #1D1921 Premium cherry blossom-inspired rose charcoal
Material Nova Nebula 🌌 #12101E Celestial deep space galactic aesthetic

💡 Light Variant

Variant Background Vibe
Material Nova Lighter #FAFAFA Perfect for bright daylight or outdoor offices

⚡ High Contrast Editions

Every dark variant ships with a High Contrast (HC) sister edition for developers who prefer sharp borders and maximum visibility — including a true OLED pitch-black option with #121212 and #09080F backgrounds.

🌌 What’s New in v2.1.0

The latest release is the biggest update yet:

Introducing Material Nova Nebula

A stunning galactic-inspired dark theme with deep space aesthetics. Background #12101E, foreground #E1DFEE — feels like coding among the stars. The HC variant pushes to OLED black at #09080F.

Introducing Material Nova Sakura 🌸

The most-requested theme from the community. A soft rose-charcoal layout inspired by cherry blossoms — background #1D1921, foreground #E3D6DF. Elegant, warm, and unlike anything else on the marketplace.

Automated Theme Compilation

Palettes are now compiled using standard-version automation — ensuring consistency across all 15 variants with zero runtime overhead.

⚡ Install in 60 Seconds

# Option 1: From VS Code Command Palette
1. Open Extensions panel → Ctrl+Shift+X (or Cmd+Shift+X)
2. Search: Material Nova
3. Click Install
4. Press Ctrl+K → Ctrl+T to open theme picker
5. Select your variant. Done. ✅

# Option 2: Via CLI
code --install-extension dhavalkurkutiya.vsc-material-nova

⚙️ Recommended Settings

Get the absolute best experience with these settings.json tweaks:

{
  "editor.fontFamily": "JetBrains Mono, Fira Code, monospace",
  "editor.fontSize": 14,
  "editor.lineHeight": 1.6,
  "editor.letterSpacing": 0.5,
  "editor.fontLigatures": true,
  "editor.cursorBlinking": "smooth",
  "editor.cursorSmoothCaretAnimation": "on"
}

Font tip: Pair Material Nova with JetBrains Mono for the sharpest ligature rendering. It’s free and the difference is night and day.

🆚 How It Compares

Feature Material Nova One Dark Pro Dracula Tokyo Night
Variants 15 4 3 6
High Contrast editions ✅ All variants ❌ ❌ Partial
Semantic highlighting ✅ Deep Partial Partial Partial
WCAG contrast compliance ✅ ❌ ❌ ❌
OLED black support ✅ ❌ ❌ ❌
Background scripts Zero None None None

🏁 Final Verdict

If you care about your editor environment — and you should — Material Nova is the most complete VS Code theme available right now.

15 variants. Semantic highlighting. WCAG-compliant contrast. Zero performance cost. And it’s completely free.

Stop settling for a theme that’s “good enough.” Your 8-hour-a-day workspace deserves better.

→ Install Material Nova on VS Code Marketplace

👨‍💻 About the Author

Material Nova is crafted with passion by Dhaval Kurkutiya.

Licensed under MIT — free to use, customize, and enjoy. Made with ❤️ by Dhaval Kurkutiya.