Comprehensive documentation for the API endpoints provided by the Tubes Lasti application. Each endpoint includes details on request payloads, responses, and usage.
Untuk menjalankan pada perangkat lokal, jalankan
npm run start
| Variable | Keterangan |
|---|---|
MONGODB_URI |
Connection string MongoDB |
JWT_SECRET |
Secret penandatangan JWT. Server menolak start kalau kosong. |
PORT |
Port HTTP (default 8080) |
R2_ACCOUNT_ID |
Account ID Cloudflare R2 |
R2_ACCESS_KEY |
Access key ID R2 |
R2_SECRET_KEY |
Secret access key R2 |
R2_BUCKET |
Nama bucket |
R2_PUBLIC_URL |
Base URL publik bucket, dipakai untuk gambar inventory |
Bucket R2 harus punya CORS policy yang mengizinkan PUT dari origin frontend,
karena browser mengunggah langsung ke R2:
[{ "AllowedOrigins": ["https://motoran.vercel.app", "http://localhost:5173"],
"AllowedMethods": ["PUT"],
"AllowedHeaders": ["content-type"],
"MaxAgeSeconds": 3600 }]Untuk membuat docker image backend, jalankan
docker build . -t motoran
Jalankan dengan melakukan run atau menggunakan docker compose
| Method | Endpoint | Usage |
|---|---|---|
| POST | /register |
Membuat account baru |
| POST | /login |
Login dengan account yang telah didaftarkan dan mendapatkan JWT token |
| POST | /login/verify |
Melakukan verifikasi JWT token dan memperbaruinya |
| GET | /profile |
Mendapatkan data diri account yang sedang login |
| PUT | /password |
Mengganti password account yang sedang login |
| POST | /uploads/presign |
Meminta presigned URL untuk mengunggah gambar langsung ke R2 |
| GET | /inventories |
Mendapatkan seluruh inventory yang ada |
| POST | /inventories |
Membuat inventory baru |
| PUT | /inventories/:id |
Mengupdate inventory berdasarkan id |
| DELETE | /inventories/:id |
Menghapus inventory berdasarkan id |
| GET | /orders |
Mendapatkan seluruh order yang pernah dibuat oleh account tertentu |
| GET | /orders/:id |
Mendapatkan order dengan id tertentu |
| POST | /orders |
Membuat order baru |
| PUT | /orders/:id/paidstatus |
Mengubah status pembayaran dari uncomplete menjadi completed |
| PUT | /orders/:id/takenstatus |
Mengubah status pembayaran dari untaken menjadi taken |
| PUT | /orders/:id/returnedstatus |
Mengubah status pembayaran dari unreturned menjadi returned |
| GET | /payment/:id/barcode |
Menghasilkan link yang akan dibuat untuk payment (nantinya di frontend diubah menjadi QR Code) |
| PUT | /payment/:id/pay |
Mengganti status payment menjadi sudah dibayar |
- Description: Creates a new user account.
- Request Body:
{ "name": "string", "email": "string", "password": "string (min. 8 characters)" } - Responses:
- 201 (Success):
{ "status": "success", "message": "Register success", "data": {} } - 400 (Error):
{ "status": "error", "message": "Register error: {error message}", "data": {} }
- 201 (Success):
- Description: Authenticates a user and returns a JWT token.
- Request Body:
{ "email": "string", "password": "string" } - Responses:
- 200 (Success):
{ "status": "success", "message": "Login success", "data": { "user": "email", "token": "string", "isAdmin": "boolean" } } - 400 (Error):
{ "status": "error", "message": "Login error: {error message}", "data": {} }
- 200 (Success):
- Description: Verify existing JWT token and generate the updated one.
- Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "Login success", "data": { "user": "email", "token": "string", "isAdmin": "boolean" } } - 400 (Error):
{ "status": "error", "message": "Login error: {error message}", "data": {} }
- 200 (Success):
- Description: Returns the signed-in account's own details. The password hash is never included.
- Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "GET Profile success", "data": { "profile": { "name": "string", "email": "email", "isAdmin": "boolean" } } } - 404 (User Not Found):
{ "status": "error", "message": "Error GET Profile: User not found", "data": {} }
- 200 (Success):
- Description: Changes the signed-in account's password. The current password must be supplied and is verified before the new one is written.
- Authorization: Bearer Token
- Request Body:
{ "currentPassword": "string", "newPassword": "string (min 8 characters)" } - Notes: Existing tokens are not revoked —
verifyTokenchecks the JWT signature only and never re-reads the user, so any token issued before the change stays valid until it expires. Clients should discard their session and re-authenticate. - Responses:
- 200 (Success):
{ "status": "success", "message": "Password updated successfully", "data": {} } - 400 (Invalid Request): wrong current password, a new password shorter than 8 characters, a new password identical to the current one, or a non-string field.
{ "status": "error", "message": "Error PUT Password: current password is incorrect", "data": {} } - 404 (User Not Found):
{ "status": "error", "message": "Error PUT Password: User not found", "data": {} }
- 200 (Success):
Gambar tidak lagi dikirim ke API. Alurnya tiga langkah:
POST /uploads/presignuntuk mendapatkanuploadUrldankey.PUTberkasnya langsung keuploadUrldengan headerContent-Typeyang sama persis dengan yang diminta pada langkah 1 — header itu ikut ditandatangani, jadi nilai yang berbeda akan ditolak R2.- Kirim
keytersebut kePOST /inventoriesatauPOST /orders.
- Description: Generates a short-lived presigned
PUTURL for a direct browser upload. - Authorization: Bearer Token
- Request Body:
{ "folder": "inventories | idcards", "contentType": "image/png | image/jpeg", "filename": "string (dipakai hanya untuk mengambil ekstensi)" } - Notes:
folder: "inventories"hanya untuk admin.- Hanya
image/*dengan ekstensi.png,.jpg,.jpeg. keydiacak (UUID), bukan dari nama berkas asli.- URL berlaku 300 detik. Objek di atas 5 MB akan ditolak dan dihapus saat
keydipakai.
- Responses:
- 201 (Success):
{ "status": "success", "message": "Upload URL generated successfully", "data": { "uploadUrl": "https://<bucket>.<account>.r2.cloudflarestorage.com/...", "key": "idcards/8f2c....png", "expiresIn": 300 } } - 403 (Forbidden): folder
inventoriesdiminta oleh non-admin. - 422 (Rejected):
{ "status": "error", "message": "Error POST Presign: Mimetype application/pdf is not allowed", "data": {} }
- 201 (Success):
- Description: Retrieves all available inventory items. Selalu
200; daftar kosong dikembalikan sebagai array kosong. - Responses:
- 200 (Success):
{ "status": "success", "message": "GET inventories success", "data": { "inventories": [/* Array of Inventory */] } } - 400 (Error):
{ "status": "error", "message": "Error GET Inventory: {error message}", "data": {} }
- 200 (Success):
- Description: Creates a new inventory item.
- Authorization: Bearer Token
- Header: Content-Type: application/json
- Request Body:
imageadalahkeydariPOST /uploads/presign.{ "name": "string", "type": "Skuter | Sport", "image": "inventories/....png", "fuel": "integer", "transmission": "Matic | Manual", "capacity": "integer", "price": "integer", "total": "integer", "available": "integer" } - Responses:
- 201 (Success):
{ "status": "success", "message": "Inventory created successfully.", "data": { "inventories": { /* Saved Inventory */ } } } - 400 (Error):
{ "status": "error", "message": "Error POST Inventory: {error message}", "data": {} }
- 201 (Success):
- Description: Updates an inventory item by ID. Seperti
POST, bilaimagedikirim sebagai object key hasil/uploads/presignia diverifikasi lalu disimpan sebagai URL publik;imageyang sudah berupahttps://diteruskan apa adanya. Kolom lain diteruskan ke dokumen tanpa diubah. - Authorization: Bearer Token (admin)
- Responses:
- 200 (Success):
{ "status": "success", "message": "Inventory updated successfully.", "data": { "inventories": { /* Updated Inventory */ } } } - 400 (Error):
{ "status": "error", "message": "Error PUT Inventory: {error message}", "data": {} } - 422 (Error): unggahan
imageditolak (mime, ekstensi, ukuran, atau object tidak ditemukan).
- 200 (Success):
- Description: Deletes an inventory item by ID. Ditolak selama masih ada
orderStatusdenganreturnStatus: "unreturned"yang menunjuk motor ini, karenamotorIddisimpan sebagai string lepas tanpa relasi. - Authorization: Bearer Token (admin)
- Responses:
- 200 (Success):
{ "status": "success", "message": "Inventory deleted successfully.", "data": { "inventories": { /* Deleted Inventory */ } } } - 403 (Error): bukan admin.
- 404 (Error): inventory tidak ditemukan.
- 409 (Error):
{ "status": "error", "message": "Error DELETE Inventory: {n} unreturned order(s) still reference this inventory", "data": {} }
- 200 (Success):
- Description: Retrieves all orders for a specific user.
- Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "GET Orders success", "data": { "orders": [ /* Array of Orders */ ] } } - 400 (Error):
{ "status": "error", "message": "Error GET Order: {error message}", "data": {} }
- 200 (Success):
- Description: Retrieves a single order status.
:idadalah_idmilik subdokumenorderStatus, bukan_iddokumenOrder. - Authorization: Bearer Token
- Responses:
- 200 (Success):
order.idCardberupa presigned URL berumur 300 detik.{ "status": "success", "message": "GET order by ID success", "data": { "order": { /* Order Status */ } } } - 404 (Not Found):
{ "status": "error", "message": "Error GET Order by ID: Order not found", "data": {} } - 400 (Error):
{ "status": "error", "message": "Error GET Order: {error message}", "data": {} }
- 200 (Success):
- Description: Creates a new order.
- Authorization: Bearer Token
- Header: Content-Type: application/json
- Request Body:
idCardKeyadalahkeydariPOST /uploads/presign.{ "phone": "string", "idCardKey": "idcards/....jpg", "startDate": "string (ISO format)", "endDate": "string (ISO format)", "motorId": "string" } - Responses:
- 201 (New Order Created):
{ "status": "success", "message": "Order created successfully.", "data": { "order": { /* New Order Data */ } } } - 200 (Order Updated):
{ "status": "success", "message": "Order status added successfully.", "data": { "order": { /* Updated Order */ } } } - 400 (Invalid Input):
{ "status": "error", "message": "Invalid input: {error message}", "data": {} }
- 201 (New Order Created):
- Description: Updates payment status of an order to
completed. - Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "Payment status updated to completed", "data": { "order": { /* Updated Order */ } } } - 404 (Order Not Found):
{ "status": "error", "message": "Error PUT Order: Order status not found", "data": {} } - 400 (Error):
{ "status": "error", "message": "Error PUT Order: {error message}", "data": {} }
- 200 (Success):
- Description: Updates taken status of an order to
taken, and stampstakenAtwith the current time. - Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "Taken status updated to completed", "data": { "order": { /* Updated Order */ } } } - 404 (Order Not Found):
{ "status": "error", "message": "Error PUT Order: Order status not found", "data": {} } - 400 (Error):
{ "status": "error", "message": "Error PUT Order: {error message}", "data": {} }
- 200 (Success):
- Description: Updates return status of an order to
returned, and stampsreturnedAtwith the current time. Rejected whiletakenStatusis stilluntaken— a vehicle cannot come back before it has been picked up. - Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "Returned status updated to completed", "data": { "order": { /* Updated Order */ } } } - 404 (Order Not Found):
{ "status": "error", "message": "Error PUT Order: Order status not found", "data": {} } - 409 (Not Taken Yet):
{ "status": "error", "message": "Error PUT Order: cannot mark returned while takenStatus is untaken", "data": {} } - 400 (Error):
{ "status": "error", "message": "Error PUT Order: {error message}", "data": {} }
- 200 (Success):
Kedua endpoint hanya bisa diakses oleh customer pemilik order, bukan admin.
:id adalah _id milik subdokumen orderStatus.
- Description: Returns the order together with the URL that the payment QR code should encode.
- Authorization: Bearer Token
- Responses:
- 200 (Success):
order.idCardberupa presigned URL berumur 300 detik.{ "status": "success", "message": "Barcode link generated successfully", "data": { "order": { /* Order Status */ }, "payment_url": "https://api-motoran.faizath.com/payment/12345/pay" } } - 403 (Forbidden):
{ "status": "error", "message": "Error GET Payment: Only customer can access payment", "data": {} } - 404 (Not Found):
{ "status": "error", "message": "Error GET Payment: Order not found", "data": {} }
- 200 (Success):
- Description: Marks the order as paid.
- Authorization: Bearer Token
- Responses:
- 200 (Success):
{ "status": "success", "message": "Payment status updated to completed", "data": { "order": { /* Updated Order */ } } } - 403 (Forbidden):
{ "status": "error", "message": "Error PUT Payment: Unauthorized", "data": {} } - 404 (Not Found):
{ "status": "error", "message": "Error PUT Payment: Order not found", "data": {} }
- 200 (Success):