# CGS Ticketing System
[](https://hackmd.io/uQiD6fYoTu-GiTQi8UmH2g)
[Postman Documentation](https://documenter.getpostman.com/view/15316813/UVR7MUBi)
## An API Contract
API contract for CGS ticketing system. Host this API in a subdomain, e.g.: `api-ticket-system.cgs.co.id`.
Not to be confused, in this API contract document, all data is represented in JavaScript Objects.
## Enum
### UserRoleEnum
| Name |
| -------------- |
| `SuperAdmin` |
| `NOC` |
| `FOC` |
| `FOCSupervisor` |
### TicketStatusNameEnum
| Name |
| ------------ |
| `Open` |
| `Draft` |
| `Accepted` |
| `OnTheWay` |
| `CheckedIn` |
| `OnGoing` |
| `Closed` |
| `Canceled` |
| `Pending` |
### TaskStatusNameEnum
| Name |
| --------------- |
| `Checking` |
| `PullingCable` |
| `Jointing` |
| `Tidying` |
| `LinkChecking` |
| `Finishing` |
### TicketTypeEnum
| Name |
| --------------- |
| `Trouble` |
| `Maintenance` |
### TicketSourceEnum
| Name |
| ----------- |
| `Whatsapp` |
| `Telegram` |
| `Email` |
| `Phone` |
| `DeviceLog` |
### RegionEnum
| Name |
| ---------- |
| `West` |
| `Central` |
| `East` |
### IndicationCategoryEnum
| Name |
| -------------- |
| `FiberCut` |
| `Bending` |
| `Device` |
| `Electricity` |
### ClientStatusEnum
| Name |
| ------------ |
| `Active` |
| `Deactive` |
| `Dismantle` |
### CustomerTypeEnum
| Name |
| ------------ |
| `Dedicated` |
| `Broadband` |
### NetworkSegmentEnum
| Name |
| ----------- |
| `Access` |
| `Fishbone` |
| `Backbone` |
### ServiceTypeEnum
| Name |
| ------------------ |
| `Interconnection` |
| `FTTX` |
### BandwidthUnitEnum
| Name |
| ------- |
| `Gbps` |
| `Mbps` |
### PendingCategory
| Name |
| ------- |
| ` ` |
| ` ` |
### CardTypeEnum
| Name |
| -------------------------- |
| `SimpleStatus` |
| `RequestValidationAction` |
| `RequestValidationDone` |
| `FinishingAction` |
| `ReassignAction` |
### SlaTypeEnum
| Name |
| ------------ |
| `UnderSla` |
| `OverSla` |
| `NonSla` |
## Firestore Collection
### `tickets`
This collection contains formatted ticket documents. All user can access the collection depending on their role:
- FOC can only get ticket which its `latestStatus` is `Open` and in the same region, or its `foc` is the user
- FOC Supervisor behaves the same as FOC. In addition, FOC Supervisor can get all on going ticket in the same region and can assign an FOC to a ticket
- NOC can only get ticket in the same region
- SuperAdmin can get all ticket
Note that this is a direct connection between frontend app (web or mobile) and firestore. The firestore rule should not allow any write operations.
**Authentication and Authorization:**
Implement authentication using backend server. Frontend app first login to backend server to get token (preferably JWT) and then perform authorization to firestore.
**Structure:**
```
interface Ticket {
acceptedDuration: Number,
acceptedTime: string,
action: String || null,
checkInTime: string,
createdAt: Date,
departureTime: string,
documentId: DocumentId,
indication: String,
indicationCategory: IndicationCategoryEnum,
inProgressByFoc: Boolean,
isDraft: Boolean,
isLastLinkChecking: Boolean,
latestStatus: TicketStatusNameEnum,
locationRemark: String || null,
needReassign: Boolean,
needValidate: Boolean,
networkSegment: NetworkSegmentEnum,
onGoingTime: string,
onTheWayDuration: Number,
publishedAt: Date,
region: RegionEnum,
remark: String || null,
sla: Integer,
slaType: SlaType,
source: TicketSourceEnum,
ticketId: String,
totalPendingDuration: Number,
totalTime: Number,
type: TicketTypeEnum,
updatedAt: Date,
workDuration: Number,
contactPerson: [{
name: String,
phone: String,
}],
foc: {
id: UUID,
nik: String,
phoneNumber: String,
email: String,
name: String,
role: UserRoleEnum,
region: RegionEnum,
profilePhoto: String,
areas: [
{
id: UUID,
name: String,
region: String,
initial: String,
}
],
} || null,
noc: {
id: UUID,
nik: String,
email: String,
name: String,
role: UserRoleEnum,
region: RegionEnum,
profilePhoto: String,
phoneNumber: String,
areas: [],
},
client: {
id: UUID || null,
cid: String || null, // Derived from Ticket.cid
name: String || 'Non SLA', // Derived from Ticket.endUser
address: String, // Derived from Ticket.clientLocation
coordinate: String, // Derived from Ticket.deviceLocation
city: Area,
customerType: CustomerTypeEnum, // Derived from Ticket.customerType
pop: { // Derived from Ticket.pop*
name: String,
coordinate: String,
} || null,
ms: { // Derived from Ticket.ms*
name: String,
coordinate: String,
} || null,
splitter: { // Derived from Ticket.splitter*
name: String,
coordinate: String,
} || null,
isp: {
name: String,
brand: String,
initial: String,
} || null,
},
ticketLogs: [
{
cardType: 'SimpleStatus',
timestamp: Date,
bubbleOption: {
photoUrl: String,
name: String,
},
title: String,
description: String,
statusName: TicketStatusNameEnum || TaskStatusNameEnum,
data: {
mediaUrl?: String,
locationCoordinate?: String,
}
} || {
cardType: 'RequestValidationAction',
evidenceId: UUID,
timestamp: Date,
bubbleOption: {
photoUrl: String,
name: String,
},
title: String,
description: String,
descriptionFields: [{
name: String,
text: String,
}],
statusName: TicketStatusNameEnum || TaskStatusNameEnum,
data: {
mediaUrl?: String,
locationCoordinate?: String,
}
} || {
cardType: 'RequestValidationDone',
timestamp: Date,
bubbleOption: {
photoUrl: String,
name: String,
},
title: String,
description: String,
descriptionFields: [{
name: String,
text: String,
}],
statusName: TicketStatusNameEnum || TaskStatusNameEnum,
data: {
mediaUrl?: String,
locationCoordinate?: String,
}
} || {
cardType: 'ReassignAction',
evidenceId: UUID,
timestamp: Date,
bubbleOption: {
photoUrl: String,
name: String,
},
title: String,
description: String,
descriptionFields: [{
name: String,
text: String,
}],
focBeforeReassigned: {
email: String,
id: String,
name: String,
nik: String,
region: String,
role: String,
},
statusName: TicketStatusNameEnum || TaskStatusNameEnum,
data: {
mediaUrl?: String,
locationCoordinate?: String,
}
}
],
}
```
**TicketLogs:**
These additional fields **must exist** in `TicketLog` depending on its `statusName`.
- `CheckedIn`, `Closed`, `Canceled`, `Finishing`, and `LinkChecking`
```
{
..., // other fields mentioned above
evidenceId: UUID,
needApproval: true,
isApproved: Boolean || null,
remark: String || null,
approvalRemark: String || null,
locationCoordinate: String || null,
mediaUrl: String || null,
}
```
- `Checking`, `PullingCable`, `Jointing`, `Tidying`
```
{
..., // other fields mentioned above
evidenceId: UUID,
needApproval: false,
remark: String || null,
locationCoordinate: String || null,
mediaUrl: String || null,
}
```
- `Pending`
```
{
..., // other fields mentioned above
evidenceId: UUID,
needApproval: true,
isApproved: Boolean || null,
remark: String || null,
approvalRemark: String || null,
locationCoordinate: String || null,
mediaUrl: String || null,
pendingInterval: Number,
pendingCategory: PendingCategory,
isResumed: Boolean,
}
```
- `Open`, `Draft`, `Accepted`, `OnTheWay`, `OnGoing`
```
{
..., // other fields mentioned above
needApproval: false,
}
```
### `ticketcount`
This collection stores ticket count in one month. This is used to create `ticketId`.
**Structure:**
```
{
count: Number, // total tickets number in the month
month: String, // name of the month ['January', 'February', ...]
year: Number, // year in integer
}
```
## API
Authentication
---
Using statefull authentication. So that backend should return response with header `Set-Cookie` to set `session_id`.
1. Login
`POST /v1/login`
Login to system
##### Request:
```
{
email: 'email@website.com',
password: 'password',
{
```
##### Response: `200`
```
{
statusCode: 200,
data: {
token: 'abcdefg',
iat: 123456789,
exp: 234567899,
}
{
```
2. Logout
`GET /v1/logout`
Logout from system
##### Params: -
##### Response: `200`
```
{
statusCode: 200,
{
```
Master Data
---
### User
1. Register New User
`POST /v1/users`
Super Admin creates a new user (register)
##### Request:
```
{
email: 'email@web.com',
password: 'noc123',
rePassword: 'noc123',
nik: '12345678910',
name: 'NOC User One',
role: <UserRoleEnum>,
region: <RegionEnum>,
area: BANDUNG,
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
{
```
##### Response: `201`
Returns newly created user
```
{
statusCode: 201,
data: {
result: {
id: '4eaf933a-17e1-4d17-84f8-8d6d070ebae6'
email: 'email@web.com',
nik: '12345678910',
name: 'NOC User One',
role: 'NOC',
region: 'West',
area: 'BANDUNG',
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
}
}
{
```
2. Get All User
`GET /v1/users`
Get all users
##### Query Params:
```
orderBy
sortBy
limit
```
##### Response: `200`
Returns user's detail
```
{
statusCode: 200,
data: {
result: {
id: '4eaf933a-17e1-4d17-84f8-8d6d070ebae6'
email: 'email@web.com',
nik: '12345678910',
name: 'NOC User One',
role: 'NOC',
region: 'West',
area: 'BANDUNG',
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
}
}
{
```
2. Get Detail User
`GET /v1/users/:id`
Get a user's detail
##### Params:
```
-
```
##### Response: `200`
Returns user's detail
```
{
statusCode: 200,
data: {
result: {
id: '4eaf933a-17e1-4d17-84f8-8d6d070ebae6'
email: 'email@web.com',
nik: '12345678910',
name: 'NOC User One',
role: 'NOC',
region: 'West',
area: 'BANDUNG',
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
}
}
{
```
3. Update User
`PUT /v1/users/:id`
Super Admin updates a user
##### Request:
```
{
email: 'email@web.com',
password: 'noc123',
rePassword: 'noc123',
nik: '12345678910',
name: 'NOC User One',
role: <UserRoleEnum>,
region: <RegionEnum>,
area: BANDUNG,
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
{
```
##### Response: `200`
Returns updated user's detail
```
{
statusCode: 200,
data: {
result: {
id: '4eaf933a-17e1-4d17-84f8-8d6d070ebae6'
email: 'email@web.com',
nik: '12345678910',
name: 'NOC User One',
role: 'NOC',
region: 'West',
area: 'BANDUNG',
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
}
}
{
```
4. Delete a User
`DELETE /v1/users/:id`
Super Admin deletes a user
##### Request:
```
-
```
##### Response: `200`
Returns deleted user's detail
```
{
statusCode: 200,
data: {
result: {
id: '4eaf933a-17e1-4d17-84f8-8d6d070ebae6'
email: 'email@web.com',
nik: '12345678910',
name: 'NOC User One',
role: 'NOC',
region: 'West',
area: 'BANDUNG',
profilePhoto: 'https://blabla.com/photo.jpg',
phoneNumber: '0812345678',
}
}
{
```
### Area
1. Add Area
`POST /v1/areas`
Super Admin adds a new area
##### Request:
```
{
region: <RegionEnum>,
name: 'BANDUNG',
initial: 'BDG',
{
```
##### Response: `201`
Returns newly created area
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
region: <RegionEnum>,
name: 'BANDUNG',
initial: 'BDG',
}
}
{
```
2. Get Detail Area
`GET /v1/areas/:id`
Get an area's detail
##### Params:
```
-
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
region: <RegionEnum>,
name: 'BANDUNG',
initial: 'BDG',
}
}
{
```
3. Update Area
`PUT /v1/areas/:id`
Super Admin updates an area
##### Request:
```
{
region: <RegionEnum>,
name: 'BANDUNG',
initial: 'BDG',
{
```
##### Response: `200`
Returns updated area's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
region: <RegionEnum>,
name: 'BANDUNG',
initial: 'BDG',
}
}
{
```
4. Delete an Area
`DELETE /v1/areas/:id`
Super Admin deletes an area
##### Request:
```
-
```
##### Response: `200`
Returns deleted area's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
region: <RegionEnum>,
name: 'BANDUNG',
initial: 'BDG',
}
}
{
```
### MainSplitter
1. Add Main Splitter
`POST /v1/main_splitters`
Super Admin adds a new main splitter
##### Request:
```
{
name: 'MAKMUR',
coordinate: '1.23124123151,-0.32413123',
{
```
##### Response: `201`
Returns newly created main splitter
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'MAKMUR',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
2. Get Detail Main Splitter
`GET /v1/main_splitters/:id`
Get main splitter's detail
##### Params:
```
-
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'MAKMUR',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
3. Update Main Splitter
`PUT /v1/main_splitters/:id`
Super Admin updates main splitter
##### Request:
```
{
name: 'MAKMUR',
coordinate: '1.23124123151,-0.32413123',
{
```
##### Response: `200`
Returns updated main splitter's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'MAKMUR',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
4. Delete a Main Splitter
`DELETE /v1/main_splitters/:id`
Super Admin deletes a main splitter
##### Request:
```
-
```
##### Response: `200`
Returns deleted main splitter's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'MAKMUR',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
### Splitter
1. Add Splitter
`POST /v1/splitters`
Super Admin adds a new splitter
##### Request:
```
{
name: 'PALLADIUM',
coordinate: '1.23124123151,-0.32413123',
{
```
##### Response: `201`
Returns newly created splitter
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'PALLADIUM',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
2. Get Detail Splitter
`GET /v1/splitters/:id`
Get splitter's detail
##### Params:
```
-
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'PALLADIUM',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
3. Update Splitter
`PUT /v1/splitters/:id`
Super Admin updates splitter
##### Request:
```
{
name: 'PALLADIUM',
coordinate: '1.23124123151,-0.32413123',
{
```
##### Response: `200`
Returns updated splitter's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'PALLADIUM',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
4. Delete a Splitter
`DELETE /v1/splitters/:id`
Super Admin deletes a splitter
##### Request:
```
-
```
##### Response: `200`
Returns deleted splitter's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'PALLADIUM',
coordinate: '1.23124123151,-0.32413123',
}
}
{
```
### ISP
1. Add ISP
`POST /v1/isps`
Super Admin adds a new ISP
##### Request:
```
{
name: 'ADIDAYA INFOCOM LESTARI, PT / AIL / WIZNET',
initial: 'AIL',
brand: 'WIZNET',
{
```
##### Response: `201`
Returns newly created main ISP
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'ADIDAYA INFOCOM LESTARI, PT / AIL / WIZNET',
initial: 'AIL',
brand: 'WIZNET',
}
}
{
```
2. Get Detail ISP
`GET /v1/isps/:id`
Get ISP's detail
##### Params:
```
-
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'ADIDAYA INFOCOM LESTARI, PT / AIL / WIZNET',
initial: 'AIL',
brand: 'WIZNET',
}
}
{
```
3. Update ISP
`PUT /v1/isps/:id`
Super Admin updates ISP
##### Request:
```
{
name: 'PALLADIUM',
initial: 'AIL',
brand: 'WIZNET',
{
```
##### Response: `200`
Returns updated ISP's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'PALLADIUM',
initial: 'AIL',
brand: 'WIZNET',
}
}
{
```
4. Delete a ISP
`DELETE /v1/isps/:id`
Super Admin deletes a ISP
##### Request:
```
-
```
##### Response: `200`
Returns deleted ISP's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
name: 'PALLADIUM',
initial: 'AIL',
brand: 'WIZNET',
}
}
{
```
### Indication
1. Add Indication
`POST /v1/indications`
Super Admin adds a new indication
##### Request:
```
{
category: <IndicationCategoryEnum>,
indication: 'Ketabrak truk',
{
```
##### Response: `201`
Returns newly created indication
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
category: 'FiberCut',
indication: 'Ketabrak truk',
}
}
{
```
2. Get Detail Indication
**Get Indication by id**
`GET /v1/indications/:id`
Get indication's detail
##### Params:
```
id: UUID
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
category: 'FiberCut',
indication: 'Ketabrak truk',
}
}
{
```
**Get Indication by Category**
`GET /v1/indications/?category=<IndicationCategoryEnum>`
List indications by category
##### Query Params:
```
category: IndicationCategoryEnum
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
category: 'FiberCut',
indication: 'Ketabrak truk',
}
}
{
```
3. Update Indication
`PUT /v1/indications/:id`
Super Admin updates indication
##### Request:
```
{
category: <IndicationCategoryEnum>,
indication: 'Ketabrak singa',
{
```
##### Response: `200`
Returns updated indication's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
category: 'FiberCut',
indication: 'Ketabrak singa',
}
}
{
```
4. Delete an Indication
`DELETE /v1/indications/:id`
Super Admin deletes an indication
##### Request:
```
-
```
##### Response: `200`
Returns deleted indication's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
category: 'FiberCut',
indication: 'Ketabrak singa',
}
}
{
```
### Client
1. Add Client
`POST /v1/clients`
Super Admin adds a new client
##### Request:
```
{
cid: String,
customerType: <CustomerTypeEnum>,
pop: String,
name: String,
userCode: String,
isp: <ISP>,
status: <ClientStatusEnum>,
region: <RegionEnum>,
city: <Area>,
address: String,
coordinate: String,
activeDate: Date,
service: <ServiceTypeEnum>,
bandwidth: Float,
bandwidthUnit: <BandwidthUnitEnum>,
ms: <MainSplitter>,
splitter: <Splitter>,
deviceType: String,
macAddress: String,
signal: String,
vlan: String,
ipMonitoring: String,
epon: String,
remark: String,
{
```
##### Response: `201`
Returns newly created client
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
cid: String,
customerType: <CustomerTypeEnum>,
pop: String,
name: String,
userCode: String,
isp: <ISP>,
status: <ClientStatusEnum>,
region: <RegionEnum>,
city: <Area>,
address: String,
coordinate: String,
activeDate: Date,
service: <ServiceTypeEnum>,
bandwidth: Float,
bandwidthUnit: <BandwidthUnitEnum>,
ms: <MainSplitter>,
splitter: <Splitter>,
deviceType: String,
macAddress: String,
signal: String,
vlan: String,
ipMonitoring: String,
epon: String,
remark: String,
}
}
{
```
2. Get Detail Client
`GET /v1/clients/:id`
Get client's detail
##### Params:
```
-
```
##### Response: `200`
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
cid: String,
customerType: <CustomerTypeEnum>,
pop: String,
name: String,
userCode: String,
isp: <ISP>,
status: <ClientStatusEnum>,
region: <RegionEnum>,
city: <Area>,
address: String,
coordinate: String,
activeDate: Date,
service: <ServiceTypeEnum>,
bandwidth: Float,
bandwidthUnit: <BandwidthUnitEnum>,
ms: <MainSplitter>,
splitter: <Splitter>,
deviceType: String,
macAddress: String,
signal: String,
vlan: String,
ipMonitoring: String,
epon: String,
remark: String,
}
}
{
```
3. Update Client
`PUT /v1/clients/:id`
Super Admin updates client
##### Request:
```
{
cid: String,
customerType: <CustomerTypeEnum>,
pop: String,
name: String,
userCode: String,
isp: <ISP>,
status: <ClientStatusEnum>,
region: <RegionEnum>,
city: <Area>,
address: String,
coordinate: String,
activeDate: Date,
service: <ServiceTypeEnum>,
bandwidth: Float,
bandwidthUnit: <BandwidthUnitEnum>,
ms: <MainSplitter>,
splitter: <Splitter>,
deviceType: String,
macAddress: String,
signal: String,
vlan: String,
ipMonitoring: String,
epon: String,
remark: String,
{
```
##### Response: `200`
Returns updated client's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
cid: String,
customerType: <CustomerTypeEnum>,
pop: String,
name: String,
userCode: String,
isp: <ISP>,
status: <ClientStatusEnum>,
region: <RegionEnum>,
city: <Area>,
address: String,
coordinate: String,
activeDate: Date,
service: <ServiceTypeEnum>,
bandwidth: Float,
bandwidthUnit: <BandwidthUnitEnum>,
ms: <MainSplitter>,
splitter: <Splitter>,
deviceType: String,
macAddress: String,
signal: String,
vlan: String,
ipMonitoring: String,
epon: String,
remark: String,
}
}
{
```
4. Delete an Client
`DELETE /v1/clients/:id`
Super Admin deletes a client
##### Request:
```
-
```
##### Response: `200`
Returns deleted client's detail
```
{
statusCode: 200,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
cid: String,
customerType: <CustomerTypeEnum>,
pop: String,
name: String,
userCode: String,
isp: <ISP>,
status: <ClientStatusEnum>,
region: <RegionEnum>,
city: <Area>,
address: String,
coordinate: String,
activeDate: Date,
service: <ServiceTypeEnum>,
bandwidth: Float,
bandwidthUnit: <BandwidthUnitEnum>,
ms: <MainSplitter>,
splitter: <Splitter>,
deviceType: String,
macAddress: String,
signal: String,
vlan: String,
ipMonitoring: String,
epon: String,
remark: String,
}
}
{
```
Ticket Management
---
### Ticket
1. Create Ticket
`POST /v1/tickets`
NOC creates new ticket
##### Requests:
```
{
client: UUID || null,
type: TicketTypeEnum,
source: TicketSourceEnum,
isDraft: Boolean,
publishedAt: Date || null,
address: String,
contactPerson: [{
name: String,
phone: String,
}],
customerType: CustomerTypeEnum,
indicationCategory: IndicationCategoryEnum,
networkSegment: NetworkSegmentEnum,
remark: String || null,
msName: String,
msLocation: String,
splitterName: String,
splitterLocation: String,
}
```
##### Response: `201`
Response body contains only the following fields
```
{
statusCode: 201,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
id: UUID,
ticketId: String,
region: RegionEnum,
endUser: String,
lastStatus: String || null,
}
}
{
```
2. Get Ticket List Items
`GET /v1/tickets`
Get ticket list items
##### Params:
Filters:
```
{
region: RegionEnum,
area: Area || null,
type: TicketTypeEnum || null,
endUser: String || null,
latestStatus: TaskStatusNameEnum || null,
agingTime: 'under' || 'over' || 'non' || null,
}
```
##### Response: `200`
Response body contains only the following fields
```
{
statusCode: 202,
data: {
result: {
createdAt: '2027-04-07T20:09:59.884Z',
updatedAt: '2027-04-07T20:09:59.884Z',
id: UUID,
ticketId: String,
region: RegionEnum,
endUser: String,
lastStatus: String || null,
}
}
{
```
3. Update Status Request
To update status of a ticket, we should segregate endpoints into smaller scopes:
`POST /v1/tickets/:id/{ticketStatus,taskStatus}/:type`
##### ticketStatus:
###### accepted
`POST /v1/tickets/:id/ticketStatus/accept`
When an FOC receive broadcast of a new ticket, he can accept it by hitting the endpoint using POST method without body. The ticket must be in `Open` state.
Params:
```
id: string
```
Requests: -
Response:
```
{
statusCode: 201,
data: {
result: {
id: UUID,
createdAt: Date,
updatedAt: Date,
}
}
{
```
###### onTheWay
`POST /v1/tickets/:id/ticketStatus/onTheWay`
When an FOC has accepted a ticket, he then clicks the on the way button. The endpoint accepts POST method without body.
Params:
```
id: string
```
Requests: -
Response:
```
{
statusCode: 201,
data: {}
{
```
###### checkedIn (validation required)
`POST /v1/tickets/:id/ticketStatus/checkedIn`
When an FOC has arrived at the location, he then checks in to the system by hitting camera button check in button. The mobile app should first upload the media taken by FOC to storage server and get the url. Then the mobile app send request to the endpoint using POST method along with validation data in the body.
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
locationCoordinate: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
###### pending (validation required)
**Request Pending**
`POST /v1/tickets/:id/ticketStatus/pending`
This endpoint can be hit by both NOC and FOC but the behavior is different depending on the role. When FOC is requesting pending, it requires validation by NOC. In contrast, NOC can also set pending status without requiring any approval. In order to request pending status, ticket status (`latestStatus`) must be in between `Accepted` and `OnGoing` inclusively.
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
pendingCategory: PendingCategory,
pendingInterval: Number, // minute in integer
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
**Resume Pending**
`POST /v1/tickets/:id/ticketStatus/resume`
This endpoint can be hit by both NOC and FOC. Success if there is an ongoing pending. Backend must implements to change `pendingInterval` value to `min(pendingInterval, deltaTime)` where `deltaTime` is interval between now and `timestamp` of approved pending.
Params:
```
id: string
```
Requests: -
Response:
```
{
statusCode: 201,
data: {}
{
```
###### canceled (validation required)
`POST /v1/tickets/:id/ticketStatus/cancel`
This endpoint can be hit by both NOC and FOC but the behavior is different depending on the role. When FOC is requesting cancelling, it requires validation by NOC. In contrast, NOC can also set pending status without requiring any approval. In order to request pending status, ticket status (`latestStatus`) can be anything exept `Closed`. If the request is approved (see: Validate Status Change Request), system will mark ticket as `Closed`.
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
cancelCategory: CancelCategory,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
##### taskStatus:
###### checking
`POST /v1/tickets/:id/taskStatus/checking`
FOC changes ticket's task status to `Checking`
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
###### pullingCable
`POST /v1/tickets/:id/taskStatus/pullingCable`
FOC changes ticket's task status to `PullingCable`
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
###### jointing
`POST /v1/tickets/:id/taskStatus/jointing`
FOC changes ticket's task status to `Jointing`
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
###### tidying
`POST /v1/tickets/:id/taskStatus/tidying`
FOC changes ticket's task status to `Tidying`
Requests:
```
{
mediaUrl: String,
remark: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
###### linkChecking (validation required)
`POST /v1/tickets/:id/taskStatus/Lequired`
FOC changes ticket's task status to `LinkChecking`
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
###### finishing (validation required)
`POST /v1/tickets/:id/taskStatus/finishing`
In order to request closing ticket, ticket must have task status `LinkChecking` and must be approved (`isApproved == true`). If the request is approved (see: Validate Status Change Request), system will mark ticket as `Closed`.
Params:
```
id: string
```
Requests:
```
{
mediaUrl: String,
remark: String,
locationCoordinate: String,
}
```
Response:
```
{
statusCode: 201,
data: {}
{
```
4. Validate Status Change Request
`POST /v1/tickets/:id/validate/:evidenceId/:approved`
NOC validates a request validation of ticket status or task status. This endpoint is used in every validation (any status that needs validation from NOC).
Params:
```
approved: Boolean
```
Response:
```
{
statusCode: 200,
data: {}
{
```