# Service Management API Documentation

## Overview

The Service Management API allows administrators to manage services (like Farmer ID, BOCW ID, etc.) and provides public endpoints for checking service availability. Services can now include images for better visual representation in service cards.

---

## Base URL

```
https://api.alldigtalseva.com/api
```

---

## API Endpoints

### Admin Endpoints (Require Admin Token)

#### 1. Get All Services

Get list of all services with their images.

**Endpoint:** `GET /admin/service`

**Headers:**
```
Authorization: Bearer {admin_token}
Content-Type: application/json
```

**Response (Success - 200):**
```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "Farmer ID",
            "path": "/user/farmerid",
            "image": "services/1234567890_abc123.jpg",
            "image_url": "https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg",
            "is_coming_soon": false,
            "cost": "25.00",
            "created_by": 1,
            "created_at": "2025-12-07T10:00:00.000000Z",
            "updated_at": "2025-12-07T10:00:00.000000Z"
        },
        {
            "id": 2,
            "name": "BOCW ID",
            "path": "/user/bocw",
            "image": null,
            "image_url": null,
            "is_coming_soon": false,
            "cost": "25.00",
            "created_by": 1,
            "created_at": "2025-12-07T10:00:00.000000Z",
            "updated_at": "2025-12-07T10:00:00.000000Z"
        }
    ]
}
```

**Response (Unauthorized - 401):**
```json
{
    "success": false,
    "message": "Unauthorized. Admin access required."
}
```

**cURL Example:**
```bash
curl -X GET https://api.alldigtalseva.com/api/admin/service \
  -H "Authorization: Bearer {admin_token}" \
  -H "Content-Type: application/json"
```

---

#### 2. Get Single Service

Get details of a specific service.

**Endpoint:** `GET /admin/service/{id}`

**Headers:**
```
Authorization: Bearer {admin_token}
Content-Type: application/json
```

**Response (Success - 200):**
```json
{
    "success": true,
    "data": {
        "id": 1,
        "name": "Farmer ID",
        "path": "/user/farmerid",
        "image": "services/1234567890_abc123.jpg",
        "image_url": "https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg",
        "is_coming_soon": false,
        "cost": "25.00",
        "created_by": 1,
        "created_at": "2025-12-07T10:00:00.000000Z",
        "updated_at": "2025-12-07T10:00:00.000000Z"
    }
}
```

**Response (Not Found - 404):**
```json
{
    "success": false,
    "message": "Service not found"
}
```

**cURL Example:**
```bash
curl -X GET https://api.alldigtalseva.com/api/admin/service/1 \
  -H "Authorization: Bearer {admin_token}" \
  -H "Content-Type: application/json"
```

---

#### 3. Add New Service

Create a new service with optional image upload.

**Endpoint:** `POST /admin/service`

**Headers:**
```
Authorization: Bearer {admin_token}
Content-Type: multipart/form-data
```

**Request Body (Form Data):**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| name | string | Yes | Service name (max 255 characters) |
| path | string | Yes | Service path (must start with `/`, unique, e.g., `/user/farmerid`) |
| image | file | No | Service image (jpeg, png, jpg, gif, webp, max 2MB) |
| is_coming_soon | boolean | No | Whether service is coming soon (default: `false`) |
| cost | decimal | No | Service cost (default: `0.00`) |

**Response (Success - 201):**
```json
{
    "success": true,
    "message": "Service added successfully",
    "data": {
        "id": 1,
        "name": "Farmer ID",
        "path": "/user/farmerid",
        "image": "services/1234567890_abc123.jpg",
        "image_url": "https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg",
        "is_coming_soon": false,
        "cost": "25.00",
        "created_by": 1,
        "created_at": "2025-12-07T10:00:00.000000Z",
        "updated_at": "2025-12-07T10:00:00.000000Z"
    }
}
```

**Response (Validation Error - 422):**
```json
{
    "success": false,
    "message": "Validation error",
    "errors": {
        "name": ["The name field is required."],
        "path": ["The path has already been taken."],
        "image": ["The image must be an image.", "The image must not be greater than 2048 kilobytes."]
    }
}
```

**cURL Example:**
```bash
# Create service with image
curl -X POST https://api.alldigtalseva.com/api/admin/service \
  -H "Authorization: Bearer {admin_token}" \
  -F "name=Farmer ID" \
  -F "path=/user/farmerid" \
  -F "image=@/path/to/image.jpg" \
  -F "cost=25.00" \
  -F "is_coming_soon=false"

# Create service without image
curl -X POST https://api.alldigtalseva.com/api/admin/service \
  -H "Authorization: Bearer {admin_token}" \
  -F "name=BOCW ID" \
  -F "path=/user/bocw" \
  -F "cost=25.00"
```

**JavaScript/Fetch Example:**
```javascript
const formData = new FormData();
formData.append('name', 'Farmer ID');
formData.append('path', '/user/farmerid');
formData.append('cost', '25.00');
formData.append('image', fileInput.files[0]); // File from input

fetch('https://api.alldigtalseva.com/api/admin/service', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${adminToken}`
    // Don't set Content-Type, browser will set it with boundary
  },
  body: formData
})
.then(response => response.json())
.then(data => {
  if (data.success) {
    console.log('Service created:', data.data);
    console.log('Image URL:', data.data.image_url);
  }
});
```

---

#### 4. Update Service

Update an existing service. Can update image by uploading a new one.

**Endpoint:** `PUT /admin/service/{id}` or `PATCH /admin/service/{id}`

**Headers:**
```
Authorization: Bearer {admin_token}
Content-Type: multipart/form-data
```

**Request Body (Form Data):**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| name | string | No | Service name (max 255 characters) |
| path | string | No | Service path (must start with `/`, unique) |
| image | file | No | New service image (jpeg, png, jpg, gif, webp, max 2MB) |
| is_coming_soon | boolean | No | Whether service is coming soon |
| cost | decimal | No | Service cost |

**Response (Success - 200):**
```json
{
    "success": true,
    "message": "Service updated successfully",
    "data": {
        "id": 1,
        "name": "Farmer ID Updated",
        "path": "/user/farmerid",
        "image": "services/1234567891_def456.jpg",
        "image_url": "https://api.alldigtalseva.com/storage/services/1234567891_def456.jpg",
        "is_coming_soon": false,
        "cost": "30.00",
        "created_by": 1,
        "created_at": "2025-12-07T10:00:00.000000Z",
        "updated_at": "2025-12-07T11:00:00.000000Z"
    }
}
```

**Note:** If a new image is uploaded, the old image will be automatically deleted.

**cURL Example:**
```bash
# Update service with new image
curl -X PUT https://api.alldigtalseva.com/api/admin/service/1 \
  -H "Authorization: Bearer {admin_token}" \
  -F "name=Farmer ID Updated" \
  -F "image=@/path/to/new-image.jpg" \
  -F "cost=30.00"

# Update service without changing image
curl -X PATCH https://api.alldigtalseva.com/api/admin/service/1 \
  -H "Authorization: Bearer {admin_token}" \
  -F "name=Farmer ID Updated" \
  -F "cost=30.00"
```

---

#### 5. Delete Service

Delete a service. The associated image file will also be deleted.

**Endpoint:** `DELETE /admin/service/{id}`

**Headers:**
```
Authorization: Bearer {admin_token}
Content-Type: application/json
```

**Response (Success - 200):**
```json
{
    "success": true,
    "message": "Service deleted successfully"
}
```

**Response (Not Found - 404):**
```json
{
    "success": false,
    "message": "Service not found"
}
```

**cURL Example:**
```bash
curl -X DELETE https://api.alldigtalseva.com/api/admin/service/1 \
  -H "Authorization: Bearer {admin_token}" \
  -H "Content-Type: application/json"
```

**Note:** When a service is deleted, its associated image file is also automatically deleted from storage.

---

### Public Endpoints (No Authentication Required)

#### 6. Get All Services

Get list of all available services with images for public display.

**Endpoint:** `GET /services`

**Response (Success - 200):**
```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "Farmer ID",
            "path": "/user/farmerid",
            "image": "services/1234567890_abc123.jpg",
            "image_url": "https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg",
            "is_coming_soon": false,
            "cost": "25.00",
            "created_by": 1,
            "created_at": "2025-12-07T10:00:00.000000Z",
            "updated_at": "2025-12-07T10:00:00.000000Z"
        },
        {
            "id": 2,
            "name": "BOCW ID",
            "path": "/user/bocw",
            "image": null,
            "image_url": null,
            "is_coming_soon": false,
            "cost": "25.00",
            "created_by": 1,
            "created_at": "2025-12-07T10:00:00.000000Z",
            "updated_at": "2025-12-07T10:00:00.000000Z"
        }
    ]
}
```

**cURL Example:**
```bash
curl -X GET https://api.alldigtalseva.com/api/services
```

---

#### 7. Check Service by Path

Check if a service is available or coming soon by its path.

**Endpoint:** `GET /service/check`

**Query Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| path | string | Yes | Service path (e.g., `/user/farmerid`) |

**Response (Success - 200):**
```json
{
    "success": true,
    "data": {
        "id": 1,
        "name": "Farmer ID",
        "path": "/user/farmerid",
        "image": "services/1234567890_abc123.jpg",
        "image_url": "https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg",
        "is_coming_soon": false,
        "available": true,
        "message": "Service is available"
    }
}
```

**Response (Not Found - 404):**
```json
{
    "success": false,
    "message": "Service not found",
    "is_coming_soon": false,
    "available": false
}
```

**cURL Example:**
```bash
curl -X GET "https://api.alldigtalseva.com/api/service/check?path=/user/farmerid"
```

---

#### 8. Get Service by Path

Get service details by path (for Angular routing).

**Endpoint:** `GET /service/path/{path}`

**URL Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| path | string | Yes | Service path without leading slash (e.g., `user/farmerid`) |

**Response (Success - 200):**
```json
{
    "success": true,
    "data": {
        "id": 1,
        "name": "Farmer ID",
        "path": "/user/farmerid",
        "image": "services/1234567890_abc123.jpg",
        "image_url": "https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg",
        "is_coming_soon": false,
        "available": true,
        "message": "Service is available"
    }
}
```

**cURL Example:**
```bash
curl -X GET https://api.alldigtalseva.com/api/service/path/user/farmerid
```

---

## JavaScript/Angular Examples

### Create Service with Image Upload

```typescript
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AdminServiceService {
  private apiUrl = 'https://api.alldigtalseva.com/api';
  private headers: HttpHeaders;

  constructor(private http: HttpClient) {
    const token = localStorage.getItem('admin_token');
    this.headers = new HttpHeaders({
      'Authorization': `Bearer ${token}`
      // Don't set Content-Type for FormData, browser will set it
    });
  }

  createService(serviceData: {
    name: string;
    path: string;
    cost?: number;
    is_coming_soon?: boolean;
    image?: File;
  }): Observable<any> {
    const formData = new FormData();
    formData.append('name', serviceData.name);
    formData.append('path', serviceData.path);
    
    if (serviceData.cost !== undefined) {
      formData.append('cost', serviceData.cost.toString());
    }
    
    if (serviceData.is_coming_soon !== undefined) {
      formData.append('is_coming_soon', serviceData.is_coming_soon.toString());
    }
    
    if (serviceData.image) {
      formData.append('image', serviceData.image);
    }

    return this.http.post(`${this.apiUrl}/admin/service`, formData, {
      headers: this.headers
    });
  }
}

// Usage in component
onFileSelected(event: any) {
  const file = event.target.files[0];
  if (file) {
    this.selectedFile = file;
  }
}

createService() {
  const serviceData = {
    name: 'Farmer ID',
    path: '/user/farmerid',
    cost: 25.00,
    image: this.selectedFile
  };

  this.adminServiceService.createService(serviceData).subscribe(
    (response) => {
      if (response.success) {
        console.log('Service created:', response.data);
        console.log('Image URL:', response.data.image_url);
        // Show success message
      }
    },
    (error) => {
      console.error('Error:', error);
      if (error.error.errors) {
        console.error('Validation errors:', error.error.errors);
      }
    }
  );
}
```

### Update Service with Image

```typescript
updateService(serviceId: number, serviceData: {
  name?: string;
  path?: string;
  cost?: number;
  is_coming_soon?: boolean;
  image?: File;
}): Observable<any> {
  const formData = new FormData();
  
  if (serviceData.name) {
    formData.append('name', serviceData.name);
  }
  
  if (serviceData.path) {
    formData.append('path', serviceData.path);
  }
  
  if (serviceData.cost !== undefined) {
    formData.append('cost', serviceData.cost.toString());
  }
  
  if (serviceData.is_coming_soon !== undefined) {
    formData.append('is_coming_soon', serviceData.is_coming_soon.toString());
  }
  
  if (serviceData.image) {
    formData.append('image', serviceData.image);
  }

  return this.http.put(`${this.apiUrl}/admin/service/${serviceId}`, formData, {
    headers: this.headers
  });
}

// Usage
updateService(1, {
  name: 'Farmer ID Updated',
  cost: 30.00,
  image: this.selectedFile
}).subscribe(
  (response) => {
    if (response.success) {
      console.log('Service updated:', response.data);
    }
  }
);
```

### Get All Services (Public)

```typescript
getAllServices(): Observable<any> {
  return this.http.get(`${this.apiUrl}/services`);
}

// Usage
this.serviceService.getAllServices().subscribe(
  (response) => {
    if (response.success) {
      response.data.forEach((service: any) => {
        console.log('Service:', service.name);
        if (service.image_url) {
          console.log('Image URL:', service.image_url);
        }
      });
    }
  }
);
```

---

## React/Next.js Examples

### Create Service with Image Upload

```javascript
const createService = async (adminToken, serviceData, imageFile) => {
  try {
    const formData = new FormData();
    formData.append('name', serviceData.name);
    formData.append('path', serviceData.path);
    
    if (serviceData.cost !== undefined) {
      formData.append('cost', serviceData.cost.toString());
    }
    
    if (serviceData.is_coming_soon !== undefined) {
      formData.append('is_coming_soon', serviceData.is_coming_soon.toString());
    }
    
    if (imageFile) {
      formData.append('image', imageFile);
    }

    const response = await fetch('https://api.alldigtalseva.com/api/admin/service', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${adminToken}`
        // Don't set Content-Type, browser will set it
      },
      body: formData
    });

    const data = await response.json();
    
    if (data.success) {
      return {
        success: true,
        data: data.data
      };
    } else {
      return {
        success: false,
        message: data.message,
        errors: data.errors
      };
    }
  } catch (error) {
    console.error('Error:', error);
    return {
      success: false,
      message: 'An error occurred'
    };
  }
};

// Usage in component
const handleSubmit = async (e) => {
  e.preventDefault();
  const adminToken = localStorage.getItem('admin_token');
  const fileInput = document.getElementById('image-input');
  const imageFile = fileInput?.files[0];

  const result = await createService(
    adminToken,
    {
      name: 'Farmer ID',
      path: '/user/farmerid',
      cost: 25.00
    },
    imageFile
  );

  if (result.success) {
    console.log('Service created:', result.data);
    console.log('Image URL:', result.data.image_url);
  } else {
    console.error('Error:', result.message);
  }
};
```

### Display Services with Images

```javascript
const [services, setServices] = useState([]);

useEffect(() => {
  fetch('https://api.alldigtalseva.com/api/services')
    .then(response => response.json())
    .then(data => {
      if (data.success) {
        setServices(data.data);
      }
    });
}, []);

// Render service cards
return (
  <div className="services-grid">
    {services.map(service => (
      <div key={service.id} className="service-card">
        {service.image_url && (
          <img 
            src={service.image_url} 
            alt={service.name}
            className="service-image"
          />
        )}
        <h3>{service.name}</h3>
        <p>Cost: ₹{service.cost}</p>
        {service.is_coming_soon && (
          <span className="badge">Coming Soon</span>
        )}
      </div>
    ))}
  </div>
);
```

---

## Image Upload Guidelines

### Supported Formats
- JPEG (.jpg, .jpeg)
- PNG (.png)
- GIF (.gif)
- WebP (.webp)

### File Size Limit
- Maximum: 2MB (2048 KB)

### Image Storage
- Images are stored in: `storage/app/public/services/`
- Images are accessible via: `https://api.alldigtalseva.com/storage/services/{filename}`
- Storage symlink: `public/storage` → `storage/app/public`

### Image Naming
- Format: `{timestamp}_{uniqueid}.{extension}`
- Example: `1234567890_abc123.jpg`
- Prevents filename conflicts

### Best Practices
1. **Image Dimensions**: Recommended 800x600px or similar aspect ratio for service cards
2. **File Size**: Optimize images before upload to reduce file size
3. **Format**: Use JPEG for photos, PNG for graphics with transparency
4. **Alt Text**: Always provide meaningful alt text when displaying images

---

## Service Card Display Example

### HTML/CSS Example

```html
<div class="service-card">
  <div class="service-image-container">
    <img 
      src="https://api.alldigtalseva.com/storage/services/1234567890_abc123.jpg" 
      alt="Farmer ID Service"
      class="service-image"
      onerror="this.src='/default-service-image.jpg'"
    />
  </div>
  <div class="service-content">
    <h3 class="service-name">Farmer ID</h3>
    <p class="service-cost">₹25.00</p>
    {#if service.is_coming_soon}
      <span class="badge coming-soon">Coming Soon</span>
    {/if}
  </div>
</div>
```

```css
.service-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.service-image-container {
  width: 100%;
  height: 200px;
  overflow: hidden;
  background-color: #f5f5f5;
}

.service-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.service-content {
  padding: 16px;
}

.service-name {
  margin: 0 0 8px 0;
  font-size: 18px;
  font-weight: bold;
}

.service-cost {
  margin: 0;
  color: #666;
  font-size: 16px;
}
```

---

## Error Handling

### Common Error Scenarios

1. **Invalid Image Format (422)**
   - Status: 422
   - Message: "Validation error"
   - Error: "The image must be an image."
   - Solution: Use supported formats (jpeg, png, jpg, gif, webp)

2. **File Too Large (422)**
   - Status: 422
   - Message: "Validation error"
   - Error: "The image must not be greater than 2048 kilobytes."
   - Solution: Compress image to under 2MB

3. **Path Already Exists (422)**
   - Status: 422
   - Message: "Validation error"
   - Error: "The path has already been taken."
   - Solution: Use a unique path

4. **Unauthorized (401)**
   - Status: 401
   - Message: "Unauthorized. Admin access required."
   - Solution: Provide valid admin token

---

## Integration Checklist

- [ ] Implement image upload in admin form
- [ ] Display service images in service cards
- [ ] Handle missing images gracefully (show placeholder)
- [ ] Optimize images before upload
- [ ] Validate image format and size
- [ ] Show image preview before upload
- [ ] Handle image upload errors
- [ ] Display image URLs in service listings
- [ ] Test image upload functionality
- [ ] Test image update functionality
- [ ] Test image deletion on service delete
- [ ] Verify image URLs are accessible

---

## Support

For issues or questions regarding the Service Management API, please contact the development team.

---

**Last Updated:** December 2025


