- openapi.yaml: bumped a 1.1.0, añadido changelog con los cambios acumulados respecto al brief inicial; /templates y bundle.templates documentan que ahora usan pivot (asignación por proyecto); enums de issue documentados. - MOBILE_APP_BRIEF.md: reescrito para reflejar v1.1 — bundle con feature_types / issue_tasks / issue_comments; feature con feature_type_id/is_active; issue.type; nuevas ops (issue.update, issue_task.*, issue_comment.create); parent_entity admite issue_task/issue_comment; deleted incluye tasks/comments; y bloque detallado sobre templates ahora globales con fields[].group/question/help. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
256 lines
9.1 KiB
YAML
256 lines
9.1 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: ConstruProgress Mobile API
|
|
version: "1.1.0"
|
|
description: >
|
|
Offline-first sync API for the mobile app. Auth via Laravel Sanctum bearer
|
|
tokens (ability `mobile-sync`). All protected endpoints require
|
|
`Authorization: Bearer <token>`. See docs/MOBILE_SYNC_PROTOCOL.md.
|
|
|
|
|
|
## Changelog (from v1.0)
|
|
|
|
|
|
- Inspection templates are now **global** and assigned to projects via
|
|
pivot. `bundle.templates` and `/templates` return templates *assigned* to
|
|
the accessible projects (no longer filtered by `project_id`).
|
|
`template.phase_id` was **removed**. `project_id` remains in the schema
|
|
for compatibility but no longer determines visibility.
|
|
|
|
- Template `fields[]` items may include `group` (section), `question` (short
|
|
prompt shown at inspection time) and `help` (long help text).
|
|
|
|
- New entities in the bundle: `feature_types` (global catalogue),
|
|
`issue_tasks`, `issue_comments`.
|
|
|
|
- `feature` gains `feature_type_id`, `is_active`; `issue` gains `type`.
|
|
|
|
- New `/sync` ops: `issue.update`, `issue_task.create`, `issue_task.update`,
|
|
`issue_comment.create`. `feature.update` accepts `is_active` and
|
|
`feature_type_id`; `issue.create`/`update` accept `type`.
|
|
|
|
- `POST /media` `parent_entity` also accepts `issue_task` and `issue_comment`.
|
|
|
|
- `deleted` tombstones include `issue_tasks` and `issue_comments`.
|
|
servers:
|
|
- url: /api/v1
|
|
security:
|
|
- bearerAuth: []
|
|
paths:
|
|
/login:
|
|
post:
|
|
summary: Issue a device token
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [email, password, device_name]
|
|
properties:
|
|
email: { type: string, format: email }
|
|
password: { type: string }
|
|
device_name: { type: string }
|
|
app_version: { type: string, nullable: true }
|
|
responses:
|
|
"200":
|
|
description: Token issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
token: { type: string }
|
|
user: { $ref: '#/components/schemas/User' }
|
|
"422": { description: Invalid credentials }
|
|
/me:
|
|
get:
|
|
summary: Current user + effective permissions
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
user: { $ref: '#/components/schemas/User' }
|
|
"401": { description: Unauthenticated }
|
|
/logout:
|
|
post:
|
|
summary: Revoke the current device token
|
|
responses:
|
|
"200": { description: Logged out }
|
|
/projects:
|
|
get:
|
|
summary: Projects the user can access
|
|
responses:
|
|
"200": { description: OK }
|
|
/projects/{project}/bundle:
|
|
get:
|
|
summary: Offline bundle (full, or delta when `since` is given)
|
|
parameters:
|
|
- name: project
|
|
in: path
|
|
required: true
|
|
schema: { type: integer }
|
|
- name: since
|
|
in: query
|
|
required: false
|
|
description: >
|
|
ISO8601 timestamp. Returns only records changed after it, plus
|
|
`deleted` tombstones. MUST be URL-encoded (the `+` offset).
|
|
schema: { type: string, format: date-time }
|
|
responses:
|
|
"200":
|
|
description: Bundle
|
|
content:
|
|
application/json:
|
|
schema: { $ref: '#/components/schemas/Bundle' }
|
|
"403": { description: Not a member of the project }
|
|
/templates:
|
|
get:
|
|
summary: Global inspection templates ASSIGNED to any accessible project (via pivot)
|
|
description: >
|
|
Templates are a global catalogue. This endpoint returns the templates
|
|
that have been *assigned* (via `inspection_template_project` pivot) to
|
|
any of the user's accessible projects. Each item includes `version`
|
|
(updated_at timestamp) and `hash` for change detection.
|
|
parameters:
|
|
- name: since
|
|
in: query
|
|
required: false
|
|
schema: { type: string, format: date-time }
|
|
responses:
|
|
"200": { description: OK }
|
|
/sync:
|
|
post:
|
|
summary: Push a batch of offline mutations (idempotent by uuid)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [operations]
|
|
properties:
|
|
operations:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Operation' }
|
|
responses:
|
|
"200":
|
|
description: Per-operation results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
results:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/OperationResult' }
|
|
/media:
|
|
post:
|
|
summary: Upload a file (multipart) and attach it to a parent record
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
multipart/form-data:
|
|
schema:
|
|
type: object
|
|
required: [uuid, parent_entity, parent_id, file]
|
|
properties:
|
|
uuid: { type: string, format: uuid }
|
|
parent_entity: { type: string, enum: [feature, issue, issue_task, issue_comment, project, phase, layer] }
|
|
parent_id: { type: integer }
|
|
file: { type: string, format: binary }
|
|
category: { type: string, enum: [image, document, other] }
|
|
description: { type: string }
|
|
responses:
|
|
"200": { description: applied | duplicate }
|
|
"403": { description: Forbidden }
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
schemas:
|
|
User:
|
|
type: object
|
|
properties:
|
|
id: { type: integer }
|
|
name: { type: string }
|
|
email: { type: string }
|
|
roles: { type: array, items: { type: string } }
|
|
permissions: { type: array, items: { type: string } }
|
|
Operation:
|
|
type: object
|
|
required: [entity, op, uuid, data]
|
|
properties:
|
|
entity: { type: string, enum: [progress_update, inspection, issue, issue_task, issue_comment, feature] }
|
|
op: { type: string, enum: [create, update] }
|
|
uuid: { type: string, format: uuid, description: client-generated idempotency key }
|
|
client_updated_at: { type: string, format: date-time }
|
|
data: { type: object }
|
|
example:
|
|
entity: feature
|
|
op: update
|
|
uuid: 0f8e...-uuid
|
|
client_updated_at: "2026-06-18T12:00:00+00:00"
|
|
data: { id: 5, status: completed, progress: 100 }
|
|
OperationResult:
|
|
type: object
|
|
properties:
|
|
uuid: { type: string, format: uuid }
|
|
status: { type: string, enum: [applied, duplicate, conflict, error] }
|
|
server_id: { type: integer, nullable: true }
|
|
error: { type: string, nullable: true }
|
|
server: { type: object, nullable: true, description: current server value on conflict }
|
|
Bundle:
|
|
type: object
|
|
properties:
|
|
server_time: { type: string, format: date-time }
|
|
project: { type: object }
|
|
phases: { type: array, items: { type: object } }
|
|
layers: { type: array, items: { type: object } }
|
|
features: { type: array, items: { type: object } }
|
|
feature_types:
|
|
type: array
|
|
description: Global catalogue of feature types (id, name, color)
|
|
items: { type: object }
|
|
inspections: { type: array, items: { type: object } }
|
|
issues:
|
|
type: array
|
|
description: >
|
|
Includes `type` (defect|safety|quality|documentation|other),
|
|
`status` (open|in_review|resolved|closed),
|
|
`priority` (low|medium|high|critical).
|
|
items: { type: object }
|
|
issue_tasks:
|
|
type: array
|
|
description: Checklist tasks per issue.
|
|
items: { type: object }
|
|
issue_comments:
|
|
type: array
|
|
description: Comment thread per issue.
|
|
items: { type: object }
|
|
templates:
|
|
type: array
|
|
description: >
|
|
Templates assigned to this project via pivot (no longer filtered by
|
|
project_id). Each item exposes version/hash for change detection and
|
|
`fields[]` where each field may include `group`, `question`, `help`.
|
|
items: { type: object }
|
|
media: { type: array, items: { type: object } }
|
|
deleted:
|
|
type: object
|
|
description: tombstones (ids of soft-deleted records) when `since` is given
|
|
properties:
|
|
phases: { type: array, items: { type: integer } }
|
|
layers: { type: array, items: { type: integer } }
|
|
features: { type: array, items: { type: integer } }
|
|
inspections: { type: array, items: { type: integer } }
|
|
issues: { type: array, items: { type: integer } }
|
|
issue_tasks: { type: array, items: { type: integer } }
|
|
issue_comments: { type: array, items: { type: integer } }
|