Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f6f87f6
BS successfully connected to DB
technologic-technologic Jun 14, 2025
9722586
Modified Product object requirements
technologic-technologic Jun 14, 2025
131ec63
Modified Product
technologic-technologic Jun 14, 2025
d65d406
Business service updated
technologic-technologic Jun 16, 2025
83276be
Moved hardcoded versions
technologic-technologic Jun 20, 2025
df8e90a
Added lombok dependency to the project
technologic-technologic Jun 20, 2025
5453e4a
Deleted getters & setters
technologic-technologic Jun 20, 2025
f31818e
Changed to .yml for the properties file
technologic-technologic Jun 20, 2025
faa56da
Deleted unused class
technologic-technologic Jun 20, 2025
2376723
New method to delete products
technologic-technologic Jun 20, 2025
10c7eaa
Updated the body type of the endpoints response entities with a DTO
technologic-technologic Jun 21, 2025
755ab54
Added feature to retrieve number of pages per data fetch
technologic-technologic Jun 21, 2025
ebc6eae
Added functionality so client can fetch all the different categories
technologic-technologic Jun 21, 2025
6a7c42b
Added summary/metrics functionality logic and endpoint
technologic-technologic Jun 23, 2025
378946f
testing
technologic-technologic Jun 24, 2025
2208829
Merge pull request #7 from technologic-technologic/5-update-business-…
technologic-technologic Jun 24, 2025
4f4c190
* (#10)
technologic-technologic Jun 24, 2025
f6529c7
Modified project to run locally
technologic-technologic Jul 23, 2025
aadfc2b
Create AI agent for PRs (#14)
technologic-technologic Oct 4, 2025
e94ad2d
Deleted empty classes
technologic-technologic Oct 4, 2025
040d4ba
API project runs on port 9090
technologic-technologic Oct 4, 2025
7ab4af7
Project running with no external DBs
technologic-technologic Oct 5, 2025
7d4fca7
Fine-tune agent behavior
technologic-technologic Oct 5, 2025
948c965
Update CORS to allow client on localhost:8080
technologic-technologic Oct 13, 2025
22ccd63
Update repository query
technologic-technologic Oct 16, 2025
eca633d
Upgraded test compliance
technologic-technologic Oct 17, 2025
48e0cf1
Upgraded pom to avoid vulnerabilities (#26)
technologic-technologic Oct 17, 2025
400cafc
Gen-AI module - > repository, cors, testing, and dependency upgrade
technologic-technologic Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions .github/workflows/ai-pr-summary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
name: PR AI Summary

on:
pull_request:
types: [opened, synchronize, reopened]

permissions:
contents: read
pull-requests: write

jobs:
summarize:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Get PR diff
id: diff
run: |
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
# Trae exactamente esos commits (evita problemas de merge-base y shallow clones)
git fetch --no-tags --prune --depth=1 origin $BASE $HEAD
git diff $BASE $HEAD > pr.diff
echo "path=pr.diff" >> $GITHUB_OUTPUT

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install deps
run: |
python -m pip install --upgrade pip
pip install openai==1.* # SDK oficial

- name: Generate AI summary (OpenAI)
id: ai
continue-on-error: true
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MODEL: gpt-4o-mini
run: |
python - << 'PY'
import os
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

with open("pr.diff","r",encoding="utf-8") as f:
diff = f.read()[:200000] # tope por costos/ruido

prompt = (
"You are a code reviewer. Summarize this PR in 2-20 bullets. "
"Include WHAT changed, WHY it matters, RISKS, TESTS to add, and any BREAKING CHANGES. "
"Highlight key features or changes. Consider markdown as the default output format."
"Keep in mind the following points:"
"1) If DIFF shows only documentation files (e.g., .md/.mdx/.txt/README), state 'Docs-only change', "
" make clear that the change is included only in documentation files, if that is the case, "
" otherwise explain normally, considering the DIFF changes like normal. "
"2) Include a short list of changed file paths as extracted from DIFF. "
"Keep it concise and actionable.\n\nDIFF:\n" + diff
)

resp = client.chat.completions.create(
model=os.getenv("MODEL","gpt-4o-mini"),
temperature=0.2,
messages=[{"role":"user","content":prompt}],
)
text = resp.choices[0].message.content.strip()
with open("summary.txt","w",encoding="utf-8") as f:
f.write(text)
PY

- name: Heuristic fallback if AI failed
if: ${{ steps.ai.outcome == 'failure' }}
run: |
python - << 'PY'
import re, pathlib
diff = pathlib.Path("pr.diff").read_text(encoding="utf-8")

added = len(re.findall(r"^\\+[^+].*$", diff, flags=re.M))
removed = len(re.findall(r"^\\-[^-].*$", diff, flags=re.M))
files = re.findall(r"^\\+\\+\\+ b/(.+)$", diff, flags=re.M)

lower_paths = [f.lower() for f in files]
DOC_EXT = (".md", ".mdx", ".txt", ".rst", ".adoc")
is_doc = lambda p: p.endswith(DOC_EXT) or "/docs/" in p or "/doc/" in p
docs_only = len(files) > 0 and all(is_doc(p) for p in lower_paths)

# ---------- Doc-only summary ----------
if docs_only:
bullets_changed = []
for f in files[:20]: # evita listas enormes
bullets_changed.append(f"- `{f}`")
doc_summary = [
"## PR Summary",
"",
"### WHAT Changed",
"- **Docs-only change** detected from DIFF.",
f"- Files changed ({len(files)}):",
*bullets_changed,
"",
"### WHY It Matters",
"- Improves documentation/README clarity and onboarding experience.",
"",
"### RISKS",
"- None to runtime behavior (documentation only).",
"",
"### TESTS to Add",
"- N/A (no code changes).",
"",
"### BREAKING CHANGES",
"- None.",
]
pathlib.Path("summary.txt").write_text("\n".join(doc_summary), encoding="utf-8")
raise SystemExit(0)

scopes = set()
for f in files:
fl = f.lower()
if "/controller" in fl: scopes.add("controller")
elif "/service" in fl: scopes.add("service")
elif "/repository" in fl or "jparepository" in diff.lower(): scopes.add("repository")
elif "/entity" in fl or "/model" in fl: scopes.add("entity")
elif "application" in fl and (fl.endswith(".yml") or fl.endswith(".yaml") or fl.endswith(".properties")):
scopes.add("config")
elif fl.endswith("test.java"): scopes.add("test")

scope = ",".join(sorted(scopes)) if scopes else "core"
kind = "refactor"
if added and not removed: kind = "feat"
if removed and not added: kind = "chore"
if re.search(r"@Test", diff): kind = "test"
if re.search(r"fix|bug|exception|stacktrace", diff, re.I): kind = "fix"

subject = f"[Fallback] {kind}({scope}): {len(files)} file(s), +{added}/-{removed}"

bullets = []
bullets.append(f"- Files changed: {len(files)}")
bullets.append(f"- Lines: +{added} / -{removed}")
if scopes:
bullets.append(f"- Layers: {', '.join(sorted(scopes))}")
if re.search(r"@Transactional", diff): bullets.append("- Touches transactional boundaries")
if re.search(r"@RestController|@Controller", diff): bullets.append("- Controller changes present")
if re.search(r"@Service", diff): bullets.append("- Service-layer changes present")
if re.search(r"@Repository|JpaRepository", diff): bullets.append("- Repository-layer changes present")
if re.search(r"todo|fixme", diff, re.I): bullets.append("- Contains TODO/FIXME markers")

text = subject + "\\n\\n" + "\\n".join(bullets)
pathlib.Path("summary.txt").write_text(text, encoding="utf-8")
PY

- name: Comment on PR
uses: marocchino/sticky-pull-request-comment@v2
with:
header: ai-pr-summary
recreate: true
path: summary.txt
38 changes: 20 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# InventoryManagerBC
Breakable Toy 1 - Inventory Manager
Breakable Toy 1 (Gen AI Augmented) - Inventory Manager

# Inventory Management Application

This is a Spring Boot-based inventory management application designed to help manage product inventories effectively. It provides a RESTful API to create, update, and retrieve product information with filtering, sorting, and pagination capabilities. This application is built with future scalability in mind, including support for an easy transition from in-memory storage to a persistent database.

---

## 🚀 Features
## Features

- **Product Management**
- Create new products with name, category, quantity, unit price, and optional expiration date.
Expand All @@ -30,10 +30,10 @@ This is a Spring Boot-based inventory management application designed to help ma

---

## 🧱 Technical Overview
## Technical Overview

### Model: `Product`
- `id` (Unique Identifier)
- `id` (Unique Identifier. Auto-generated)
- `name` (Required, max 120 characters)
- `category` (Required)
- `unitPrice` (Required)
Expand All @@ -44,30 +44,31 @@ This is a Spring Boot-based inventory management application designed to help ma

### API Endpoints

| Method | Endpoint | Description |
|--------|----------------------------------|---------------------------------------------------|
| GET | `/products` | Retrieve products with filtering, sorting, and pagination |
| POST | `/products` | Create a new product |
| PUT | `/products/{id}` | Update an existing product |
| POST | `/products/{id}/outofstock` | Mark a product as out of stock |
| PUT | `/products/{id}/instock` | Restore a product's stock |
| Method | Endpoint | Description |
|--------|-----------------------------|------------------------------------------------------------------|
| GET | `/products` | Retrieve products with pagination support |
| POST | `/products` | Create a new product |
| DELETE | `/products` | Delete a products |
| PUT | `/products/{id}` | Update an existing product |
| PATCH | `/products/{id}/outofstock` | Mark a product as out of stock |
| PATCH | `/products/{id}/instock` | Restore a product's stock<br/> |
| GET | `/products/summary` | Retrieves inventory metrics |
| GET | `/products/filters` | Retrieves products based on filters, sort methods and pagination |
| GET | `/products/categories` | Retrieves all the categories available |

### Storage

Currently, product data is stored in-memory using Java Collections. The application is designed to allow easy migration to a persistent storage layer in the future.

---

## 🛠️ Tech Stack
## Tech Stack

- **Language:** Java
- **Framework:** Spring Boot
- **Build Tool:** Maven
- **Data Storage:** In-Memory (Java Collections)
- **Data Storage:** H2 local Runtime via JDBC

---

## ⚙️ Getting Started
## Getting Started

### Prerequisites

Expand All @@ -77,4 +78,5 @@ Currently, product data is stored in-memory using Java Collections. The applicat
### Running the Application

```bash
mvn spring-boot:run
mvn spring-boot:run
```
72 changes: 65 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
<version>3.5.6</version>
<relativePath/>
</parent>
<groupId>com.encorazone</groupId>
<artifactId>inventory-manager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>1.0.0</version>
<name>inventory-manager-spark</name>
<description>Demo project for Spring Boot</description>
<description>Inventory management application</description>
<url/>
<licenses>
<license/>
Expand All @@ -27,7 +27,14 @@
<url/>
</scm>
<properties>
<logback.version>1.5.19</logback.version>
<java.version>17</java.version>
<ojdbc.version>21.3.0.0</ojdbc.version>
<springdoc.version>2.8.13</springdoc.version>
<lombok.version>1.18.38</lombok.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<maven-compiler.version>3.14.0</maven-compiler.version>
<commons-lang3.version>3.18.0</commons-lang3.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -46,7 +53,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>${ojdbc.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
Expand All @@ -66,17 +77,64 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:+EnableDynamicAgentLoading -Xshare:off</argLine>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
Loading