PROJECT / PRESENTATION
ReturnLoop, the software engineering view
SOFTWARE ENGINEERING · MINI PROJECT
ReturnLoop
A returns and reverse-logistics centre for an e-commerce business: request, pickup, quality check, grading, refurbish / restock / scrap, refund.
01Chirag Seervi
02Anshuman Singh
03Aryan Singh
04Aadi Srivastava
AGENDA
What we'll cover
- 01 Project planning & managementslide 03
- 02 Functional requirementsslide 06
- 03 Non-functional requirementsslide 07
- 04 Use case diagramslide 08
- 05 Class diagramslide 09
- 06 Data flow diagram, level 0slide 10
- 07 Data flow diagram, level 1slide 11
- 08 Activity diagramslide 12
- 09 Sequence diagram: gradingslide 13
- 10 State diagramslide 14
- 11 Sequence diagram: handoffslide 15
- 12 Layered architectureslide 16
- 13 Architecture: from UI to dataslide 17
PPM · PRODUCT / PROJECT PLANNING & MANAGEMENT
Vision, scope and stakeholders
Product vision
Give an online store one place to run every return, from the customer's doorstep to a graded item and a correct refund, with every step on record.
Objectives
- Enforce return rules automatically
- Grade items A / B / C and route them
- Compute refunds exactly, once
- Live tracking for the customer
In scope
- 6 roles, 13-status workflow
- Pickup booking, 2 attempts
- QC checklist, fraud check
- Refurbish & re-inspection
- Refund + inventory log
- Admin dashboard & flags
Out of scope
- Real payments / payment gateway
- Passwords & real accounts
- Courier API integration
Stakeholders
| Customer | returns items, tracks refund |
| Pickup agent | collects parcels |
| Warehouse | checks parcels in |
| QC inspector | grades items |
| Refurbisher | repairs grade B |
| Admin | monitors, flags |
Team
Chirag Seervi, Anshuman Singh, Aryan Singh, Aadi Srivastava
PPM · PROCESS MODEL & PLAN
Incremental delivery in seven increments
Each increment was built, tested with pytest, run, and committed to Git before the next one started. Definition of done: all tests green and the app runs.
- INC ACoreModels, config, services, unit tests
- INC BDataSeed data through real services
- INC CCustomerOrders, return, pickup, tracking
- INC DOperationsAgent, warehouse, QC, refurbisher
- INC EAdminDashboard, charts, flags
- INC FExperienceDesign system, 3D scenes, effects
- INC GHardeningEdge cases, docs, end-to-end demo
Why incremental?
Business rules first, UI later: the riskiest logic (state machine, refunds) was tested before any screen existed.
Work breakdown
Data model → services → routes → templates → visual design → testing & docs.
Tools
Python, Flask, SQLite, pytest, Git, VS Code, Playwright for screenshot checks.
PPM · RISK & QUALITY MANAGEMENT
Risks, and how we handled them
| Risk | Impact | Mitigation in the product |
|---|---|---|
| Invalid status jumps (e.g. refund before QC) | High | Single state machine; every change validated and logged in status_history |
| Refund paid twice | High | Unique refunds.return_id + service check + one DB transaction |
| Double-clicks on submit | Medium | Buttons disable on submit; server rejects the repeat via the state machine |
| Malicious or huge uploads | Medium | Type, 3 MB size and file-signature checks; random file names |
| Device without WebGL / slow GPU | Low | Static fallbacks; particles halve if frame rate < 40 fps |
| Rules change later (window, fees) | Low | All rule constants live in config.py |
QUALITY: 109 AUTOMATED TESTS · STATE MACHINE, REFUNDS, ELIGIBILITY, FLAGS, API, PAGES, FULL FLOW
REQUIREMENTS
Functional requirements
Choose any of 6 roles and a user without a password; each page rejects the wrong role (403).
Customer sees delivered items with eligibility, or the reason it can't be returned.
Return allowed within 7 days of delivery, for returnable products, with no other open return.
Reason, comment (≤ 300 chars), optional photo (PNG/JPG/WEBP, ≤ 3 MB).
Date from tomorrow to +5 days, slot Morning / Afternoon / Evening; reschedule.
Agent marks picked up or absent; the 2nd absence cancels the return.
Warehouse checks the parcel in; it joins the QC queue.
QC checklist, suggested grade, A/B/C; a mismatched item is rejected as fraud.
Grade B goes to repair, then re-inspection: pass → restock (70%), fail → scrap.
final = max(0, base × grade% − pickup fee), damaged/wrong-item exception, created once.
Live status (polled every 5 s), history timeline and refund breakdown.
Totals, reasons and grades charts, frequent-returner flags (> 3 in 30 days).
After each step, a card names the next desk and opens its page in one click.
QC's findings become the fix list; ticked fixes are saved as the notes; past repairs show QC's verdict.
The admin sees the latest status changes, newest first, with who made each one.
REQUIREMENTS
Non-functional requirements
60 fps on a mid laptop, 30+ on phones; pixel ratio capped; 3D pauses off-screen.
Refund + inventory log + status change in one transaction; no double refunds.
Role guard on every blueprint; customers only see their own returns; upload validation.
Plain-language errors and empty states; the handoff card always names the next step.
WCAG AA contrast, keyboard-only use, visible focus, reduced-motion mode, text on every badge.
Logic in services/, rules in config.py, thin routes; a pytest suite over services, pages and the full flow.
Python 3.10+, SQLite, no build step: install, seed, run in 3 commands.
Static fallbacks without WebGL or internet; friendly 403 / 404 / 413 pages.
UML · USE CASE DIAGRAM
Who does what
UML · CLASS DIAGRAM
The domain model (models.py)
classDiagram
direction TB
class Customer {
+name
+email
+address
}
class Product {
+name
+price
+is_returnable
}
class Order {
+order_date
+delivered_at
+total
}
class OrderItem {
+quantity
+unit_price
}
class ReturnRequest {
+return_code
+reason
+status
+flagged_fraud
}
class Pickup {
+slot_date
+slot_window
+attempt_no
}
class QCReport {
+grade
+item_matches_order
+is_recheck
}
class RefurbishJob {
+status
+completed_at
}
class Refund {
+grade_percent
+pickup_fee
+final_amount
}
class InventoryLog {
+action
+quantity
}
class StatusHistory {
+from_status
+to_status
+actor_name
}
Customer "1" --> "*" Order : places
Order "1" *-- "1..*" OrderItem : contains
OrderItem "*" --> "1" Product
OrderItem "1" --> "*" ReturnRequest : returned in
ReturnRequest "1" *-- "*" Pickup
ReturnRequest "1" *-- "*" QCReport
ReturnRequest "1" *-- "*" RefurbishJob
ReturnRequest "1" *-- "0..1" Refund
ReturnRequest "1" *-- "*" StatusHistory
ReturnRequest "1" --> "*" InventoryLog
DFD · LEVEL 0 (CONTEXT DIAGRAM)
The system and the people around it
flowchart LR
C[Customer]
AG[Pickup agent]
WH[Warehouse manager]
QC[QC inspector]
RF[Refurbisher]
AD[Admin]
S(("0
ReturnLoop
System"))
C -- "return request, photo, pickup slot" --> S
S -- "eligibility, status, refund breakdown" --> C
S -- "pickup list, addresses" --> AG
AG -- "picked up / absent" --> S
WH -- "parcel received" --> S
S -- "inbound parcels, inventory" --> WH
S -- "QC queue, item details" --> QC
QC -- "checklist, grade" --> S
S -- "repair jobs" --> RF
RF -- "repaired" --> S
S -- "stats, charts, flagged customers" --> AD
DFD · LEVEL 1
Processes and data stores
flowchart LR
C[Customer]
AG[Pickup agent]
WH[Warehouse]
QC[QC inspector]
RF[Refurbisher]
AD[Admin]
P1(("1.0
Check eligibility
& create return"))
P2(("2.0
Schedule
pickup"))
P3(("3.0
Collect
parcel"))
P4(("4.0
Receive
parcel"))
P5(("5.0
Inspect
& grade"))
P6(("6.0
Refurbish"))
P7(("7.0
Issue
refund"))
P8(("8.0
Report
& flag"))
D1[("D1 Orders / Products")]
D2[("D2 Return requests")]
D3[("D3 Pickups")]
D4[("D4 QC reports")]
D5[("D5 Refunds + Inventory log")]
D6[("D6 Status history")]
C -- "reason, photo" --> P1
D1 -- "delivery date, returnable" --> P1
P1 -- "new return" --> D2
C -- "date, slot" --> P2
P2 --> D3
D3 -- "pickup list" --> AG
AG -- "outcome" --> P3
P3 --> D2
WH -- "check-in" --> P4
P4 --> D2
QC -- "checklist, grade" --> P5
P5 --> D4
P5 -- "grade B" --> P6
D4 -- "QC findings" --> P6
RF -- "repaired" --> P6
P6 -- "re-inspection" --> P5
P5 -- "A / C / recheck" --> P7
P7 --> D5
P5 -. "every status change" .-> D6
D2 & D5 --> P8
D6 -- "latest events" --> P8
P8 -- "stats, flags, live feed" --> AD
UML · ACTIVITY DIAGRAM
One return, start to finish
UML · SEQUENCE DIAGRAM
QC grades a return and the refund is issued
sequenceDiagram autonumber actor QC as QC inspector participant B as Browser participant R as qc blueprint participant W as services.returns participant SM as state_machine participant F as services.refund participant DB as SQLite QC->>B: tick checklist, choose grade A, Stamp it B->>R: POST /qc/inspect/RL-2026-0004 R->>W: submit_inspection(ret, checklist, "A") W->>SM: change_status(Received → Inspected) W->>SM: change_status(Inspected → Restocked) W->>F: issue_refund(ret, "Restocked") F->>F: calculate_refund(base, A, reason) F->>SM: change_status(Restocked → Refunded) F->>DB: INSERT refund, inventory_log, status_history (one COMMIT) R-->>B: 302 redirect to queue + toast Note over B,DB: Customer's tracking page polls GET /api/return/code/status every 5 s and moves the parcel
UML · STATE DIAGRAM
Every status a return can be in
UML · SEQUENCE DIAGRAM
Handing a return to the next desk
sequenceDiagram autonumber actor A as Pickup agent participant B as Browser participant R as agent blueprint participant W as services.returns participant H as services.handoff participant S as /switch participant DB as SQLite A->>B: Mark picked up, confirm B->>R: POST /agent/pickup/7 R->>W: mark_picked_up(pickup) W->>DB: status Picked Up + history row (COMMIT) R->>R: hand_off(ret): remember RL-2026-0004 in the session R-->>B: 302 redirect to /agent/pickups B->>R: GET /agent/pickups R->>H: handoff_for(ret, agent) while rendering H-->>R: next desk: warehouse, Ansuman Singh R-->>B: page + card "Your part is done" A->>B: Continue as warehouse B->>S: POST /switch (who, next, code) S-->>B: 302 redirect to /warehouse/receive?focus=RL-2026-0004 Note over B,DB: The warehouse page opens with this parcel highlighted. No menu, no searching.
ARCHITECTURE · LAYERS
Layered architecture
templates/, static/
blueprints/
services/
config.py
models.py
returnloop.db
RULE: EACH LAYER ONLY TALKS TO THE ONE BELOW · ROUTES NEVER CONTAIN BUSINESS RULES
ARCHITECTURE · FROM UI TO DATA
One click, layer by layer: “Request return”
- UIBrowser
Form with reason tiles, comment and photo is submitted (button disables itself).
- HTTPPOST /customer/return/new
Multipart request reaches Flask; session holds role + user id.
- Guardcustomer blueprint
before_request checks the role is customer, else friendly 403.
- Validateservices.uploads
Photo type, size ≤ 3 MB and file signature are checked.
- Rulesservices.eligibility
7-day window, returnable product, no open return.
- Logicservices.returns
Generates RL-2026-0004, writes the first status_history row.
- ORMmodels.ReturnRequest
SQLAlchemy turns objects into INSERT statements.
- DataSQLite
Rows committed in one transaction.
- Back to UIRedirect + Jinja2
Pickup page renders; tracking page later polls the JSON API.
END OF DECK · QUESTIONS?
Thank you.
Chirag Seervi · Anshuman Singh · Aryan Singh · Aadi Srivastava
pip install -r requirements.txt && python seed.py && python app.py