
この記事は、「NEWT Product Advent Calendar 2025」Day10の記事となります。
「NEWT Product Advent Calendar 2025」10日目は、令和トラベル シニアエンジニアのrodrigoが、アプリエンジニア hossyからバトンをもらい執筆。ぜひ、最後までご覧ください!
(※ この記事は英語にて執筆いたします。)
🧑💻 Introduction
Hello! My name is Rodrigo Ramirez; A Senior Engineer at ReiwaTravel.
I was in charge of selecting the tech stack and building the NEWT backend and website from scratch.
This blog is a written version of a talk I recently gave —
How our TypeScript backend evolved as we scaled in products, teams, and AI-generated code.
The pace of software development is accelerating, and AI is changing not only how we write code, but how we design systems. Our backend needs to evolve to support this new reality.
🕰️ How Our Backend Journey Began
Back in 2021, we started with a modular monolithic architecture. This means one codebase with separate modules, but everything deployed together.

This structure worked very well at the beginning:
- We were a small team.
- Our priority was speed.
- Engineers could code in their own style. Speed was more important than consistency
But… time passed.
NEWT grew from one product to multiple products
and from one backend team to several backend teams working in parallel.
A fragmented backend slows us down. Small changes become risky and expensive. We need a codebase where changes are safe and predictable.
🤖 The AI Era Arrived
In the last year, AI code assistants became part of our daily workflow.
Inside ReiwaTravel we measure how much code is assisted by AI, and today:
- Our company-wide average is ~50% AI-generated code.
- Some teams reach up to 90% AI-assisted generation.
This is great for speed…but it creates a new challenge:
AI writes code very fast—too fast for humans to review everything
We needed a backend architecture where:
- Code can be generated safely.
- Quality can be validated automatically.
- Humans spend time on architecture, not syntax.
This pushed us to rethink everything.
AI works best with clear, consistent patterns. When the code structure is clear, AI generates better code.
How can we move even faster and still keep quality in this new AI Era?
AI works great for new projects and prototypes. But what about production codebases with complex business logic? How can we use AI safely without checking every single line?
Let me introduce some of the approaches we are trying:
🏗️ From Modular Monolith → TypeScript Monorepo
Even though we started with a modular monolith, as the product grew, we hit limitations:
- All products lived in one codebase.
- No clear separation between product boundaries.
- Modules could call each other freely.
- One big deployment for everything.
- When AI generates code, it copied these unclear patterns—making the problem worse, faster.

We needed stronger boundaries.
So we migrated to a TypeScript Monorepo:
Benefits:
- Each product = its own deployable app.
- Shared logic lives in
/packages.
- Clear import rules prevent unwanted coupling.
- AI can see the entire system structure (API, UI, packages, etc.)
- Code generation becomes predictable.

🧱 Clean Architecture: Working Layer by Layer
Inside each app/package we follow Clean Architecture with four clear layers:
- Domain → pure business logic
- Application → use cases
- Infrastructure → DB, APIs, external services
- Presentation → GraphQL/HTTP entrypoints

We also use facades to enforce boundaries:
export interface BookingFacade { create(input: CreateBookingInput): Promise<Booking>; getById(id: BookingId): Promise<Booking | null>; }
AI knows:
- Where each file belongs
- Which layer to write
- How layers connect
This allows AI to work layer by layer, just like we do. Each layer has one clear purpose, so AI knows exactly where to put new code
Separating layers prevents side-effects. Changes in one layer don't break other layers. This is important when AI generates code quickly
📜 Contracts as Code
Contracts define the shape of the system.
When contracts are clear and strong:
- Humans know what to build
- AI knows how to implement it
As result Implementation becomes predictable—perfect for AI code generation.
1) TypeScript Types
These model our domain:
export type UserId = string; export enum UserStatus { ACTIVE = 'ACTIVE', SUSPENDED = 'SUSPENDED', } export type User = { id: UserId; firstName: string; lastName: string; email: string; status: UserStatus; };
AI generates services, resolvers, and tests based on these shapes.
2) Facades
Each module/context has one entry point—a facade.
Facades control how modules communicate with each other.
export interface UserFacade { getById(id: UserId): Promise<User | null>; create(input: CreateUserInput): Promise<User>; updateStatus(input: UpdateStatusInput): Promise<User>; }
Why facades matter:
- Prevents tight coupling: Modules only talk through facades. They don't know about each other's internal code.
- Clear boundaries: Each module decides what to expose. Internal changes don't break other modules.
3) GraphQL Schema
Schema-first, type-safe:
type User { id: ID! name: String! status: UserStatus! ... } type Query { userById(id: ID!): User } type Mutation { createUser(input: CreateUserInput!): User! updateUserStatus(input: UpdateUserStatusInput!): User! }
4) Prisma Schema
Database schema → typed client:
enum UserStatus { ACTIVE SUSPENDED } model User { id String @id @default(cuid()) firstName String lastName String email String @unique status UserStatus @default(ACTIVE) createdAt DateTime @default(now()) }
5) Zod Validation
Runtime validation with automatic TypeScript types:
import { z } from 'zod'; export const CreateUserInputSchema = z.object({ name: z.string().min(1), email: z.string().email(), }); export type CreateUserInput = z.infer<typeof CreateUserInputSchema>;
Why Zod:
- Validates inputs at runtime: Catches errors that TypeScript cannot catch at compile time
- Generates types automatically: One schema creates both validation and types
- Easy to use: Simple, readable syntax
🧪 Validation & Testing
Contracts give us shape.
Architecture gives us structure.
Testing gives us trust.
We validate that generated code really works as expected.
Layer-by-Layer Testing Strategy
- Domain: Pure business logic
- Application: Use-case integration
- Presentation: GraphQL input/output E2E tests
Each layer defines what to mock and what to test. This keeps tests simple and focused.
How AI uses this:
AI code agents generate code layer by layer. After each layer, they run tests to verify everything works before moving to the next layer.
TypeScript Safety Checks
When AI generates code, it can see build errors or linter warnings immediately. AI fixes these errors automatically, so problems are caught early.
AI Code Review
We use Claude Code and sub-agents to review the final code.
After all code is generated, AI agents verify:
- Architecture rules are followed
- Import boundaries are respected
- The original plan was implemented correctly
- Test coverage, etc
Humans only review design and intent, not every line of code.
🚀 Results & Impact
We're still in progress — but the direction is clear.
- TypeScript is now the foundation of all backend and frontend systems.
- Parts of NEWT already follow the new architecture; others are being migrated.
- Our goal is a fully aligned monorepo that AI can understand end-to-end.
- On average, ~50% of our code is AI-generated, with some teams reaching 90% AI-assisted.
The combination of TypeScript + Architecture + Contracts is already improving:
- Speed
- Quality
- Consistency
- Developer focus
This isn’t about rewriting everything. Evolution is safer than revolution. We keep what works and slowly change what doesn't. Step by step, the system becomes more predictable.
🧠 The Human Role in the AI Era
The real change is cultural.
Engineers are shifting from writing code to designing architecture, rules, and requirements.
As AI handles more of the implementation, software development becomes more abstract.
Instead of focusing on every line of code, engineers will focus on defining what the system should do and why. AI handles the details; we focus on design, clarity, and good decisions.
When AI-generated code fails, we don’t patch it manually.
We improve the rule, the contract, or the schema — and generate again.
This creates a self-improving loop:

🎯 Conclusion
The next generation of developers will be architects, not coders.
We are moving toward a future where software is built very differently from how we build it today. AI-first workflows will become the norm, and new companies will adopt them from day one. Their products will evolve faster, with less friction, and with far fewer limitations than traditional codebases.
To stay competitive, we must evolve too.
Our backend must be ready for this future. Engineers focus on design and decisions. AI handles the implementation. This shift is already happening across the industry. Teams who adapt early will move faster and build better products.
We’re excited to keep evolving NEWT’s backend and to continue building the future of AI-driven development at Reiwa Travel.
📣 『NEWT Tech Talk』のお知らせ
令和トラベルでは、毎月技術的な知識や知見・成果を共有するLT会を毎月実施しています。発表テーマや令和トラベルに興味をお持ちいただいた方は、誰でも気軽に参加いただけます。
2026年第一弾のイベントも鋭意企画中ですので、令和トラベルのconnpassページにて、チェックしてみてください!
【NEWT Chat リリース記念】AI × Travel Innovation Week 開催!
「NEWT Chat」誕生の裏側や開発ストーリーをお届けする特別企画 “AI × Travel Innovation Week” を令和トラベルのnote上で開催しました!
「NEWT Chat」のリリース背景、プロダクトの価値、開発体制、そして今後の展望など、新規事業の “舞台裏” を公開。特に、AIプロダクト開発に関わるエンジニア・PMの皆さまにとって学びの多い内容となりますので、ぜひご覧ください。
▼ AI × Travel Innovation Week のnoteはこちら:
旅行・観光業に特化したAIエージェントチャット「NEWT Chat(ニュートチャット)」についてはこちらから。
1年間の感謝を込めた、”クリスマスセール🎄” 開催中!
NEWTでは現在、海外旅行やホテルをおトクにご予約いただける『クリスマスセール🎄』を12/4〜スタートしています!ぜひこの機会にご利用ください!
令和トラベルでは一緒に働く仲間を募集しています
この記事を読んで会社やプロダクトについて興味を持ってくれた方は、ぜひご連絡お待ちしています!お気軽にお問い合わせください!
フランクに話だけでも聞きたいという方は、カジュアル面談も実施できますので、お気軽にお声がけください。
📣宣伝
次回の「NEWT Product Advent Calendar 2025」Day11は、「生成AIを使ってGoogleフォーム×Slackツールの自動リマインドツールを作った話」と題してAX室のyasuが担当します。次のブログもお楽しみに!





