AI is changing how we build software, but many teams still work as if nothing has changed. They treat code as the only reliable artifact. Everything else slowly gets outdated:
- Requirements documents drift away from reality
- Diagrams do not match the current architecture
- Tests only cover part of the behavior
- Business logic hides deep in service classes
AI code generation tools can make this even worse if used without structure. They produce code fast, but the process behind the code remains the same.
Spec-Driven Development (SDD) solves this by starting from clear specifications instead of starting from code. AI then uses these specifications to generate consistent code, tests, and documentation.
The AI Unified Process (AIUP) is a practical way to apply SDD in real projects. It keeps requirements, code, and documentation in sync. In this article, we look at AIUP in the context of a full-stack Java application built with Spring Boot, jOOQ, and Vaadin.
From Code-Centered To Spec-Driven
In most teams, development is code-centered:
- A ticket is created
- A developer writes code
- Documentation and tests come later
This leads to long-term problems:
- You lose track of why a rule exists
- Business decisions hide in commit messages
- Refactoring becomes risky
- The architecture stops matching the documentation
Spec-Driven Development flips this:
- You start with a clear specification.
- This specification becomes the single source of truth.
- AI generates code, tests, and diagrams from it.
- Developers review and adjust the generated results.
When requirements change, you update the specification first, then regenerate.
The AI Unified Process (AIUP)
AIUP is an iterative process with a simple but powerful structure.
It is built on three core specification artifacts:
- Requirements Catalog
- Entity Model
- System Use Cases
These artifacts are always updated in this order. Everything else flows from them.
1. Requirements Catalog
The Requirements Catalog is the foundation of AIUP.
It defines what the system must do and under which conditions.
It contains three types of requirements:
Functional Requirements
These describe what the system should do. In AIUP, they are usually written as user stories.
Examples:
- As a user, I want to create a customer with name and email.
- As an admin, I want to deactivate customers who have no open orders.
- As a sales agent, I want to see all active customers sorted by name.
Functional requirements describe user goals and expected behavior, not code.
Non-Functional Requirements
These describe qualities of the system, like:
- Performance
- Security
- Availability
- Logging
- Observability
- Scalability
Example:
- All write operations must be audited with a timestamp, user, and change details.
Constraints
These describe rules that must always be enforced.
Examples:
- Customer email must be unique.
- Only authenticated users may access customer data.
- Orders cannot be deleted once invoiced.
The Requirements Catalog is written in simple, precise language. It is reviewed frequently and kept under version control. Everything in AIUP starts with this catalog.
2. Entity Model
The Entity Model describes the domain data structure.
It answers:
Which concepts exist, and how do they relate?
The Entity Model is based on the Requirements Catalog. Functional requirements describe what users want to do. Constraints often describe the domain rules. From both, you extract stable domain objects.
For example, from the requirements above, you define:
Entities:
- Customer
- Order
Attributes:
- Customer: id, name, email, active
- Order: id, status, totalAmount, customerId
Relationships:
- Customer 1..* Order
The Entity Model lets AI generate:
- Database schema or migrations
- jOOQ meta model
- Domain classes and DTOs
- Validation rules
- Basic UI bindings in Vaadin
It ensures that back end, database, and UI use the same domain structure.
3. System Use Cases
AIUP uses only System Use Cases. There is no separation between business and system use cases.
A System Use Case describes how the system behaves when triggered by a user or external system. It defines:
- Actors
- Preconditions
- Steps
- Decision logic
- Postconditions
- Errors
System Use Cases transform requirements into explicit logic.
Example System Use Case: Deactivate Customer
Name: Deactivate Customer
Actor: Administrator
Preconditions:
- User is authenticated
- User has role ADMIN
Main Flow:
- Load customer
- Load related orders
- Check for open orders
- If open orders exist, return error
- Set customer.active = false
- Write audit entry
Postconditions:
- Customer is inactive
- Operation is logged
How AIUP Runs In Iterations
AIUP uses short iterations. Each cycle follows this sequence:
- Update Requirements Catalog
- Update Entity Model
- Update System Use Cases
- Generate code, diagrams, and tests with AI
- Review and improve the generated output
- Run tests
- Refine the specifications
This creates a stable, controlled development loop.
Example: A Java Feature With AIUP
Imagine you add a “Deactivate Customer” feature. All documentation is code and under version control.
The example uses Markdown, but you could also use AsciiDoc to get a richer Markdown syntax.
Step 1: Requirements Catalog
| Category | Description |
|---------------------------|------------------------------------------------------------|
| Functional requirement | As an admin, I want to deactivate a customer who has no open orders. |
| Non-functional requirement| All write operations must be audited. |
| Constraint | Customer email must be unique.
Step 2: Entity Model
Entity: Customer with id, name, email, active
Entity: Order with id, status, customerId
Relation: Customer 1..* Order
Rule: Status can be OPEN, COMPLETED, or CANCELLED
AI generates:
- Migration script for unique email
- jOOQ code
- Domain classes
Step 3: Use Cases
## UC-001: Deactivate Customer
**Name**
Deactivate Customer
**Actor**
Administrator
**Preconditions**
- User is authenticated
- User has role ADMIN
**Main Flow**
1. Load customer
2. Load related orders
3. Check for open orders
4. If open orders exist, return error
5. Set customer.active = false
6. Write audit entry
**Postconditions**
- Customer is inactive
- Operation is logged
AI generates:
- Vaadin UI
- Service method implementing logic
- jOOQ queries
- Unit, integration tests, and E2E tests
You review, adjust, and commit.
Why This Fits Full-Stack Java So Well
AIUP fits the Java ecosystem because:
- The Spring ecosystem is very mature
- jOOQ is built around generated code
- Vaadin UI components are superior
- Java is strongly typed
- Tests are easy to generate from System Use Cases
AIUP connects these elements with a straightforward process.
Benefits For Teams
- Clear Requirements
Rules, constraints, and user stories are explicit. - Consistent Architecture
UI, Backend, and database reflect the same model. - Faster Onboarding
New developers read the specs instead of guessing - Safer Use Of AI
AI follows the spec and avoids random patterns. - Higher Speed
AI handles repetitive tasks - Lower Risk
System Use Cases generate strong test coverage.
AI Is A Partner, Not A Replacement
AIUP assumes a skilled development team. Developers still:
- Make architectural decisions
- Review the generated code
- Ensure security
- Ensure performance
- Adjust implementation details
AI accelerates work. Developers ensure correctness.
Conclusion
Spec-Driven Development with AIUP provides teams with a structured approach to using AI. AI can generate code, tests, and diagrams that stay consistent with the specification.
In a Java stack using Spring Boot, jOOQ, and Vaadin, this approach is a natural fit. It increases speed, improves quality, and keeps the system aligned with business needs.
To get started:
- Write the Requirements Catalog
- Define the Entity Model
- Add System Use Cases
- Let AI generate code and tests
- Review, refine, and repeat
This is how AIUP makes full-stack Java development faster, safer, and more consistent.
See it in Action
Two webinar recordings show how to work with the AIUP: Spec-driven Development and Spec-driven Testing
