Photo Management (per specs/photo-management.md): - Sharp integration for 3-size compression (thumb/medium/full) - WebP output with 80-90% quality - Client-side compression with browser-image-compression - PhotoUpload component with camera/drag-drop support - Upload API with bulk support and stats endpoint Testing: - Backend: Jest tests for all major API endpoints - Frontend: Vitest tests for utilities and API clients - CI: Updated Forgejo workflow for test execution Specs (100% coverage): - visitor-management.md (Phase 8) - messaging.md (Phase 9) - audit-and-documents.md (Phase 10) - accessibility-i18n.md (Phase 11) - hardware-integration.md (Phase 12) - advanced-features.md (Phase 13) Documentation: - OpenAPI 3.0 spec (docs/openapi.yaml) - All endpoints documented with schemas
457 lines
10 KiB
YAML
457 lines
10 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: CA Grow Ops Manager API
|
|
description: |
|
|
API for managing California cannabis cultivation operations.
|
|
|
|
## Authentication
|
|
All endpoints except `/api/healthz` and `/api/auth/login` require a valid JWT token.
|
|
Include the token in the Authorization header: `Bearer <token>`
|
|
version: 1.0.0
|
|
contact:
|
|
name: 777 Wolfpack
|
|
|
|
servers:
|
|
- url: http://localhost:3000/api
|
|
description: Local development
|
|
- url: https://777wolfpack.runfoo.run/api
|
|
description: Production
|
|
|
|
tags:
|
|
- name: Auth
|
|
description: Authentication endpoints
|
|
- name: Rooms
|
|
description: Grow room management
|
|
- name: Batches
|
|
description: Batch lifecycle management
|
|
- name: Tasks
|
|
description: Task management and scheduling
|
|
- name: Supplies
|
|
description: Inventory and materials
|
|
- name: Timeclock
|
|
description: Labor tracking
|
|
- name: Walkthrough
|
|
description: Daily facility walkthroughs
|
|
- name: IPM
|
|
description: Integrated Pest Management
|
|
- name: Visitors
|
|
description: Visitor management
|
|
- name: Messaging
|
|
description: Announcements and shift notes
|
|
- name: Audit
|
|
description: Audit trail and compliance
|
|
- name: Documents
|
|
description: SOP and document management
|
|
- name: Environment
|
|
description: Environmental monitoring
|
|
- name: Financial
|
|
description: Financial tracking
|
|
- name: Insights
|
|
description: AI/ML insights
|
|
- name: Upload
|
|
description: Photo upload and management
|
|
|
|
paths:
|
|
/healthz:
|
|
get:
|
|
summary: Health check
|
|
tags: [System]
|
|
responses:
|
|
'200':
|
|
description: Server is healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
example: ok
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
|
|
/auth/login:
|
|
post:
|
|
summary: User login
|
|
tags: [Auth]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [email, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
password:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Login successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
'401':
|
|
description: Invalid credentials
|
|
|
|
/auth/me:
|
|
get:
|
|
summary: Get current user
|
|
tags: [Auth]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Current user info
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
|
|
/rooms:
|
|
get:
|
|
summary: List all rooms
|
|
tags: [Rooms]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of rooms
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Room'
|
|
|
|
/batches:
|
|
get:
|
|
summary: List all batches
|
|
tags: [Batches]
|
|
security:
|
|
- bearerAuth: []
|
|
parameters:
|
|
- name: stage
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [CLONE, VEG, FLOWER, DRY, CURE, FINISHED]
|
|
- name: roomId
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of batches
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Batch'
|
|
post:
|
|
summary: Create a batch
|
|
tags: [Batches]
|
|
security:
|
|
- bearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BatchCreate'
|
|
responses:
|
|
'201':
|
|
description: Batch created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Batch'
|
|
|
|
/tasks:
|
|
get:
|
|
summary: List tasks
|
|
tags: [Tasks]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of tasks
|
|
|
|
/supplies:
|
|
get:
|
|
summary: List supplies
|
|
tags: [Supplies]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of supplies
|
|
|
|
/timeclock/active:
|
|
get:
|
|
summary: Get active time entry
|
|
tags: [Timeclock]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Active entry
|
|
'404':
|
|
description: No active entry
|
|
|
|
/walkthrough:
|
|
get:
|
|
summary: List walkthroughs
|
|
tags: [Walkthrough]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of walkthroughs
|
|
|
|
/visitors:
|
|
get:
|
|
summary: List visitors
|
|
tags: [Visitors]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of visitors
|
|
|
|
/messaging/announcements:
|
|
get:
|
|
summary: List announcements
|
|
tags: [Messaging]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of announcements
|
|
|
|
/audit/logs:
|
|
get:
|
|
summary: Get audit logs
|
|
tags: [Audit]
|
|
security:
|
|
- bearerAuth: []
|
|
parameters:
|
|
- name: entityType
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: entityId
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: startDate
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: endDate
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: date
|
|
responses:
|
|
'200':
|
|
description: List of audit logs
|
|
|
|
/documents:
|
|
get:
|
|
summary: List documents
|
|
tags: [Documents]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of documents
|
|
|
|
/environment/sensors:
|
|
get:
|
|
summary: List sensors
|
|
tags: [Environment]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of sensors
|
|
|
|
/environment/dashboard:
|
|
get:
|
|
summary: Environment dashboard
|
|
tags: [Environment]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Dashboard data
|
|
|
|
/financial/transactions:
|
|
get:
|
|
summary: List transactions
|
|
tags: [Financial]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Transactions with totals
|
|
|
|
/financial/reports/profit-loss:
|
|
get:
|
|
summary: Profit/Loss report
|
|
tags: [Financial]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: P&L report
|
|
|
|
/insights/dashboard:
|
|
get:
|
|
summary: AI insights dashboard
|
|
tags: [Insights]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Dashboard data
|
|
|
|
/upload/photo:
|
|
post:
|
|
summary: Upload a photo
|
|
tags: [Upload]
|
|
security:
|
|
- bearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
multipart/form-data:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
file:
|
|
type: string
|
|
format: binary
|
|
responses:
|
|
'200':
|
|
description: Photo uploaded
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UploadedPhoto'
|
|
|
|
/upload/stats:
|
|
get:
|
|
summary: Get upload statistics
|
|
tags: [Upload]
|
|
security:
|
|
- bearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Upload stats
|
|
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
|
|
schemas:
|
|
User:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
format: email
|
|
name:
|
|
type: string
|
|
role:
|
|
type: string
|
|
enum: [OWNER, COMPLIANCE_MANAGER, HEAD_GROWER, STAFF, TRIMMER]
|
|
|
|
Room:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
type:
|
|
type: string
|
|
enum: [VEG, FLOWER, DRY, FACILITY]
|
|
capacity:
|
|
type: integer
|
|
|
|
Batch:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
strain:
|
|
type: string
|
|
stage:
|
|
type: string
|
|
enum: [CLONE, VEG, FLOWER, DRY, CURE, FINISHED]
|
|
plantCount:
|
|
type: integer
|
|
roomId:
|
|
type: string
|
|
format: uuid
|
|
|
|
BatchCreate:
|
|
type: object
|
|
required: [name, strain, plantCount]
|
|
properties:
|
|
name:
|
|
type: string
|
|
strain:
|
|
type: string
|
|
plantCount:
|
|
type: integer
|
|
roomId:
|
|
type: string
|
|
format: uuid
|
|
|
|
UploadedPhoto:
|
|
type: object
|
|
properties:
|
|
success:
|
|
type: boolean
|
|
photoId:
|
|
type: string
|
|
urls:
|
|
type: object
|
|
properties:
|
|
thumb:
|
|
type: string
|
|
medium:
|
|
type: string
|
|
full:
|
|
type: string
|
|
metadata:
|
|
type: object
|
|
properties:
|
|
originalSize:
|
|
type: integer
|
|
savingsPercent:
|
|
type: integer
|