23 KiB
Handoff
Project: ina-trading-web
Current branch: main
Latest verified commit: f090ba7
Summary
This codebase has recent updates around auth/onboarding, help/privacy pages, dashboard search, product creation/edit/review/detail, admin review/detail, stock/price editing, seller in-review listing, backend request logging, expired-session redirects, product keyword limits, sanitized backend error display, AddProductRequest validation, and 10 MB upload limits.
The latest build was verified successfully with:
npm run build
Latest TypeScript verification after the validation/upload changes:
npx tsc --noEmit
Latest Codex Changes After 76fb4f3
Product create preorder and warranty submit rules
Files:
src/app/(dashboard)/products/new/details/page.tsxsrc/app/(dashboard)/products/new/specifications/page.tsxsrc/app/(dashboard)/products/new/review/page.tsxsrc/lib/product-draft.tsxsrc/lib/use-product-submit.tssrc/lib/product-request-validation.ts
Behavior:
- Pre-order day placeholder is now
0, not14, so an empty/unfilled value is visually obvious. - If pre-order is checked, the Details step blocks Next unless
preOrderDayis a valid number greater than or equal to 1. - Warranty now has an On/Off switch in the Specifications step.
- When warranty is On:
- warranty type is required
- warranty duration must be greater than or equal to 1
- the review page shows warranty information
- submit payload sends the filled
warrantyInformationobject
- When warranty is Off:
- warranty inputs are disabled and dimmed
- the review page hides warranty information
- submit payload still sends
warrantyInformationas an object required by the backend, with:
{
"type": null,
"duration": null,
"durationType": "MONTH"
}
- Frontend payload validation treats the above null-valued warranty object as warranty Off, so it does not block submit with warranty type/duration errors.
- Local test server was rebuilt and restarted against
https://api-dev.inatrading.co.idin.env.local;.env.localis not committed.
AddProductRequest validation
Files:
src/lib/product-request-validation.tssrc/lib/use-product-submit.tssrc/app/(dashboard)/products/[productId]/edit/page.tsxsrc/app/(dashboard)/products/new/details/page.tsxsrc/app/(dashboard)/products/new/pricing/page.tsxsrc/app/(dashboard)/products/new/specifications/page.tsxsrc/lib/product-draft.tsx
Behavior:
- Added a shared validator for create/edit product payloads before requests are sent to backend.
- Validates the backend
AddProductRequestlimits for:- basic product fields
- image/file IDs
- keywords max 3 and features max 5
- model fields, currencies, SKU, package fields
- numeric weight/dimension/package fields max 9 digits plus 1 decimal
- warehouse IDs max 50 and stock minimal 1
- measurement fields, measurement warehouses, and measurement stock
- product/category information param name/value limits
- compliance information limits
- warranty type max 50 and duration minimal 1 when warranty is filled
- Existing wizard drafts normalize keywords to max 3 and features to max 5.
- Create-product UI now shows visible validation-limit panels on:
- Details
- Pricing
- Specifications
- Relevant inputs also received direct hints/limits such as max product name length, keyword/feature limits, pre-order minimum, warranty minimum, and upload limit text.
Upload file size limit
Files:
src/lib/upload-limits.tssrc/app/api/upload/route.tssrc/components/upload-field.tsxsrc/app/(dashboard)/products/new/specifications/page.tsxsrc/app/(dashboard)/products/[productId]/edit/page.tsxsrc/app/(onboarding)/onboarding/business/page.tsx
Behavior:
- Uploads are limited to 10 MB per file.
- Client-side checks reject oversized files before upload in shared upload fields, product create/edit document uploads, and onboarding legal document upload.
- Server-side
/api/uploadrejects oversized files with HTTP413and a saferesponseDesc. - User-facing helper text now mentions the 10 MB limit for document uploads.
Previous Codex Changes After aa406f5
Backend URL
Local .env.local now points to:
NEXT_PUBLIC_API_URL=https://api.inatrading.co.id
The previous local value was https://be.inatrading.co.id.
Expired session / access denied handling
Files:
src/components/auth-session-guard.tsxsrc/app/layout.tsx
Behavior:
- A global client guard wraps local
/api/*fetch calls, excluding/api/auth/*. - If a response is
401,403, or contains auth-style error text such as:access deniedunauthorizedsession expiredtoken expiredinvalid token
- It clears
tokenandrolefromlocalStorageandsessionStorage, then redirects to/login.
Product create keyword limit
Files:
src/app/(dashboard)/products/new/details/page.tsxsrc/lib/product-draft.tsxsrc/lib/use-product-submit.tssrc/lib/translations/id.tssrc/lib/translations/en.ts
Behavior:
- Create-product search keywords are limited to 3.
- The keyword input and add button are disabled after 3 keywords.
- Existing saved wizard drafts are normalized to a maximum of 3 keywords when loaded from
sessionStorage. - Submit payload uses only the first 3 keywords as a backend guard.
Sanitized backend error display
Files:
src/lib/error-message.tssrc/lib/use-product-submit.tssrc/components/upload-field.tsxsrc/app/(dashboard)/products/new/review/page.tsxsrc/app/(dashboard)/products/[productId]/edit/page.tsx- plus updated callers across dashboard, admin, settings, onboarding, upload, news, places, categories, and warehouse forms
Behavior:
- Raw JSON request/response error logs are no longer shown to users.
Copy Error LogUI was removed from create-product review and edit-product save errors.getBackendErrorMessage()extracts a user-safe message from:responseDescmessageerrordetails- nested
data
- JSON-looking strings are parsed for a useful message; if none is found, the UI falls back to the local generic error.
- Long text messages are capped to avoid large raw dumps in the UI.
Verification notes
npx tsc --noEmitpassed after the latest changes.npm run lintstill has pre-existing unrelated errors in:src/app/(dashboard)/dashboard/page.tsxsrc/app/(dashboard)/layout.tsx
- Local dev server was running at
http://localhost:3000.
Current Local Changes After 7e6446b
These are the important local changes made after the last recorded commit. The latest local build was verified successfully with npm run build, and the production local server was restarted on http://localhost:3000.
Admin review compare flow
File:
src/app/admin/review/[productId]/page.tsx
Behavior:
- Product update review now uses the compare API as the source of truth:
- frontend proxy:
GET /api/admin/review/{productId}/compare - backend:
GET /api/v1.0/product/compare/{productId}
- frontend proxy:
- The compare payload is parsed from rows like:
productImages[id=...].imageproductFiles[id=...].fileIdproductModels[sku=...].pricecategoryInformations[paramName=Design].paramValueproductFeatures[3]- nested objects such as
complianceInformation.safetyWarning
- The page reconstructs:
oldProductfromoldValuenewProductfromnewValue
- The compare layout is now section-paired, not product-paired:
Gambar Produk (Diajukan)Gambar Produk (Live Saat Ini)Detail Produk (Diajukan)Detail Produk (Live Saat Ini)- and so on for features, keywords, info, files, models, compliance, warranty
- Empty section pairs are hidden. If both proposed and live sections have no displayable content, nothing is rendered.
Statusis not shown in the compareDetail Produksection and no longer marks the section as updated.- Compare image thumbnails are rendered as small square thumbnails with
object-contain, so images are visible in full instead of cropped into wide banners. - Approve/reject for update reviews uses the resolved review/action id from compare, when available.
Reference test data:
/Users/wirabasalamah/Downloads/json compare.txt- Example compare API:
/api/v1.0/product/compare/ba70a8e3-2342-4cd3-a7c7-a0f1b58689ab
Image URL handling
Files:
src/lib/image-url.tssrc/components/product-variant-showcase.tsxsrc/app/(dashboard)/products/[productId]/detail/page.tsxsrc/app/admin/products/[productId]/page.tsxsrc/app/admin/review/[productId]/page.tsxsrc/app/admin/review/page.tsxsrc/app/admin/news/new/page.tsxsrc/app/admin/news/[newsId]/edit/page.tsxsrc/app/admin/places/PlaceForm.tsx
Behavior:
- Added shared image URL helper:
- if backend already provides an image URL, use it as-is
- otherwise build a fallback URL from
imageId - default fallback uses
/api/v1.0/file/image/tmp/{imageId}
- Seller/admin product details and admin review now use backend
imagefields before building URLs. - Product variant showcase now supports
imageon product images and model images.
Product create/edit thumbnail persistence
Files:
src/app/(dashboard)/products/new/details/page.tsxsrc/app/(dashboard)/products/new/pricing/page.tsxsrc/app/(dashboard)/products/new/review/page.tsxsrc/app/api/file/image/[...path]/route.ts
Behavior:
- Added local API proxy for images:
GET /api/file/image/{path}- forwards to backend
/api/v1.0/file/image/{path}with auth headers
- Create product step 2 and step 3 reload thumbnails from saved file ids when navigating forward/back.
- Create product final review shows real thumbnails for visual identity and model images.
- Review page was made full width and now displays model image and measurement details more completely.
Product create submit debug logging
File:
src/app/api/products/create/route.ts
Behavior:
- When
DEBUG_BACKEND_PROXY=true, create product submit writesproduct-create-submit-log.json. - The log captures:
- local endpoint
- backend endpoint
- redacted headers
- full request payload
- backend response
Current known finding from latest capture:
- Payload sent top-level
imageIdand separateproductImages. - Backend review detail returned top-level
imageIdfromproductImages[0], not from request top-levelimageId. - Payload sent
productFiles, but review detail returnedproductFiles: []in the checked response.
Dashboard seller metrics
File:
src/app/api/dashboard/seller/route.ts
Behavior:
- Fixed parsing of scalar metrics from backend payloads where
datais an object like{ total: 96 }. - Verified for Pendopo account that dashboard total products can resolve to non-zero.
Admin product list/detail
Files:
src/app/admin/products/page.tsxsrc/app/admin/products/[productId]/page.tsxsrc/app/api/admin/products/route.ts
Behavior:
- Admin product list now renders product thumbnails in
All ProductandDeletedtabs. - Thumbnail uses the shared image URL helper.
- Admin product detail now resolves main category by looking up categories/subcategories when backend omits
subCategory.category.name. - Admin All Product endpoint was tested with:
GET /api/v1.0/admin/product?page=1&size=20
- Backend returned:
- HTTP
400 - body
{"responseCode":"000001","data":null,"responseDesc":"Bad Request"}
- HTTP
- Current proxy behavior:
- tries
/api/v1.0/admin/product - if non-deleted tab and the admin endpoint fails, falls back to
/api/v1.0/product
- tries
- Deleted endpoint remains:
GET /api/v1.0/admin/deleted/product?page={page}&size={size}
- Server log showed request reached backend with admin token and failed in about 3 ms, suggesting request validation/contract mismatch rather than auth or DB latency.
Seller profile save flow
Files:
src/app/(dashboard)/settings/page.tsxsrc/app/api/seller/profile/route.ts
Behavior:
- Seller profile edit saves via:
- frontend:
PUT /api/seller/profile - backend:
PUT /api/v1.0/seller/store
- frontend:
- Payload:
storeNamestoreBiography- optional
imageIdwhen seller avatar was uploaded - optional
storeImageIdwhen store image was uploaded
Example payload:
{
"storeName": "...",
"storeBiography": "...",
"imageId": "optional-file-id",
"storeImageId": "optional-file-id"
}
Recent Commits
7e6446bRefine seller onboarding and product review flowse9a0cd0Update product review, measurement, and backend logging flowsb266047Fix TypeScript build errors in product detail and admin review
Main Changes
1. Auth, help, and onboarding
Files:
next.config.tssrc/app/(onboarding)/layout.tsxsrc/app/(auth)/login/page.tsxsrc/app/(auth)/register/verify/page.tsxsrc/app/(auth)/forgot-password/page.tsxsrc/app/(auth)/account-not-found/page.tsxsrc/app/help/page.tsxsrc/app/privacy/page.tsxsrc/app/terms/page.tsx
Behavior:
- Seller onboarding is enabled again
- Seller login redirects incomplete seller profiles to onboarding
- Register verify flow redirects seller to onboarding instead of dashboard
- Forgot password support link opens default mail app to
admin@inatrading.co.id - Forgot password
?button links to public/help - Account-not-found
Bantuan,Kebijakan Privasi, andSyarat & Ketentuanlink to public pages - Login
Remember menow stores email and password in localStorage
2. Onboarding seller final submit flow
Files:
src/app/(onboarding)/onboarding/business/page.tsxsrc/app/(onboarding)/onboarding/store-detail/page.tsxsrc/app/api/seller/route.tssrc/app/api/seller/store/route.tssrc/app/api/warehouses/route.ts
Behavior:
- Plan step was removed from seller onboarding UI flow
Warehouse Typeis hidden in UI and forced toINA- Final onboarding submit is not a single endpoint. It calls, in order:
POST /api/seller-> hostPOST /api/v1.0/sellerPUT /api/seller/store-> hostPUT /api/v1.0/seller/storeGET /api/products/warehouses?page=1&size=100PUT /api/warehouses/{id}orPOST /api/warehouses
- Frontend tries to reuse backend autogenerated warehouse if found, to avoid duplicate warehouse creation
3. Backend proxy logging
Files:
src/lib/backend-fetch-logger.tssrc/instrumentation.ts.env.localusesDEBUG_BACKEND_PROXY=truelocally
Behavior:
- Logs server-side
fetchrequests to backend - Logs request method, URL, headers, body preview
- Logs response status, duration, headers, body preview
- Redacts authorization header
Use this when tracing frontend-to-backend failures in local dev.
4. Product measurement mode on add product
Files:
src/app/(dashboard)/products/new/pricing/page.tsxsrc/lib/use-product-submit.tssrc/app/(dashboard)/products/new/review/page.tsx
Behavior:
- Each model has a
Product Measurementswitch - When enabled:
- nested measurements are shown
- model-level price, currency, weight, dimensions, promotion, packaging, and warehouse stock are disabled
- at least 1 measurement row is required
- Submit payload uses
model.hasMeasurements - When measurement mode is active, model-level numeric fields are zeroed and model warehouses are omitted
5. Product measurement mode on edit product
File:
src/app/(dashboard)/products/[productId]/edit/page.tsx
Behavior:
- Matches add-product measurement behavior
- Uses explicit
hasMeasurementsstate instead of guessing from array length - Disables model-level fields when measurement mode is on
6. Seller product review page improvements
File:
src/app/(dashboard)/products/new/review/page.tsx
Behavior:
- Review now renders actual product thumbnails using backend file URLs
- Previously it only showed image indicators, which was confusing
- Review also reflects measurement-based pricing correctly
7. Product list page improvements
File:
src/app/(dashboard)/products/page.tsxsrc/lib/product-variants.ts
Behavior:
- Edit stock/price modal supports:
- choosing model
- choosing measurement if present
- choosing warehouse
- Warehouse labels use warehouse names from master warehouse API, not raw UUIDs
- Product row status badges now show explicit state like active, draft, review, unpublished, deleted, rejected
- Seller
In Reviewlisting now uses host endpoint/api/v1.0/seller/product/review - If list API returns
minPrice = 0andmaxPrice = 0, frontend hydrates that row by fetching product detail and calculating effective price from model/measurement data
Important:
- This fallback exists because some list rows from backend do not include valid min/max price for measurement-based products
- Example verified case: product
Pembersih Mobilreturned0/0in list butIDR 50.000in detail measurement
8. Product detail page improvements
File:
src/app/(dashboard)/products/[productId]/detail/page.tsxsrc/components/product-variant-showcase.tsxsrc/lib/product-variants.ts
Behavior:
- Main category now resolves even when backend omits
subCategory.category.name - Warehouse display now uses warehouse master names instead of UUID slices
- TypeScript nullability issue for category resolution was fixed here
- Seller detail, admin detail, and admin review now share the same variant presentation logic
- Effective price rules:
- no measurement: use model price
- with measurement: use measurement price
- multiple measurements: show min-max from measurements
- multiple models: show min-max from effective model prices
- Variant showcase now supports:
- product-level summary price/weight/dimension
- model selector
- measurement selector
- selected variant detail
- model image thumbnail switching
9. Admin review page improvements
File:
src/app/admin/review/[productId]/page.tsx
Behavior:
- Review supports model + measurement structures
- New product review and compare review now handle measurement-driven price/weight/dimension/promo/stock
- Compare view highlights updated sections using backend compare response and
isUpdate - Product images are rendered using main image + gallery images
- TypeScript issue around
row.fieldnullability was fixed here - Single-product review view now follows admin product detail layout more closely
- Compare view stays separate only for product update review
- Approve/reject action flow:
- UI
POST /api/admin/review/{productId} - new create accept -> host
POST /api/v1.0/product/accept/{productId}with{ "state": "PUBLISHED" } - update accept -> host
PUT /api/v1.0/product/accept/{productId}with{ "state": "PUBLISHED" } - create reject -> host
POST /api/v1.0/product/reject/{productId} - update reject -> host
PUT /api/v1.0/product/reject/{productId}
- UI
- Review approve does not resubmit full product payload. It only submits action and state.
10. Dashboard shell and search
Files:
src/app/(dashboard)/layout.tsxsrc/app/(dashboard)/dashboard/page.tsx
Behavior:
- Bell and message icons are intentionally grayed/disabled because no backend function exists yet
- Dashboard search now resolves query results across dashboard content instead of behaving like a dead input
11. Sidebar submenu reliability
Files:
src/components/product-submenu-nav.tsxsrc/components/admin-product-submenu-nav.tsx
Behavior:
- Click behavior was hardened because submenu items were sometimes not navigating
- Navigation is explicit via
router.push(...)
Translation Files Touched
src/lib/translations/id.tssrc/lib/translations/en.ts
These include labels added for statuses and stock/price modal UI.
Important Findings
Product image inconsistency on Pembersih Mobil
Verified seller account:
Pendopo@Pendopo.com- password:
password
Product:
Pembersih Mobil- ID:
92a8fae0-d067-4c90-be24-da31012aeaf9
Verified backend behavior:
- list endpoint row returned
minPrice: 0,maxPrice: 0 - detail endpoint returned one measurement priced at
IDR 50.000 - detail endpoint currently returns:
imageId: nullproductImages: []model.imageId: null
Implication:
- product images are currently absent in backend detail payload for this product
- if user reports image visible in older browser tab, suspect stale tab state before assuming frontend regression
Admin review image issue
For at least one reviewed product, backend review payload returned:
image: nullimageId: nullproductImages: []
In that case frontend cannot render images. If an image is missing in review, verify backend review payload before debugging frontend.
Edit product empty main image behavior
In edit product submit flow, empty imageId is currently sent as undefined, which means the field is omitted from JSON payload, not sent as null and not sent as empty string.
If backend requires explicit image removal via null, this behavior will need to be changed.
Seller in-review API note
Postman latest collection contains:
- seller review listing:
/api/v1.0/seller/product/review - generic review detail:
/api/v1.0/product/review/{productId}
Current app matches this for listing and still uses generic review detail endpoint for product review detail.
Local Dev Notes
Run local dev:
npm run dev
Build verification:
npm run build
Dev Server Update Guide
Based on current deployment notes, dev server update flow is:
sudo -iu inadev
cd ~/apps/ina-trading-web
git fetch origin
git checkout main
git pull --ff-only origin main
npm ci
npm run build
pm2 restart ina-trading-dev
pm2 save
sudo -iu inadev pm2 status
Current expected deployed commit after latest push:
2f64282
Verify on server:
git rev-parse HEAD
Optional logs:
sudo -iu inadev pm2 logs ina-trading-dev --lines 100
Suggested Next Checks
- Verify whether backend expects
nullwhen main image is intentionally removed during edit - Verify seller and admin review payload consistency for image fields
- Verify warehouse master API always contains all warehouse IDs referenced in product payloads
- Verify whether seller in-review detail also has a seller-specific detail endpoint in backend/Postman, to align with seller-specific listing endpoint
- Investigate when product images were lost for
Pembersih Mobiland whether edit/update flow can preserve old image ids more defensively - If submenu click issue still appears, inspect layout overlays with browser tooling
- Consider adding field-level compare highlighting, not only section-level highlighting, in admin review compare page
Files Most Likely To Be Relevant Next
src/app/(dashboard)/products/new/pricing/page.tsxsrc/app/(dashboard)/products/[productId]/edit/page.tsxsrc/app/(dashboard)/products/new/review/page.tsxsrc/app/(dashboard)/products/[productId]/detail/page.tsxsrc/app/(dashboard)/products/page.tsxsrc/app/admin/review/[productId]/page.tsxsrc/components/product-variant-showcase.tsxsrc/lib/product-variants.tssrc/lib/use-product-submit.tssrc/lib/backend-fetch-logger.ts