# Datos

Bases de datos, colecciones y registros con esquemas y reglas, por una sola puerta REST/JSON.

URL base: `https://data.inovacc.dev`

## Descripción general

Datos es la base de datos de tu aplicación, servida por una sola puerta REST/JSON en `https://data.inovacc.dev`. Creas **bases de datos**, les das **colecciones**, y lees y escribes **registros** con simples llamadas HTTP. Una colección es tipada, con campos declarados por un esquema, o libre, y contiene documentos JSON sin esquema. Quién puede hacer qué se decide en cada solicitud, primero por los permisos de la credencial y luego, registro por registro, por las **reglas** que declara la colección.

El problema que resuelve es operar datos persistentes sin operar una base de datos: sin servidor, sin pool de conexiones, sin herramienta de migraciones, sin respaldos que programar. Tu aplicación conserva su propio código y almacena aquí sus datos; dónde viven los datos lo decide Inovacc y nunca se muestra. La misma API atiende a tus servidores, a tus páginas web (con una clave de navegador) y a las personas con sesión iniciada en tu app, y un oyente en tiempo real envía los cambios a medida que ocurren.

Usa Datos para el estado de la aplicación: notas de usuarios, pedidos, configuraciones, catálogos, cualquier cosa con forma de registros. Almacena contenido binario grande con [Archivos](/es/products/files/), consulta lo que sucedió con el [Registro de actividad](/es/products/activity/), y notifica a otros sistemas con [Eventos](/es/products/events/).

## Conceptos

**Bases de datos.** Una base de datos es una clave que elige tu aplicación, como `shop` o `crm/v2` (una `/` se escribe `%2F` en una ruta). Una base de datos pertenece a la aplicación cuya credencial la creó; la base de datos de otra aplicación responde `404`, como si no existiera. Una credencial a nivel de organización ve todas las bases de datos de la organización.

**Colecciones: con esquema o libres.** Una colección con **esquema** declara hasta 64 campos, cada uno con un tipo: `text`, `integer`, `number`, `bool`, `datetime`, `json`, `relation` (un id de registro en una colección `target`) o `blob` (el SHA-256 de un archivo en la misma base de datos). Un campo puede ser `required`, `unique`, `indexed` o `fulltext` (en `text`). Una colección **libre** no declara nada: cada registro es un documento JSON, consultado por ruta con puntos (`profile.city`), y se le puede dar un esquema más adelante cuando todos los documentos encajen. Escribir en una colección que no existe crea una libre, cuando tu credencial puede cambiar esquemas.

**Registros y versiones.** Un registro es `{id, version, created_at, updated_at, ...fields}`. Su `id` lo genera el servicio (`rec_` más 26 caracteres ordenables) o lo eliges tú. Cada cambio sube `version` en uno; las actualizaciones y eliminaciones deben enviar `If-Match: <version>`, de modo que dos escritores nunca se sobrescriban en silencio.

**Reglas.** Una colección declara cinco reglas, `list`, `view`, `create`, `update` y `delete`. Cada una es `null` (nadie), `""` (cualquier credencial de servidor de tu organización), `public` (cualquiera, incluidas las claves de navegador), `users` (las personas con sesión iniciada de la aplicación propietaria, y los servidores), o una expresión como `owner = @auth.id`. Las reglas se aplican a toda credencial, incluida la de un administrador.

**Credenciales.** Una **clave secreta** es para servidores. Una **clave publicable** (`apb_...`) es para páginas web: funciona solo desde los orígenes que lista su aplicación y solo donde una regla la admite. El **token de acceso** de una persona con sesión iniciada lleva solo permisos de registros y archivos.

## Cómo funciona

Toda llamada lleva `Authorization: Bearer <credential>`. No hay encabezado de organización: tu organización, y la aplicación, se obtienen de la credencial, y nada en una ruta, una consulta o un encabezado puede nombrar a otra. Una solicitud sin una credencial válida, o a una ruta que no es una ruta del servicio, recibe un único `401` idéntico.

Para cada llamada el servicio primero verifica el permiso de la credencial para la acción (leer, escribir, crear, actualizar, eliminar o cambios de esquema) sobre la base de datos. Cualquier cosa distinta de "permitir" es `403 forbidden` sin detalle. Luego la regla de la colección decide por registro: una lista devuelve solo los registros que admite la regla `list`; leer un registro que la regla `view` oculta es `404`, igual que un registro inexistente; una creación verifica los datos nuevos; una actualización verifica tanto el registro almacenado como los datos nuevos.

Las escrituras llevan versión. `POST /records` crea y responde `201` con `ETag: "1"`. `PATCH` cambia los campos nombrados (en una colección libre es un parche de combinación JSON), `PUT` reemplaza el registro, y `PUT` con `If-None-Match: *` lo crea en el id que elijas. Un `If-Match` incorrecto es `409 version_conflict`; uno ausente es `428`.

Las listas toman `filter` (`field op value` unidos por `&&` y `||`), `sort`, `limit` (hasta 200) y un `cursor` opaco, y devuelven `next_cursor` hasta la última página; `q` busca en los campos `fulltext`. Un **lote** aplica hasta 100 creaciones, actualizaciones y eliminaciones en una sola transacción: todas tienen éxito, o ninguna.

Un **oyente en tiempo real** es un WebSocket en `GET .../collections/{c}/listen`: envía `ready`, luego eventos `added`, `modified` y `removed` para los registros que tu regla te permite listar. Cada llamada se registra en el [Registro de actividad](/es/products/activity/).

## Primeros pasos

Necesitas una clave secreta con permiso para crear bases de datos y colecciones ([Autenticación](/es/guides/authentication/)).

1. **Crea una base de datos.** `PUT /v1/databases/notes` sin cuerpo. La respuesta es `201` con `{key, created_at}`; repetirlo responde `200`.
2. **Declara una colección.** `PUT /v1/databases/notes/collections/items` con los campos `owner` y `body` y reglas (consulta [los ejemplos](#example)). La respuesta es la colección con `schema_version` 1.
3. **Escribe un registro.** `POST .../collections/items/records` con los campos. La respuesta es `201` con el registro, su `id` y `version` 1.
4. **Actualízalo.** `PATCH .../records/{id}` con `If-Match: 1`. La respuesta tiene `version` 2; enviar `If-Match: 1` de nuevo es `409 version_conflict`.
5. **Lista.** `GET .../records?filter=owner%20%3D%20%22me%22&limit=10` devuelve tu registro y `next_cursor: null`.

## Casos de uso

**Datos por usuario en una aplicación web.** Una aplicación de notas declara una colección cuyas cinco reglas dicen `owner = @auth.id`. La página llama a Datos directamente con el token de la persona con sesión iniciada; cada persona lista y edita solo sus propias notas, y la nota de otra persona es un `404`. Ningún código de servidor lo hace cumplir: lo hacen las reglas.

**Un catálogo público.** Una tienda en línea mantiene `products` como una colección libre con `list` y `view` en `public` y las escrituras cerradas. El escaparate la lee desde el navegador con una clave publicable; la administración la escribe desde un servidor con una clave secreta.

**Paneles en vivo.** Una pantalla de operaciones abre un oyente sobre `orders` filtrado por los pedidos abiertos de hoy. Ejecuta la consulta después de `ready`, y luego aplica los eventos `added`, `modified` y `removed` a medida que llegan, sin sondeo.

## Límites y precios

| Límite | Valor |
|---|---|
| Cuerpo de solicitud JSON | 1 MiB |
| Un registro | 900 KiB |
| Un campo `json` | 64 KiB |
| Campos por colección; colecciones por base de datos | 64; 64 |
| Registros por página | 200 (por defecto 50) |
| Operaciones por lote | 100, en una sola transacción |
| Filtro | 2,048 caracteres, 40 valores, profundidad de anidamiento 8 |
| Cadena de consulta | 16 KiB |
| Búsqueda de texto completo `q` | 16 términos, 256 caracteres |
| Oyentes por colección; un evento de oyente | 1,000; 512 KiB |
| Tasa | 600 solicitudes por minuto por titular de credencial, por ubicación (`429 rate_limited`) |

**Precios:** a consultar.

## Errores

| Estado | Código | Qué significa y qué hacer |
|---|---|---|
| 400 | `invalid_body`, `invalid_name`, `unknown_field`, `missing_field`, `invalid_value` | El cuerpo o un nombre incumple las reglas; corrígelo. |
| 400 | `record_too_large`, `field_too_large`, `reserved_field` | Reduce el registro; no envíes `id`, `version`, `created_at`, `updated_at` en un cuerpo. |
| 400 | `invalid_schema`, `invalid_rule`, `schema_change_unsupported` | La definición de la colección no es válida, o se cambió un campo en el mismo lugar. |
| 400 | `invalid_filter`, `invalid_sort`, `invalid_cursor`, `invalid_limit`, `invalid_search` | Corrige la consulta de la lista; empieza de nuevo sin el cursor. |
| 400 | `invalid_if_match`, `batch_too_large`, `cross_shard_batch` | Revisa el encabezado o divide el lote. |
| 401 | `invalid_credentials` | Envía una credencial válida. |
| 403 | `forbidden` | Los permisos de la credencial o la regla de la colección lo rechazan. |
| 403 | `origin_not_allowed`, `secret_key_in_browser` | Una clave de navegador desde un origen no listado, o una clave secreta en un navegador. |
| 404 | `database_not_found`, `collection_not_found`, `record_not_found` | No existe, o no tienes permiso para verlo. |
| 409 | `version_conflict` | Alguien cambió el registro; léelo de nuevo y reintenta. |
| 409 | `already_exists`, `unique_violation`, `not_empty`, `schema_violation` | El id o el valor ya está en uso; vacíala antes de eliminar; los documentos no encajan en el esquema. |
| 412, 428 | `precondition_failed`, `precondition_required` | El registro ya existe; envía `If-Match`. |
| 413 | `payload_too_large` | El cuerpo supera 1 MiB. |
| 429 | `rate_limited`, `too_many_listeners` | Reduce el ritmo; cierra los oyentes que no necesites. |
| 503 | `service_unavailable` | Reintenta más tarde; no se escribió nada. |

## Buenas prácticas

- **Envía siempre `If-Match`** con la versión que leíste, y ante `409 version_conflict` vuelve a leer antes de reintentar.
- **Cierra toda colección por defecto** y ábrela regla por regla; una colección nacida de una escritura admite cualquier credencial de servidor hasta que la restrinjas.
- **Nunca pongas una clave secreta en una página web**: usa una clave publicable y reglas `public` o `@auth`.
- **Elige tus propios ids de registro** para las importaciones, de modo que una importación reintentada no cree nada dos veces (`409 already_exists`).
- **Usa un lote** cuando varias escrituras deban tener éxito juntas.
- **Indexa los campos por los que filtras y ordenas**, y sigue `next_cursor` en lugar de usar páginas grandes.
- **Con un oyente, espera a `ready` antes de consultar**, y luego descarta los eventos que no sean más recientes que lo que devolvió la consulta.

## Relacionados

- [Archivos](/es/products/files/): contenido binario junto a tus registros
- [Registro de actividad](/es/products/activity/): qué se escribió, y quién lo hizo
- [Eventos](/es/products/events/): avisa a otros sistemas de un cambio
- [Autenticación](/es/guides/authentication/), [Errores](/es/guides/errors/), [Límites](/es/guides/limits/)

## Endpoints

- GET /v1/databases
- PUT /v1/databases/{database}
- PUT /v1/databases/{database}/collections/{collection}
- POST /v1/databases/{database}/collections/{collection}/records
- POST /v1/databases/{database}/batch

## Ejemplo

```sh
curl -X GET "https://data.inovacc.dev/v1/databases" -H "Authorization: Bearer $INOVACC_API_KEY"
```
