- Name: neomart
- Role: E-commerce and store API for the Neo Ecosystem.
- Port:
8083(internal) /dev.neotica.id/neomart(external) - Internal Database:
db_neomart(Hosted onneoserver-db)
- Framework: Ktor Server (Netty) v3.x
- Language: Kotlin
- ORM: Exposed DAO (UUIDTable)
- DI: Koin
- Migrations: Flyway (Targeting
db_neomartonly)
Every table uses UUIDTable to match neoserver standards.
| Table | Key Fields | Relationship |
|---|---|---|
| ProductTable | id, name, price, stock, description, image_url, created_at | - |
| CategoryTable | id, name | 1:N with Products |
| CartTable | id, user_id (UUID), product_id, quantity, created_at | user_id (JWT), product_id (ProductTable |
| OrderTable | id, user_id (UUID), total_amount, status, created_at | user_id (JWT) |
| OrderItemTable | id, order_id, product_id, quantity, price_at_purchase | order_id (OrderTable, CASCADE delete) |
- Secret: Loaded securely via
Utils.EnvLoader["HMAC_256_SECRET"]. - Issuer: Loaded securely via
Utils.EnvLoader["NEOSERVER_URL"]. - Claim Name: Must look for
"id"(matchesneoservertoken payload). - Architecture Note (CRITICAL): - Ktor 3.x's
Authenticationplugin is installed globally to act as a strict gatekeeper (verifies signature and issuer).- However, due to a Ktor 3 context-dropping quirk, we do not use
call.principal<JWTPrincipal>()in our routes. - Instead, routes use a custom extension function
call.getUserIdFromToken()which safely extracts the rawAuthorizationheader and decodes the"id"claim directly after Ktor has validated the request. - Rule: Neomart never queries
neoserverto verify a user.
- However, due to a Ktor 3 context-dropping quirk, we do not use
| Method | Route | Auth | Description |
|---|---|---|---|
| GET | /products | no | List all products |
| GET | /products/{id} | no | Product details |
| POST | /cart | yes | Add item to cart (uses JWT id) |
| GET | /cart | yes | View User's Cart |
| DELETE | /cart/{id} | yes | Delete User's Cart |
| POST | /checkout | yes | [TRANSACTION] Process cart, deduct stock, order. |
| POST | /admin/products | yes | Add new product (Requires Admin Roles) |
| PUT | /admin/products/{id} | yes | Update existing product (Requires Admin Roles) |
| DELETE | /admin/products/{id} | yes | Delete a product (Requires Admin Roles) |
- Proxy Logic: Mirror the
seaweedProxyfromneoserver. - Target bucket:
neomart-asset/neomart - Access URL:
dev.neotica.id/neomart/assets/{fileName} - Database Storage: The
productstable strictly stores the relative path, allowing the client to prepend the base URL dynamically.
- Order History (
GET /orders)
- Fetch all
orders(and eager-load nestedorder_itemsvia Exposed's.with()) where theuser_idmatches the JWT token.
- Admin Order Fulfillment (
PUT /admin/orders/{id})
- Secure route for store managers to change an order's
status(e.g. from "COMPLETED" to "SHIPPED" or "CANCELLED").
- Pagination & Search
- Update
ProductRepositoryImplto read query parameters and use Exposed's.limit()and.offset()to prevent memory overflow on large datasets.
id.neotica.neomart
/neomart
├── application
│ ├── Frameworks.kt (Dependency Injection config)
│ ├── Monitoring.kt (Call Logging config)
│ ├── Routing.kt (Base Route config)
│ ├── Security.kt (Authentication config)
│ └── Serialization.kt (Serialization config)
├── data
│ ├── dao
│ │ ├── cart
│ │ │ ├── CartTable.kt
│ │ │ └── CartEntity.kt
│ │ ├── order
│ │ │ ├── OrderTable.kt
│ │ │ └── OrderEntity.kt
│ │ └── product
│ │ ├── ProductTable.kt
│ │ └── ProductEntity.kt
│ ├── repository
│ │ └── CartRepositoryImpl.kt
│ │ └── ProductRepositoryImpl.kt
│ └── DatabaseImpl.kt (Points to db_neomart)
│ └── NeoDatabase.kt (Interface for DatabaseImpl.kt)
├── di
│ └── NeoMartModule.kt (Koin module)
├── domain
│ ├── repository
│ │ └── mapper
│ │ └── CartMapper.kt
│ │ └── OrderMapper.kt
│ │ └── ProductMapper.kt
│ │ └── CartRepository.kt
│ │ └── OrderRepository.kt
│ │ └── ProductRepository.kt
│ └── models (NeoProduct, etc.)
│ └── CartItem.kt
│ └── Order.kt
│ └── OrderItem.kt
│ └── Product.kt
├── route
│ └── CartRoute.kt
│ └── OrderRoute.kt
│ └── ProductRoute.kt
├── utils
│ └── Constants.kt
│ └── Extensions.kt
│ └── Utils.kt
└── Application.kt (Frameworks.kt, Routing.kt, Authentication.kt)