next.config.ts activa output: "standalone". El build empaqueta solo lo
que Next.js necesita para arrancar (.next/standalone + .next/static +
public), sin el resto de node_modules.
El CLI de Prisma no viaja dentro del bundle standalone. Por eso la
imagen final incluye, aparte, un toolkit de migraciones separado (más
abajo).
next.config.ts también fuerza el file-tracing de sharp y @img con
outputFileTracingIncludes, porque el tracing automático de Next.js no
siempre los detecta al construir el bundle standalone; sin ese ajuste, el
procesamiento de imágenes falla en producción.
Al arrancar el contenedor, un script de entrypoint corre antes que
node server.js:
Crea los directorios de upload (public/uploads/avatars,
public/uploads/camellos) por si la imagen arranca sin volumen o con un
volumen montado vacío.
Aplica prisma migrate deploy usando un toolkit de Prisma (CLI, schema y
cliente generado) instalado aparte, en /migrate, precisamente porque el
CLI no está incluido en el bundle standalone.
El seed no corre en cada deploy — se asume que el entorno ya tiene
datos. Se ejecuta a mano, con npm run db:seed, solo cuando hace falta.
/salud (y GET /api/admin/health) comprueba, además de la base y de que
public/uploads sea escribible, dos señales del deploy:
Migraciones: filas de _prisma_migrations sin finished_at, o con
rolled_back_at. El proceso de Next no trae la carpeta
prisma/migrations (el CLI vive en /migrate), así que no compara
archivos pendientes.
Disco: bytes libres en public/uploads (o en el directorio de trabajo si
esa carpeta no existe). Por debajo de 100 MB el estado queda degradado.
El probe público GET /api/health sigue mirando solo la base.El recordatorio de cita no corre dentro del proceso. Un cron externo puede
llamar:
Seed o creación de un admin dentro del contenedor (si tienes shell):
npm run db:seednpm run admin:create
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"CamellApp","colors":{"primary":"#c88d2f","light":"#e0b46a","dark":"#122c51"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"camellapp","hasAudioNarration":false,"actualSubdomain":"camellapp","customDomains":["docs.camellapp.com"],"gitSource":{"type":"github","owner":"mangomorado","repo":"camellapp","deployBranch":"master","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6aec9a1f8c2847cc731fd8b8","clientVersion":"0.0.4076","searchFilterCounts":[{"language":"default","tag":"API","count":65},{"language":"default","tag":"Dominio","count":9},{"language":"default","tag":"Notifications","count":8},{"language":"default","tag":"Jobs","count":7},{"language":"default","tag":"Admin Users","count":6},{"language":"default","tag":"Agenda","count":6},{"language":"default","tag":"Me","count":6},{"language":"default","tag":"Arquitectura","count":5},{"language":"default","tag":"Admin Camellos","count":5},{"language":"default","tag":"Auth","count":5}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"docs/handbook/guias/despliegue","slug":"/docs/handbook/guias/despliegue","pageMetadata":{"title":"Despliegue","description":"Cómo se construye y arranca la imagen de CamellApp.","href":"/docs/handbook/guias/despliegue"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Cómo se construye y arranca la imagen de CamellApp.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsxs(Heading,{level:`2`,id:`build-en-modo-standalone`,children:[`Build en modo `,_jsx(_components.code,{children:`standalone`})]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`next.config.ts`}),` activa `,_jsx(_components.code,{children:`output: \"standalone\"`}),`. El build empaqueta solo lo\nque Next.js necesita para arrancar (`,_jsx(_components.code,{children:`.next/standalone`}),` + `,_jsx(_components.code,{children:`.next/static`}),` +\n`,_jsx(_components.code,{children:`public`}),`), sin el resto de `,_jsx(_components.code,{children:`node_modules`}),`.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`El CLI de Prisma `,_jsx(_components.strong,{children:`no`}),` viaja dentro del bundle standalone. Por eso la\nimagen final incluye, aparte, un toolkit de migraciones separado (más\nabajo).`]})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`next.config.ts`}),` también fuerza el file-tracing de `,_jsx(_components.code,{children:`sharp`}),` y `,_jsx(_components.code,{children:`@img`}),` con\n`,_jsx(_components.code,{children:`outputFileTracingIncludes`}),`, porque el tracing automático de Next.js no\nsiempre los detecta al construir el bundle standalone; sin ese ajuste, el\nprocesamiento de imágenes falla en producción.`]}),`\n`,_jsxs(Heading,{level:`2`,id:`arranque-docker-entrypoint-sh`,children:[`Arranque: `,_jsx(_components.code,{children:`docker-entrypoint.sh`})]}),`\n`,_jsxs(_components.p,{children:[`Al arrancar el contenedor, un script de entrypoint corre antes que\n`,_jsx(_components.code,{children:`node server.js`}),`:`]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Crea los directorios de upload (`,_jsx(_components.code,{children:`public/uploads/avatars`}),`,\n`,_jsx(_components.code,{children:`public/uploads/camellos`}),`) por si la imagen arranca sin volumen o con un\nvolumen montado vacío.`]}),`\n`,_jsxs(_components.li,{children:[`Aplica `,_jsx(_components.code,{children:`prisma migrate deploy`}),` usando un toolkit de Prisma (CLI, schema y\ncliente generado) instalado aparte, en `,_jsx(_components.code,{children:`/migrate`}),`, precisamente porque el\nCLI no está incluido en el bundle standalone.`]}),`\n`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`El seed `,_jsx(_components.strong,{children:`no`}),` corre en cada deploy — se asume que el entorno ya tiene\ndatos. Se ejecuta a mano, con `,_jsx(_components.code,{children:`npm run db:seed`}),`, solo cuando hace falta.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`salud-del-deploy`,children:`Salud del deploy`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`/salud`}),` (y `,_jsx(_components.code,{children:`GET /api/admin/health`}),`) comprueba, además de la base y de que\n`,_jsx(_components.code,{children:`public/uploads`}),` sea escribible, dos señales del deploy:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Migraciones: filas de `,_jsx(_components.code,{children:`_prisma_migrations`}),` sin `,_jsx(_components.code,{children:`finished_at`}),`, o con\n`,_jsx(_components.code,{children:`rolled_back_at`}),`. El proceso de Next no trae la carpeta\n`,_jsx(_components.code,{children:`prisma/migrations`}),` (el CLI vive en `,_jsx(_components.code,{children:`/migrate`}),`), así que no compara\narchivos pendientes.`]}),`\n`,_jsxs(_components.li,{children:[`Disco: bytes libres en `,_jsx(_components.code,{children:`public/uploads`}),` (o en el directorio de trabajo si\nesa carpeta no existe). Por debajo de 100 MB el estado queda degradado.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`El probe público `,_jsx(_components.code,{children:`GET /api/health`}),` sigue mirando solo la base.`]}),`\n`,_jsx(_components.p,{children:`El recordatorio de cita no corre dentro del proceso. Un cron externo puede\nllamar:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -fsS`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -X`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` POST`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Authorization: Bearer `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`$CRON_SECRET`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://camellapp.com/api/cron/appointment-reminders`})}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`integración-continua`,children:`Integración continua`}),`\n`,_jsxs(_components.p,{children:[`El workflow de CI corre en cada `,_jsx(_components.code,{children:`push`}),` y `,_jsx(_components.code,{children:`pull request`}),` contra `,_jsx(_components.code,{children:`master`}),`, en\nuna matriz con Node.js 22 y 25:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ci`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npx`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` prisma`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` generate`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` run`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` test`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`construir-y-ejecutar-la-imagen`,children:`Construir y ejecutar la imagen`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`docker`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -t`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` camellapp`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` .`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`docker`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` run`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --rm`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -p`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 3000:3000`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -e`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` DATABASE_URL=\"mysql://usuario:contrasena@host:3306/basededatos\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -e`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` AUTH_SECRET=\"secreto-aleatorio-largo\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -e`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` NEXTAUTH_URL=\"http://localhost:3000\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` camellapp`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Seed o creación de un admin dentro del contenedor (si tienes shell):`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` run`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` db:seed`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` run`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` admin:create`})]}),`\n`]})})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Despliegue","description":"Cómo se construye y arranca la imagen de CamellApp.","href":"/docs/handbook/guias/despliegue"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Build en modo standalone","slug":"build-en-modo-standalone","depth":2,"children":[]},{"title":"Arranque: docker-entrypoint.sh","slug":"arranque-docker-entrypoint-sh","depth":2,"children":[]},{"title":"Salud del deploy","slug":"salud-del-deploy","depth":2,"children":[]},{"title":"Integración continua","slug":"integración-continua","depth":2,"children":[]},{"title":"Construir y ejecutar la imagen","slug":"construir-y-ejecutar-la-imagen","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"camellapp","siteName":"CamellApp","title":"Despliegue - CamellApp","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-05T17:25:03.645Z","originalFileLocation":"docs/handbook/guias/despliegue.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Cómo se construye y arranca la imagen de CamellApp.\">\u003cmeta data-mint-head name=\"application-name\" content=\"CamellApp\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/camellapp/_generated/favicon/apple-touch-icon.png?v=3\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/camellapp/_generated/favicon/favicon-32x32.png?v=3\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/camellapp/_generated/favicon/favicon-16x16.png?v=3\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/camellapp/_generated/favicon/favicon.ico?v=3\">\u003cmeta data-mint-head property=\"og:title\" content=\"Despliegue - CamellApp\">\u003cmeta data-mint-head property=\"og:description\" content=\"Cómo se construye y arranca la imagen de CamellApp.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"CamellApp\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.camellapp.com/docs/handbook/guias/despliegue\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://camellapp.mintlify.site/_mintlify/api/og/v2?division=Gu%C3%ADas\u0026amp;title=Despliegue\u0026amp;description=C%C3%B3mo+se+construye+y+arranca+la+imagen+de+CamellApp.\u0026amp;theme=e6c2b81cb548feb29b388616\u0026amp;signature=2a4883c1e80a8770eaf5bd7929d8a7de068faa493bcbd84dc4793b9cfe499470\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Despliegue - CamellApp\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Cómo se construye y arranca la imagen de CamellApp.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://camellapp.mintlify.site/_mintlify/api/og/v2?division=Gu%C3%ADas\u0026amp;title=Despliegue\u0026amp;description=C%C3%B3mo+se+construye+y+arranca+la+imagen+de+CamellApp.\u0026amp;theme=e6c2b81cb548feb29b388616\u0026amp;signature=2a4883c1e80a8770eaf5bd7929d8a7de068faa493bcbd84dc4793b9cfe499470\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"https://mintlify.s3.us-west-1.amazonaws.com/camellapp/_generated/favicon/browserconfig.xml?v=3\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"CamellApp\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#c88d2f\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.camellapp.com/docs/handbook/guias/despliegue\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/handbook/guias/despliegue.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.camellapp.com/#organization\",\"name\":\"CamellApp\",\"url\":\"https://docs.camellapp.com\"},{\"@type\":\"WebSite\",\"@id\":\"https://docs.camellapp.com#website\",\"name\":\"CamellApp\",\"url\":\"https://docs.camellapp.com\",\"publisher\":{\"@id\":\"https://docs.camellapp.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue#webpage\",\"url\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue\",\"name\":\"Despliegue\",\"description\":\"Cómo se construye y arranca la imagen de CamellApp.\",\"dateModified\":\"2026-10-05T17:25:03.645Z\",\"isPartOf\":{\"@id\":\"https://docs.camellapp.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Guías\",\"item\":\"https://docs.camellapp.com/docs/handbook/guias/testing\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Despliegue\",\"item\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue#article\",\"headline\":\"Despliegue\",\"name\":\"Despliegue\",\"description\":\"Cómo se construye y arranca la imagen de CamellApp.\",\"url\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue\",\"mainEntityOfPage\":{\"@id\":\"https://docs.camellapp.com/docs/handbook/guias/despliegue#webpage\"},\"dateModified\":\"2026-10-05T17:25:03.645Z\",\"publisher\":{\"@id\":\"https://docs.camellapp.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.camellapp.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"CamellApp\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"CamellApp","nav":{"global":null,"groups":[{"group":"Inicio","pages":[{"title":"CamellApp","href":"/index"}]},{"group":"Novedades","pages":[{"title":"Novedades","href":"/docs/handbook/novedades"}]},{"group":"Empezar","pages":[{"title":"Instalación","href":"/docs/handbook/empezar/instalacion"},{"title":"Variables de entorno","href":"/docs/handbook/empezar/variables-de-entorno"}]},{"group":"Arquitectura","pages":[{"title":"Visión general","href":"/docs/handbook/arquitectura/vision-general"},{"title":"Datos y Prisma","href":"/docs/handbook/arquitectura/datos-y-prisma"},{"title":"Estructura del código","href":"/docs/handbook/arquitectura/estructura-del-codigo"},{"title":"Route handlers","href":"/docs/handbook/arquitectura/route-handlers"},{"title":"Autenticación y roles","href":"/docs/handbook/arquitectura/auth-y-roles"}]},{"group":"Dominio","pages":[{"title":"Trabajos (Jobs)","href":"/docs/handbook/dominio/jobs"},{"title":"Agenda","href":"/docs/handbook/dominio/agenda"},{"title":"Matching por score","href":"/docs/handbook/dominio/matching"},{"title":"Búsqueda conversacional","href":"/docs/handbook/dominio/busqueda"},{"title":"Precio referencial","href":"/docs/handbook/dominio/precio-referencial"},{"title":"Notificaciones","href":"/docs/handbook/dominio/notificaciones"},{"title":"Auditoría de acceso","href":"/docs/handbook/dominio/auditoria"},{"title":"Textos legales","href":"/docs/handbook/dominio/legales"},{"title":"Centro de ayuda","href":"/docs/handbook/dominio/ayuda"}]},{"group":"Guías","pages":[{"title":"Testing","href":"/docs/handbook/guias/testing"},{"title":"Añadir un endpoint","description":"Receta completa, del route handler a la documentación.","href":"/docs/handbook/guias/anadir-un-endpoint"},{"title":"Despliegue","href":"/docs/handbook/guias/despliegue"}]},{"group":"Contribuir","pages":[{"title":"Flujo de trabajo y regla de docs","description":"Cómo se documenta una feature y qué obliga a actualizar el handbook.","href":"/docs/handbook/contribuir/flujo-y-regla-de-docs"}]},{"group":"API","pages":[{"group":"Auth","pages":[{"title":"Registrar usuario con email y password","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/register","href":"/api-reference/auth/registrar-usuario-con-email-y-password"},{"title":"Registrar prestador (usuario CAMELLOS + perfil Camello)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/register/camello","href":"/api-reference/auth/registrar-prestador-usuario-camellos-+-perfil-camello"},{"title":"Pantalla/flujo de inicio de sesion NextAuth","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/auth/signin","href":"/api-reference/auth/pantallaflujo-de-inicio-de-sesion-nextauth"},{"title":"Obtener sesion actual","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/auth/session","href":"/api-reference/auth/obtener-sesion-actual"},{"title":"Cerrar sesion","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/auth/signout","href":"/api-reference/auth/cerrar-sesion"}]},{"group":"Me","pages":[{"title":"Obtener perfil del usuario autenticado","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/me","href":"/api-reference/me/obtener-perfil-del-usuario-autenticado"},{"title":"Eliminar (anonimizar) la cuenta del usuario autenticado","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml delete /api/me","href":"/api-reference/me/eliminar-anonimizar-la-cuenta-del-usuario-autenticado"},{"title":"Actualizar nombre, telefono, ciudad y/o barrio","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/me","href":"/api-reference/me/actualizar-nombre-telefono-ciudad-yo-barrio"},{"title":"Subir avatar (JPEG/PNG/WebP, max 2 MB)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/me/avatar","href":"/api-reference/me/subir-avatar-jpegpngwebp-max-2-mb"},{"title":"Cambiar contraseña","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/me/password","href":"/api-reference/me/cambiar-contraseña"},{"title":"Actualizar el precio referencial del camello autenticado","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/me/price","href":"/api-reference/me/actualizar-el-precio-referencial-del-camello-autenticado"}]},{"group":"Agenda","pages":[{"title":"Franjas semanales del camello autenticado","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/me/availability","href":"/api-reference/agenda/franjas-semanales-del-camello-autenticado"},{"title":"Reemplaza todas las franjas del camello","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml put /api/me/availability","href":"/api-reference/agenda/reemplaza-todas-las-franjas-del-camello"},{"title":"Huecos libres de 60 minutos de un camello activo","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/camellos/{id}/slots","href":"/api-reference/agenda/huecos-libres-de-60-minutos-de-un-camello-activo"},{"title":"Citas del rango, con la visibilidad de los trabajos","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/agenda","href":"/api-reference/agenda/citas-del-rango-con-la-visibilidad-de-los-trabajos"},{"title":"Recordatorio de citas en las proximas 24 horas","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/cron/appointment-reminders","href":"/api-reference/agenda/recordatorio-de-citas-en-las-proximas-24-horas"},{"title":"Fija o mueve la cita de un trabajo propio","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/jobs/{id}/schedule","href":"/api-reference/agenda/fija-o-mueve-la-cita-de-un-trabajo-propio"}]},{"group":"Camellos","pages":[{"title":"Listar camellos activos (publico)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/camellos","href":"/api-reference/camellos/listar-camellos-activos-publico"},{"title":"Metadatos publicos (conteo, oficios, ciudades)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/camellos/meta","href":"/api-reference/camellos/metadatos-publicos-conteo-oficios-ciudades"},{"title":"Crear reseña de un camello (solo CLIENTES)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/camellos/{id}/reviews","href":"/api-reference/camellos/crear-reseña-de-un-camello-solo-clientes"}]},{"group":"Categories","pages":[{"title":"Listar categorias (publico)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/categories","href":"/api-reference/categories/listar-categorias-publico"}]},{"group":"Health","pages":[{"title":"Probe publico de liveness (DB)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/health","href":"/api-reference/health/probe-publico-de-liveness-db"},{"title":"Snapshot de salud del sistema","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/health","href":"/api-reference/health/snapshot-de-salud-del-sistema"}]},{"group":"Search","pages":[{"title":"Interpretar una busqueda en lenguaje natural (publico)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/search/interpret","href":"/api-reference/search/interpretar-una-busqueda-en-lenguaje-natural-publico"},{"title":"Interpretar una foto del problema (publico)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/search/interpret-image","href":"/api-reference/search/interpretar-una-foto-del-problema-publico"}]},{"group":"Admin Users","pages":[{"title":"Listar usuarios (paginado)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/users","href":"/api-reference/admin-users/listar-usuarios-paginado"},{"title":"Crear usuario","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/admin/users","href":"/api-reference/admin-users/crear-usuario"},{"title":"Obtener usuario por ID","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/users/{id}","href":"/api-reference/admin-users/obtener-usuario-por-id"},{"title":"Eliminar usuario","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml delete /api/admin/users/{id}","href":"/api-reference/admin-users/eliminar-usuario"},{"title":"Actualizar usuario","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/admin/users/{id}","href":"/api-reference/admin-users/actualizar-usuario"},{"title":"Actualizar solo el rol de usuario","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/admin/users/{id}/role","href":"/api-reference/admin-users/actualizar-solo-el-rol-de-usuario"}]},{"group":"Admin Services","pages":[{"title":"Listar servicios","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/services","href":"/api-reference/admin-services/listar-servicios"},{"title":"Crear servicio","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/admin/services","href":"/api-reference/admin-services/crear-servicio"},{"title":"Eliminar servicio","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml delete /api/admin/services/{id}","href":"/api-reference/admin-services/eliminar-servicio"},{"title":"Actualizar servicio","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/admin/services/{id}","href":"/api-reference/admin-services/actualizar-servicio"}]},{"group":"Admin Categories","pages":[{"title":"Listar categorias (con conteo de servicios)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/categories","href":"/api-reference/admin-categories/listar-categorias-con-conteo-de-servicios"},{"title":"Crear categoria","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/admin/categories","href":"/api-reference/admin-categories/crear-categoria"},{"title":"Eliminar categoria","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml delete /api/admin/categories/{id}","href":"/api-reference/admin-categories/eliminar-categoria"},{"title":"Actualizar categoria","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/admin/categories/{id}","href":"/api-reference/admin-categories/actualizar-categoria"}]},{"group":"Admin Camellos","pages":[{"title":"Listar camellos (admin)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/camellos","href":"/api-reference/admin-camellos/listar-camellos-admin"},{"title":"Crear camello (JSON o multipart con foto)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/admin/camellos","href":"/api-reference/admin-camellos/crear-camello-json-o-multipart-con-foto"},{"title":"Obtener camello por ID","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/camellos/{id}","href":"/api-reference/admin-camellos/obtener-camello-por-id"},{"title":"Eliminar camello (hard delete)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml delete /api/admin/camellos/{id}","href":"/api-reference/admin-camellos/eliminar-camello-hard-delete"},{"title":"Actualizar camello (JSON o multipart)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/admin/camellos/{id}","href":"/api-reference/admin-camellos/actualizar-camello-json-o-multipart"}]},{"group":"Jobs","pages":[{"title":"Listar trabajos del usuario autenticado","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/jobs","href":"/api-reference/jobs/listar-trabajos-del-usuario-autenticado"},{"title":"Crear solicitud de trabajo","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/jobs","href":"/api-reference/jobs/crear-solicitud-de-trabajo"},{"title":"Detalle de un trabajo visible para el usuario","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/jobs/{id}","href":"/api-reference/jobs/detalle-de-un-trabajo-visible-para-el-usuario"},{"title":"Camello acepta un trabajo pendiente","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/jobs/{id}/accept","href":"/api-reference/jobs/camello-acepta-un-trabajo-pendiente"},{"title":"Camello rechaza un trabajo pendiente","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/jobs/{id}/reject","href":"/api-reference/jobs/camello-rechaza-un-trabajo-pendiente"},{"title":"Marcar trabajo en progreso como completado","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/jobs/{id}/complete","href":"/api-reference/jobs/marcar-trabajo-en-progreso-como-completado"},{"title":"Cancelar un trabajo pendiente o en progreso","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/jobs/{id}/cancel","href":"/api-reference/jobs/cancelar-un-trabajo-pendiente-o-en-progreso"}]},{"group":"Admin Jobs","pages":[{"title":"Asignar un camello a un trabajo pendiente libre","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/admin/jobs/{id}/assign","href":"/api-reference/admin-jobs/asignar-un-camello-a-un-trabajo-pendiente-libre"},{"title":"Ranking de camellos candidatos para un trabajo","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/jobs/{id}/candidates","href":"/api-reference/admin-jobs/ranking-de-camellos-candidatos-para-un-trabajo"}]},{"group":"Notifications","pages":[{"title":"Listar inbox del usuario","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/notifications","href":"/api-reference/notifications/listar-inbox-del-usuario"},{"title":"Marcar notificacion como leida","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/notifications/{id}/read","href":"/api-reference/notifications/marcar-notificacion-como-leida"},{"title":"Marcar todas como leidas","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/notifications/read-all","href":"/api-reference/notifications/marcar-todas-como-leidas"},{"title":"Clave publica VAPID","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/notifications/push/vapid","href":"/api-reference/notifications/clave-publica-vapid"},{"title":"Guardar suscripcion Web Push","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml post /api/notifications/push/subscribe","href":"/api-reference/notifications/guardar-suscripcion-web-push"},{"title":"Eliminar suscripcion Web Push","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml delete /api/notifications/push/subscribe","href":"/api-reference/notifications/eliminar-suscripcion-web-push"},{"title":"Preferencias de canal","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/me/notification-preferences","href":"/api-reference/notifications/preferencias-de-canal"},{"title":"Actualizar preferencia de canal","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml patch /api/me/notification-preferences","href":"/api-reference/notifications/actualizar-preferencia-de-canal"}]},{"group":"Admin Notifications","pages":[{"title":"Listar envios (deliveries)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/notifications","href":"/api-reference/admin-notifications/listar-envios-deliveries"}]},{"group":"Admin Legal","pages":[{"title":"Listar textos legales editables","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/legal-documents","href":"/api-reference/admin-legal/listar-textos-legales-editables"},{"title":"Publicar una version de un texto legal","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml put /api/admin/legal-documents/{slug}","href":"/api-reference/admin-legal/publicar-una-version-de-un-texto-legal"}]},{"group":"Admin Meta","pages":[{"title":"Obtener especificación OpenAPI (YAML)","deprecated":null,"version":null,"openapi":"/docs/openapi-auth.yaml get /api/admin/openapi","href":"/api-reference/admin-meta/obtener-especificación-openapi-yaml"}]}]}]},"basePath":"","title":"Despliegue - CamellApp","buildId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","deploymentId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","dynamics":[],"chunks":[]}