# SmartStack Postman Templates

> **Note:** These templates are used to automatically generate Postman tests
> after creating a controller.

---

## Structure Collection Postman

```json
{
  "name": "{Module} API",
  "item": [
    // Tests GET list
    // Tests GET single
    // Tests POST create
    // Tests PUT update
    // Tests PATCH activate/deactivate
    // Tests DELETE
  ]
}
```

---

## Available Test Users

| User | Email | Password | Permissions |
|------|-------|----------|-------------|
| SuperAdmin | `superadmin@smartstack.test` | `SuperAdmin123!` | `*` (all) |
| PlatformAdmin | `platformadmin@smartstack.test` | `PlatformAdmin123!` | `platform.administration.*` |
| User | `user@smartstack.test` | `User123!` | Standard |
| ReadOnly | `readonly@smartstack.test` | `ReadOnly123!` | `*.read` only |
| NoPerm | `noperm@smartstack.test` | `NoPerm123!` | None |
| Inactive | `inactive@smartstack.test` | `Inactive123!` | Disabled account |

---

## Template Test GET List (200)

```json
{
  "name": "GET {module} - With SuperAdmin Token (200)",
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "exec": [
          "const baseUrl = pm.collectionVariables.get('baseUrl');",
          "",
          "pm.sendRequest({",
          "    url: baseUrl + '/api/auth/login',",
          "    method: 'POST',",
          "    header: { 'Content-Type': 'application/json' },",
          "    body: {",
          "        mode: 'raw',",
          "        raw: JSON.stringify({",
          "            email: 'superadmin@smartstack.test',",
          "            password: 'SuperAdmin123!'",
          "        })",
          "    }",
          "}, function (err, res) {",
          "    if (err) {",
          "        console.error('Login failed:', err);",
          "        return;",
          "    }",
          "    const response = res.json();",
          "    pm.collectionVariables.set('accessToken', response.token);",
          "    pm.collectionVariables.set('currentUser', 'superadmin');",
          "});"
        ],
        "type": "text/javascript"
      }
    },
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 200', function () {",
          "    pm.response.to.have.status(200);",
          "});",
          "",
          "pm.test('Response has items array', function () {",
          "    const response = pm.response.json();",
          "    pm.expect(response).to.have.property('items');",
          "    pm.expect(response.items).to.be.an('array');",
          "});",
          "",
          "pm.test('Response has pagination info', function () {",
          "    const response = pm.response.json();",
          "    pm.expect(response).to.have.property('totalCount');",
          "    pm.expect(response).to.have.property('page');",
          "    pm.expect(response).to.have.property('pageSize');",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "GET",
    "header": [
      {
        "key": "Authorization",
        "value": "Bearer {{accessToken}}",
        "type": "text"
      }
    ],
    "url": {
      "raw": "{{baseUrl}}/api/{area}/{module}",
      "host": ["{{baseUrl}}"],
      "path": ["api", "{area}", "{module}"]
    }
  }
}
```

---

## Template Test GET (403 - Permission Denied)

```json
{
  "name": "GET {module} - With NoPerm Token (403)",
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "exec": [
          "const baseUrl = pm.collectionVariables.get('baseUrl');",
          "",
          "pm.sendRequest({",
          "    url: baseUrl + '/api/auth/login',",
          "    method: 'POST',",
          "    header: { 'Content-Type': 'application/json' },",
          "    body: {",
          "        mode: 'raw',",
          "        raw: JSON.stringify({",
          "            email: 'noperm@smartstack.test',",
          "            password: 'NoPerm123!'",
          "        })",
          "    }",
          "}, function (err, res) {",
          "    if (err) {",
          "        console.error('Login failed:', err);",
          "        return;",
          "    }",
          "    const response = res.json();",
          "    pm.collectionVariables.set('accessToken', response.token);",
          "    pm.collectionVariables.set('currentUser', 'noperm');",
          "});"
        ],
        "type": "text/javascript"
      }
    },
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 403 Forbidden', function () {",
          "    pm.response.to.have.status(403);",
          "});",
          "",
          "pm.test('Response indicates permission denied', function () {",
          "    // 403 responses may have empty body or error message",
          "    pm.expect(pm.response.code).to.equal(403);",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "GET",
    "header": [
      {
        "key": "Authorization",
        "value": "Bearer {{accessToken}}",
        "type": "text"
      }
    ],
    "url": {
      "raw": "{{baseUrl}}/api/{area}/{module}",
      "host": ["{{baseUrl}}"],
      "path": ["api", "{area}", "{module}"]
    }
  }
}
```

---

## Template Test GET (401 - No Auth)

```json
{
  "name": "GET {module} - Without Token (401)",
  "event": [
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 401 Unauthorized', function () {",
          "    pm.response.to.have.status(401);",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "GET",
    "header": [],
    "url": {
      "raw": "{{baseUrl}}/api/{area}/{module}",
      "host": ["{{baseUrl}}"],
      "path": ["api", "{area}", "{module}"]
    }
  }
}
```

---

## Template Test POST Create (201)

```json
{
  "name": "POST {module} - With Admin Token (201)",
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "exec": [
          "const baseUrl = pm.collectionVariables.get('baseUrl');",
          "",
          "pm.sendRequest({",
          "    url: baseUrl + '/api/auth/login',",
          "    method: 'POST',",
          "    header: { 'Content-Type': 'application/json' },",
          "    body: {",
          "        mode: 'raw',",
          "        raw: JSON.stringify({",
          "            email: 'superadmin@smartstack.test',",
          "            password: 'SuperAdmin123!'",
          "        })",
          "    }",
          "}, function (err, res) {",
          "    if (err) return console.error('Login failed:', err);",
          "    const response = res.json();",
          "    pm.collectionVariables.set('accessToken', response.token);",
          "});"
        ],
        "type": "text/javascript"
      }
    },
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 201 Created', function () {",
          "    pm.response.to.have.status(201);",
          "});",
          "",
          "pm.test('Response has created entity with ID', function () {",
          "    const response = pm.response.json();",
          "    pm.expect(response).to.have.property('id');",
          "    // Store for subsequent tests",
          "    pm.collectionVariables.set('test{Entity}Id', response.id);",
          "});",
          "",
          "pm.test('Response has Location header', function () {",
          "    pm.expect(pm.response.headers.has('Location')).to.be.true;",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "POST",
    "header": [
      {
        "key": "Authorization",
        "value": "Bearer {{accessToken}}",
        "type": "text"
      },
      {
        "key": "Content-Type",
        "value": "application/json",
        "type": "text"
      }
    ],
    "body": {
      "mode": "raw",
      "raw": "{\n    \"name\": \"Test {Entity} {{$timestamp}}\",\n    \"description\": \"Created via Postman test\"\n}"
    },
    "url": {
      "raw": "{{baseUrl}}/api/{area}/{module}",
      "host": ["{{baseUrl}}"],
      "path": ["api", "{area}", "{module}"]
    }
  }
}
```

---

## Template Test POST (403 - ReadOnly)

```json
{
  "name": "POST {module} - With ReadOnly Token (403)",
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "exec": [
          "const baseUrl = pm.collectionVariables.get('baseUrl');",
          "",
          "pm.sendRequest({",
          "    url: baseUrl + '/api/auth/login',",
          "    method: 'POST',",
          "    header: { 'Content-Type': 'application/json' },",
          "    body: {",
          "        mode: 'raw',",
          "        raw: JSON.stringify({",
          "            email: 'readonly@smartstack.test',",
          "            password: 'ReadOnly123!'",
          "        })",
          "    }",
          "}, function (err, res) {",
          "    if (err) return console.error('Login failed:', err);",
          "    const response = res.json();",
          "    pm.collectionVariables.set('accessToken', response.token);",
          "});"
        ],
        "type": "text/javascript"
      }
    },
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 403 Forbidden', function () {",
          "    pm.response.to.have.status(403);",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "POST",
    "header": [
      {
        "key": "Authorization",
        "value": "Bearer {{accessToken}}",
        "type": "text"
      },
      {
        "key": "Content-Type",
        "value": "application/json",
        "type": "text"
      }
    ],
    "body": {
      "mode": "raw",
      "raw": "{\n    \"name\": \"Should Fail\",\n    \"description\": \"ReadOnly cannot create\"\n}"
    },
    "url": {
      "raw": "{{baseUrl}}/api/{area}/{module}",
      "host": ["{{baseUrl}}"],
      "path": ["api", "{area}", "{module}"]
    }
  }
}
```

---

## Template Test DELETE (403)

```json
{
  "name": "DELETE {module} - With ReadOnly Token (403)",
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "exec": [
          "const baseUrl = pm.collectionVariables.get('baseUrl');",
          "",
          "pm.sendRequest({",
          "    url: baseUrl + '/api/auth/login',",
          "    method: 'POST',",
          "    header: { 'Content-Type': 'application/json' },",
          "    body: {",
          "        mode: 'raw',",
          "        raw: JSON.stringify({",
          "            email: 'readonly@smartstack.test',",
          "            password: 'ReadOnly123!'",
          "        })",
          "    }",
          "}, function (err, res) {",
          "    if (err) return console.error('Login failed:', err);",
          "    const response = res.json();",
          "    pm.collectionVariables.set('accessToken', response.token);",
          "});"
        ],
        "type": "text/javascript"
      }
    },
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 403 Forbidden', function () {",
          "    pm.response.to.have.status(403);",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "DELETE",
    "header": [
      {
        "key": "Authorization",
        "value": "Bearer {{accessToken}}",
        "type": "text"
      }
    ],
    "url": {
      "raw": "{{baseUrl}}/api/{area}/{module}/{{test{Entity}Id}}",
      "host": ["{{baseUrl}}"],
      "path": ["api", "{area}", "{module}", "{{test{Entity}Id}}"]
    }
  }
}
```

---

## Template Test Auth - Login Success

```json
{
  "name": "Login - Valid Credentials (200)",
  "event": [
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 200', function () {",
          "    pm.response.to.have.status(200);",
          "});",
          "",
          "pm.test('Response has access token', function () {",
          "    const response = pm.response.json();",
          "    pm.expect(response).to.have.property('token');",
          "    pm.expect(response.token).to.be.a('string');",
          "});",
          "",
          "pm.test('Response has user info', function () {",
          "    const response = pm.response.json();",
          "    pm.expect(response).to.have.property('user');",
          "    pm.expect(response.user).to.have.property('email');",
          "    pm.expect(response.user).to.have.property('roles');",
          "    pm.expect(response.user).to.have.property('permissions');",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "POST",
    "header": [
      {
        "key": "Content-Type",
        "value": "application/json",
        "type": "text"
      }
    ],
    "body": {
      "mode": "raw",
      "raw": "{\n    \"email\": \"superadmin@smartstack.test\",\n    \"password\": \"SuperAdmin123!\"\n}"
    },
    "url": {
      "raw": "{{baseUrl}}/api/auth/login",
      "host": ["{{baseUrl}}"],
      "path": ["api", "auth", "login"]
    }
  }
}
```

---

## Template Test Auth - Login Failed (Locked Account)

```json
{
  "name": "Login - Locked Account (401)",
  "event": [
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 401 Unauthorized', function () {",
          "    pm.response.to.have.status(401);",
          "});",
          "",
          "pm.test('Response indicates account locked', function () {",
          "    const response = pm.response.json();",
          "    pm.expect(response).to.have.property('code');",
          "    pm.expect(['ACCOUNT_LOCKED', 'ACCOUNT_LOCKED_BY_ADMIN']).to.include(response.code);",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "POST",
    "header": [
      {
        "key": "Content-Type",
        "value": "application/json",
        "type": "text"
      }
    ],
    "body": {
      "mode": "raw",
      "raw": "{\n    \"email\": \"locked@smartstack.test\",\n    \"password\": \"any-password\"\n}"
    },
    "url": {
      "raw": "{{baseUrl}}/api/auth/login",
      "host": ["{{baseUrl}}"],
      "path": ["api", "auth", "login"]
    }
  }
}
```

---

## Template Test Auth - Invalid Token (401)

```json
{
  "name": "Any Endpoint - Invalid Token (401)",
  "event": [
    {
      "listen": "test",
      "script": {
        "exec": [
          "pm.test('Status code is 401 Unauthorized', function () {",
          "    pm.response.to.have.status(401);",
          "});"
        ],
        "type": "text/javascript"
      }
    }
  ],
  "request": {
    "method": "GET",
    "header": [
      {
        "key": "Authorization",
        "value": "Bearer invalid.token.here",
        "type": "text"
      }
    ],
    "url": {
      "raw": "{{baseUrl}}/api/admin/users",
      "host": ["{{baseUrl}}"],
      "path": ["api", "admin", "users"]
    }
  }
}
```

---

## Automatic Generation

To generate tests for a new controller, replace:

| Variable | Example |
|----------|---------|
| `{area}` | `support`, `admin`, `business` |
| `{module}` | `tickets`, `sla`, `users` |
| `{Entity}` | `Ticket`, `SlaDefinition`, `User` |

### Minimum Tests per Controller

1. GET list - SuperAdmin (200)
2. GET list - NoPerm (403)
3. GET list - No Token (401)
4. POST create - Admin (201)
5. POST create - ReadOnly (403)
6. DELETE - ReadOnly (403)

### Optional Tests

- GET by ID - (200)
- GET by ID - Not Found (404)
- PUT update - (200)
- PATCH activate/deactivate - (204)
- POST with invalid data - (400)
- POST duplicate - (409)
