DEV Community

Jorge Gomez
Jorge Gomez

Posted on

🚀 How I Used AI, FRDs, Claude Sonnet, Windsurf, and Antigravity to Orchestrate a Complete Backend Without Chaos

A Reproducible Methodology for Generating Real, Clean, and Scalable Software Using LLM Agents Orchestrated Through Formal FRD Documents

Introduction

Over the past few weeks, I’ve been applying a development approach based on FRDs (Functional Requirements Documents) orchestrated with the support of Artificial Intelligence to build modern, clean, and scalable backends. This method allowed me to generate a complete backend—from CRUD, database layer, JWT authentication, migrations, and unit testing—without chaos, without improvisation, and with clean code from the very first commit.

Although FRDs are a traditional standard widely used in software engineering, what’s truly interesting here is not the FRD concept itself, but how FRDs are combined with LLM agents to create a deterministic build process.

This approach aligns with modern techniques such as LLM Orchestration, Task Graphs, and Agentic Pipelines, which are becoming mainstream in tools like Windsurf, Cursor, Claude Sonnet, and VSCode Agents.

One key insight I found early on was that I initially started with a massive FRD—a single document describing all phases (boilerplate, database, authentication, testing, etc.). Even though the document was detailed, two real problems quickly emerged:

  1. LLMs had to process too much information in a single context window, increasing reasoning load and causing the agent to drift, forget steps, or ask redundant questions.
  2. The process became slow because the model entered loops of “confirmation,” uncertainty, ambiguity, and frequent re-validation.

This led me to investigate a more scalable approach: splitting the project into multiple small FRDs, each responsible for a specific phase, and introducing a Master FRD-00 responsible for orchestrating them in the correct order.

With this structure:

  • The LLM no longer needs to parse a giant document
  • Each stage has a short, precise FRD
  • The Master FRD controls the entire execution pipeline
  • The agent stops asking “what’s next” and simply executes
  • Adding new features becomes safer and easier because each one lives in its own FRD without interfering with others

What Is FRD-Based Orchestration?

FRDs define:

  • What needs to be built
  • In what order
  • What criteria must be satisfied
  • Which steps are mandatory
  • What behaviors the AI must validate
  • What acceptance conditions each phase must pass

The key insight is that you’re not only describing features, you’re also defining the construction process itself, ensuring accuracy, repeatability, and zero improvisation.


📘 Connection to Existing Practices

FRD-based orchestration does not try to reinvent methodologies—it integrates formal, well-known practices with the new wave of AI-assisted development.

This method incorporates ideas from:

  • LLM-driven Development Workflows
  • Prompt Chaining
  • Task Graph Execution
  • Reproducible Pipelines
  • Specification-Driven Engineering

The contribution here lies in how the process is structured, not in the FRD concept itself.


FRD-00: The Orchestration Controller

This master document defines:

  • Required phases
  • Clear dependencies
  • Agent behavior
  • Validation rules per stage
  • Strict conditions to advance or stop
  • Success criteria for each phase

It acts as the logical pipeline that ensures the project can be executed by AI without deviations.

🔗 Ruta


🚀 How Orchestration Actually Begins

Before starting any phase, I execute this initial instruction so the AI loads all FRDs and understands the execution order:

@FRD-00-master-orchestration.md
@FRD-01-boilerplate-core-products.md
@FRD-02-products-database.md
@FRD-03-auth-security.md
@FRD-04-unit-testing.md 

folder name: api-products

FRD-00-master-orchestration.md
FRD-01-boilerplate-core-products.md
FRD-02-products-persistence-typeorm.md
FRD-03-unit-testing.md

Start the orchestration.

Enter fullscreen mode Exit fullscreen mode

Why Is This Critical?

  • Ensures the agent follows the correct order
  • Enforces FRD-00 as the master controller
  • Reduces context overload
  • Prevents unnecessary loops or clarifying questions
  • Makes the process reproducible across any AI editor: Windsurf, Antigravity, Cursor, Sonnet, VSCode Agents, etc.

General Project Architecture

The final result was a NestJS backend with:

🧩 Included Modules

  • Auth (JWT + bcrypt + Passport)
  • Users (registration, login, hashing)
  • Products (CRUD with validation)
  • Centralized config
  • SQLite + TypeORM + migrations
  • Unit testing (33 tests)

📁 Final Structure

api-products/
├── src/
│   ├── auth/
│   ├── products/
│   ├── users/
│   ├── config/
│   └── main.ts
├── migrations/
├── README.md
└── package.json
Enter fullscreen mode Exit fullscreen mode

🔥 Phase 1 — Boilerplate + In-Memory CRUD

  • Project created using nest new
  • Swagger enabled
  • Global validation pipes
  • In-memory CRUD
  • DTOs with class-validator
  • Mandatory JSDoc
export class CreateProductDto {
  @IsString()
  name: string;

  @IsBoolean()
  isPremium: boolean;

  @IsNumber()
  price: number;
}
Enter fullscreen mode Exit fullscreen mode

🔗 Ruta


🗄️ Phase 2 — Database + TypeORM

  • TypeORM integration
  • Migrations
  • ProductRepository
  • Real persistence using SQLite
@Entity()
export class Product {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  name: string;

  @Column()
  isPremium: boolean;

  @Column('float')
  price: number;
}
Enter fullscreen mode Exit fullscreen mode

🔗 Ruta


🔐 Phase 3 — JWT Authentication

  • UsersService + repository
  • bcrypt hashing
  • LocalStrategy + JwtStrategy
  • JwtAuthGuard
  • Swagger Bearer Auth
  async login(loginDto: LoginDto): Promise<{ accessToken: string }> {
    const user = await this.usersService.validateCredentials(loginDto.email, loginDto.password);

    if (!user) {
      throw new UnauthorizedException('Invalid credentials');
    }

    const payload = { email: user.email, sub: user.id };
    const accessToken = this.jwtService.sign(payload);

    return { accessToken };
  }
Enter fullscreen mode Exit fullscreen mode

🔗 Ruta


🧪 Phase 4 — Unit Testing

  • 6 test suites
  • 33 tests
  • Clean mocks
  • No real database
  describe('login', () => {
    it('should login successfully and return access token', async () => {
      const loginDto: LoginDto = {
        email: 'test@example.com',
        password: 'password123',
      };
      const accessToken = 'jwt-token';
      mockUsersService.validateCredentials.mockResolvedValue(mockUser);
      mockJwtService.sign.mockReturnValue(accessToken);

      const result = await service.login(loginDto);

      expect(result).toEqual({ accessToken });
      expect(usersService.validateCredentials).toHaveBeenCalledWith(loginDto.email, loginDto.password);
      expect(jwtService.sign).toHaveBeenCalledWith({ email: mockUser.email, sub: mockUser.id });
    });

    it('should throw UnauthorizedException for invalid credentials', async () => {
      const loginDto: LoginDto = {
        email: 'test@example.com',
        password: 'wrongpassword',
      };
      mockUsersService.validateCredentials.mockResolvedValue(null);

      await expect(service.login(loginDto)).rejects.toThrow(UnauthorizedException);
      expect(usersService.validateCredentials).toHaveBeenCalledWith(loginDto.email, loginDto.password);
    });
  });
Enter fullscreen mode Exit fullscreen mode

🔗 Ruta


📊 Final Results

  • All 33 tests passing
  • Migrations working
  • JWT fully functional
  • CRUD operational
  • Consistent architecture

🖼️ Visual Evidence

(Gallery with screenshots from Windsurf, Antigravity, and Claude Sonnet)


🧠 Why This Matters in the AI Era

  1. AI needs structure
  2. Enables end-to-end project execution
  3. Reinforces best practices in LLM-assisted development workflows.
  4. Reproducible, scalable, modular

🧭 Conclusion

FRD Orchestration is not merely an operational technique—it is a way of structuring collaboration between humans and AI models to produce reproducible, stable, and scalable software.

This method enhances—not replaces—the developer.

📂 Official Repository with FRDs + Full Backend


`

Top comments (0)