turash/docs/api/proposals.md
Damir Mukimov 000eab4740
Major repository reorganization and missing backend endpoints implementation
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools

Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
  * GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
  * GET /api/v1/users/me/organizations - User organizations
  * POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue

API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules

Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
2025-11-25 06:01:16 +01:00

265 lines
6.3 KiB
Markdown

# Proposals API
The Proposals API provides endpoints for managing symbiosis proposals between organizations. Proposals represent requests for resource exchange or collaboration opportunities.
## Base URL
```
https://api.turash.com/api/v1
```
## Endpoints
### Get All Proposals
Retrieve all proposals with optional filtering.
**Endpoint:** `GET /api/v1/proposals`
**Query Parameters:**
- `status` (optional): Filter by proposal status (`pending`, `accepted`, `rejected`)
- `from_org` (optional): Filter by proposing organization ID
- `to_org` (optional): Filter by target organization ID
- `limit` (optional): Maximum number of results (default: 50)
- `offset` (optional): Pagination offset (default: 0)
**Response:**
```json
[
{
"id": "proposal-123",
"from_org_id": "org-456",
"to_org_id": "org-789",
"resource_id": "resource-101",
"resource_type": "input",
"resource_name": "Organic Waste",
"message": "We can provide organic waste for your composting needs",
"status": "pending",
"created_at": "2024-01-15T10:30:00Z"
}
]
```
### Get Proposal by ID
Retrieve a specific proposal by its ID.
**Endpoint:** `GET /api/v1/proposals/{id}`
**Path Parameters:**
- `id`: Proposal ID
**Response:**
```json
{
"id": "proposal-123",
"from_org_id": "org-456",
"to_org_id": "org-789",
"resource_id": "resource-101",
"resource_type": "input",
"resource_name": "Organic Waste",
"message": "We can provide organic waste for your composting needs",
"status": "pending",
"created_at": "2024-01-15T10:30:00Z"
}
```
**Error Responses:**
- `404 Not Found` - Proposal not found
### Get Proposals by Organization
Retrieve all proposals where an organization is either the sender or receiver.
**Endpoint:** `GET /api/v1/organizations/{id}/proposals`
**Path Parameters:**
- `id`: Organization ID
**Response:**
```json
{
"incoming": [
{
"id": "proposal-123",
"from_org_id": "org-456",
"to_org_id": "org-789",
"resource_id": "resource-101",
"resource_type": "input",
"resource_name": "Organic Waste",
"message": "We can provide organic waste for your composting needs",
"status": "pending",
"created_at": "2024-01-15T10:30:00Z"
}
],
"outgoing": [
{
"id": "proposal-124",
"from_org_id": "org-789",
"to_org_id": "org-456",
"resource_id": "resource-102",
"resource_type": "output",
"resource_name": "Heat Energy",
"message": "Interested in your heat recovery system",
"status": "accepted",
"created_at": "2024-01-16T14:20:00Z"
}
]
}
```
### Create Proposal
Create a new symbiosis proposal.
**Endpoint:** `POST /api/v1/proposals`
**Request Body:**
```json
{
"from_org_id": "org-456",
"to_org_id": "org-789",
"resource_id": "resource-101",
"resource_type": "input",
"resource_name": "Organic Waste",
"message": "We can provide organic waste for your composting needs"
}
```
**Required Fields:**
- `from_org_id`: ID of the proposing organization
- `to_org_id`: ID of the target organization
- `resource_id`: ID of the resource flow being proposed
- `resource_type`: Direction of the resource flow (`input` or `output`)
- `resource_name`: Human-readable name of the resource
**Optional Fields:**
- `message`: Additional message or proposal details
**Response:**
```json
{
"id": "proposal-123",
"from_org_id": "org-456",
"to_org_id": "org-789",
"resource_id": "resource-101",
"resource_type": "input",
"resource_name": "Organic Waste",
"message": "We can provide organic waste for your composting needs",
"status": "pending",
"created_at": "2024-01-15T10:30:00Z"
}
```
**Error Responses:**
- `400 Bad Request` - Invalid request data
- `404 Not Found` - Organization or resource not found
### Update Proposal Status
Update the status of an existing proposal.
**Endpoint:** `POST /api/v1/proposals/{id}/status`
**Path Parameters:**
- `id`: Proposal ID
**Request Body:**
```json
{
"status": "accepted"
}
```
**Valid Status Values:**
- `pending` - Initial status, awaiting response
- `accepted` - Proposal accepted by target organization
- `rejected` - Proposal rejected by target organization
**Response:**
```json
{
"message": "Proposal status updated successfully"
}
```
**Error Responses:**
- `400 Bad Request` - Invalid status value
- `404 Not Found` - Proposal not found
## Data Types
### Proposal Status
```typescript
type ProposalStatus = 'pending' | 'accepted' | 'rejected';
```
### Proposal Object
```typescript
interface Proposal {
id: string;
from_org_id: string;
to_org_id: string;
resource_id: string;
resource_type: 'input' | 'output';
resource_name: string;
message?: string;
status: ProposalStatus;
created_at: string;
}
```
## Business Rules
### Proposal Lifecycle
1. **Creation**: Proposals are created with `pending` status
2. **Response**: Target organization can accept or reject the proposal
3. **Final State**: Once accepted or rejected, status cannot be changed
### Validation Rules
- Organizations cannot propose to themselves
- Resource must exist and be owned by the proposing organization
- Resource type must match the direction being proposed
- Message length limited to 500 characters
### Permissions
Currently, all proposal operations are publicly accessible. Future implementations will include:
- Authentication requirements
- Authorization based on organization membership
- Proposal creation limits per organization
## Error Codes
| Code | Description |
|------|-------------|
| `VALIDATION_ERROR` | Request data validation failed |
| `PROPOSAL_NOT_FOUND` | Specified proposal does not exist |
| `ORGANIZATION_NOT_FOUND` | Specified organization does not exist |
| `RESOURCE_NOT_FOUND` | Specified resource does not exist |
| `INVALID_STATUS_TRANSITION` | Attempted invalid status change |
| `SELF_PROPOSAL_ERROR` | Organization cannot propose to itself |
## Rate Limits
- Create Proposal: 10 per hour per organization
- Update Status: 50 per hour per organization
- Get Operations: 100 per hour per IP
## WebSocket Events
The API emits WebSocket events for real-time proposal updates:
- `proposal_created`: New proposal submitted
- `proposal_status_changed`: Proposal status updated
**Event Payload:**
```json
{
"type": "proposal_status_changed",
"proposal_id": "proposal-123",
"old_status": "pending",
"new_status": "accepted",
"updated_by": "org-789",
"timestamp": "2024-01-15T10:35:00Z"
}
```