# Day 01 - Modular Architecture Baseline

Date: 2026-06-16

## Goal

Move from folder-based modules to real domain-based modules, step by step.

## Architecture Diagnosis

Current modules:

- Authentication
- Admin
- Customer

Main issue:

```text
Admin currently acts as both admin panel and commerce domain owner.
```

Examples of domain concepts currently owned by Admin:

- Product
- Category
- Brand
- Coupon
- DeliveryMethod
- ProductVariant

Target direction:

```text
Catalog owns products.
Pricing owns discounts and coupons.
Cart owns cart behavior.
Order owns orders.
Shipping owns delivery.
Admin only exposes management APIs.
Storefront only exposes customer APIs.
```

## Fixes Reviewed

- `BaseService::exists` and repository contracts now use a consistent `exists(column, value)` API.
- `cart_items` rollback now drops `cart_items`, not `carts`.
- Invalid `purchasable_type/purchasable_id` index was removed from `orders`; `order_items` owns that polymorphic
  relation through `morphs('purchasable')`.

## Module Boundary Rules

- Domain modules own business behavior.
- Admin and Storefront should not own business entities.
- Optional features should be removable without breaking unrelated modules.
- Prefer contracts or application services over deep concrete coupling.

## Optional Module: ProductQuestion

Decision:

Create ProductQuestion as its own optional module, not inside Admin or Customer.

Purpose:

- Customers ask questions about products.
- Admin users answer, approve, reject, or hide questions.
- Public product pages show only approved or answered questions.

Version 1 scope:

- Ask a product question.
- List public product questions.
- Admin list/filter questions.
- Admin answer/approve/reject/hide questions.

Out of scope for version 1:

- Voting
- Reporting
- Nested replies
- Multiple answers
- Notifications

## ProductQuestion Rules

Statuses:

- pending
- approved
- answered
- rejected

Visibility:

- Storefront shows only approved or answered questions.
- Admin can see all statuses.
- New questions start as pending.
- Answering moves a question to answered.
- Rejecting moves a question to rejected.

Business rule location:

Visibility and status transitions belong inside ProductQuestion, not Admin or Storefront.

## ProductQuestion Data Model

Table:

```text
product_questions
```

Columns:

- id
- product_id
- user_id
- question
- answer
- answered_by
- status
- is_visible
- answered_at
- created_at
- updated_at

Product reference decision:

Use a database foreign key from `product_questions.product_id` to `products.id` for version 1.

Reason:

The project is currently a modular monolith with one database. The foreign key protects data
integrity and prevents questions from being attached to missing products.

Tradeoff:

ProductQuestion depends on the `products` table existing before its migration runs. This is
acceptable for now because products are core commerce data. When Catalog is extracted, the table
can remain `products` while the owning Laravel model moves from Admin to Catalog.

## Next Step

Create the ProductQuestion migration and review only the schema before writing model or business code.

## ProductQuestion Progress

- Public endpoint added: `GET /api/v1/products/{productId}/questions`
- Flow: route -> storefront controller -> service -> repository -> model scopes -> resource
- Product listing/detail remains independent from ProductQuestion.

Next:

- Add authenticated question creation.
