01OverviewIntroducción
Meerkat is a self-hosted workspace for the whole company: an internal social feed and forums, project boards, a prompt backlog for AI work, training, a people directory with org chart, onboarding, hiring and payroll — all sharing the same users, groups and permissions, behind your single sign-on.
Meerkat es un espacio de trabajo self-hosted para toda la empresa: feed social interno y foros, tableros de proyectos, un backlog de prompts para el trabajo con IA, capacitación, directorio de personas con organigrama, onboarding, reclutamiento y nómina. Todo comparte los mismos usuarios, grupos y permisos, detrás de tu inicio de sesión único.
Around them: a welcome tour for new hires, an app launcher for your other SSO apps, a ⌘K command palette with global search, in-app/email/chat notifications, dark & light themes with accent colors, and an installable PWA.
Alrededor: un recorrido de bienvenida para nuevas incorporaciones, un lanzador para tus otras apps con SSO, una paleta de comandos ⌘K con búsqueda global, notificaciones en la app, por email y por chat, temas claro y oscuro con colores de acento, y una PWA instalable.
02ArchitectureArquitectura
Meerkat has two deployables: a Go backend (Fiber, one process) that owns the data and the API, and a React frontend (Vite, PWA) served from Cloudflare Pages. Pages Functions reverse-proxy the API paths to the backend, so the browser only ever talks to one origin.
Meerkat tiene dos piezas desplegables: un backend en Go (Fiber, un solo proceso) que es dueño de los datos y la API, y un frontend en React (Vite, PWA) servido desde Cloudflare Pages. Las Pages Functions hacen de proxy inverso de las rutas de la API hacia el backend, así el navegador solo habla con un origen.
- PostgreSQL is the only data store. Uploaded files (avatars, attachments, training media, resumes) live on disk under
public/uploads, next to the binary. - Redis is optional and stores sessions only. Application data is cached in-process.
- Realtime:
GET /api/liveis a Server-Sent Events stream that nudges clients to refetch. The hub is in-process, so run a single backend instance; clients fall back to polling every 2 minutes. - Background workers drain the notification queue every 20 seconds and run daily maintenance (inbox retention, time-based board automations).
- PostgreSQL es el único almacén de datos. Los archivos subidos (avatares, adjuntos, material de capacitación, CV) se guardan en disco bajo
public/uploads, junto al binario. - Redis es opcional y guarda solo sesiones. Los datos de la aplicación se cachean en memoria del proceso.
- Tiempo real:
GET /api/livees un stream de Server-Sent Events que avisa a los clientes para que vuelvan a pedir datos. El hub vive en el proceso, así que corre una sola instancia del backend; los clientes hacen polling cada 2 minutos como respaldo. - Workers en segundo plano: vacían la cola de notificaciones cada 20 segundos y corren el mantenimiento diario (retención de la bandeja, automatizaciones de tableros por tiempo).
03RequirementsRequisitos
| ComponentComponente | Version / notesVersión / notas |
|---|---|
| Go | 1.24+ |
| Node.js | 20+ (frontend build, Wrangler)(build del frontend, Wrangler) |
| PostgreSQL | Required. Any supported release (12+) works — Meerkat uses JSONB, GIN indexes and full-text search.Obligatorio. Cualquier versión con soporte (12+) sirve: Meerkat usa JSONB, índices GIN y búsqueda full-text. |
| Redis | Optional, for sessions. Strongly recommended in production — without it every restart signs everyone out.Opcional, para sesiones. Muy recomendado en producción: sin Redis, cada reinicio cierra la sesión de todos. |
| OIDC identity providerProveedor de identidad OIDC | Required — it is the only way to sign in. Built for Authentik; any standard OIDC provider exposing sub, email, preferred_username and name via userinfo should work.Obligatorio: es la única forma de iniciar sesión. Pensado para Authentik; cualquier proveedor OIDC estándar que exponga sub, email, preferred_username y name en userinfo debería funcionar. |
| libwebp + gcc + pkg-config | Only for WebP avatar encoding (CGO build). Without it, build with CGO_ENABLED=0 and avatars are stored as PNG.Solo para codificar avatares en WebP (build con CGO). Sin eso, compila con CGO_ENABLED=0 y los avatares se guardan como PNG. |
| SMTP, RocketChat | Optional, for email and chat notifications.Opcionales, para notificaciones por email y chat. |
| Cloudflare | A Pages project for the frontend (or any static host plus a reverse proxy).Un proyecto de Pages para el frontend (o cualquier hosting estático más un proxy inverso). |
04Quick start (local)Inicio rápido (local)
Starting from an empty database? Migrations only add to an existing base schema — a few core tables (for example the forum tables and some users columns) predate the migration runner. Restore a schema-only dump from an existing Meerkat deployment before the first boot:
¿Arrancas con una base vacía? Las migraciones solo agregan sobre un esquema base existente: algunas tablas centrales (por ejemplo las de foros y algunas columnas de users) son anteriores al sistema de migraciones. Restaura un dump solo de esquema de una instalación existente de Meerkat antes del primer arranque:
pg_dump --schema-only <source-db> | psql <new-db>
-
Get the code and create the configObtén el código y crea la configuración
git clone <your-meerkat-repo> meerkat && cd meerkat cp config.sample.json config.jsonEdit
config.jsonfor local development — the essentials:Edita
config.jsonpara desarrollo local; lo esencial:{ "db": { "host": "localhost", "port": 5432, "user": "meerkat", "name": "meerkat", "sslmode": "disable" }, "app": { "port": 3000, "environment": "development" }, "auth": { "cookie_secure": false, "cookie_samesite": "Lax" }, "redis": { "host": "" }, "oauth": { "client_id": "meerkat-dev", "redirect_url": "http://localhost:5173/oauth/callback", "auth_url": "https://auth.example.com/application/o/authorize/", "token_url": "https://auth.example.com/application/o/token/", "userinfo_url": "https://auth.example.com/application/o/userinfo/", "scopes": "openid email profile" } }Pass secrets through the environment rather than the file:
DB_PASSWORD,OAUTH_CLIENT_SECRET.Pasa los secretos por variables de entorno en vez del archivo:
DB_PASSWORD,OAUTH_CLIENT_SECRET. -
Run the backendLevanta el backend
# migrations apply automatically on start export DB_PASSWORD=... OAUTH_CLIENT_SECRET=... CGO_ENABLED=0 go run . # or, with libwebp installed: go build -o meerkat . && ./meerkatconfig.jsonis read from the current working directory, and the port comes only fromapp.port— there are no command-line flags. Ifapp.portis missing the server picks a random port.config.jsonse lee desde el directorio de trabajo actual y el puerto sale solo deapp.port: no hay flags de línea de comandos. Si faltaapp.port, el servidor elige un puerto al azar. -
Run the frontendLevanta el frontend
cd meerkat-app npm install npm run dev # http://localhost:5173 → proxies /api /oauth /avatars /uploads /public to :3000Backend on another port? Point the dev proxy at it:
MEERKAT_API_PROXY=http://localhost:15601 npm run dev. Also available:dev:alt(5174 → 3100),dev:b(5175 → 3200) anddev:auto.¿El backend corre en otro puerto? Apunta el proxy de desarrollo:
MEERKAT_API_PROXY=http://localhost:15601 npm run dev. También existendev:alt(5174 → 3100),dev:b(5175 → 3200) ydev:auto. -
Sign in and promote the first adminInicia sesión y promueve al primer admin
Open
http://localhost:5173and click Sign in with SSO. Your first login creates your user. There is no bootstrap admin, so grant the first one in SQL — after that, admins manage roles from Admin → Users.Abre
http://localhost:5173y haz clic en Sign in with SSO. Tu primer login crea tu usuario. No hay un admin inicial, así que otorga el primero por SQL; después, los admins gestionan los roles desde Admin → Users.UPDATE users SET is_admin = true WHERE username = '<your-preferred_username>';
Register http://localhost:5173/oauth/callback as a redirect URI in your identity provider. Since redirect_url is a single value, use a separate OIDC client (or an extra redirect URI) for development and production.
Registra http://localhost:5173/oauth/callback como redirect URI en tu proveedor de identidad. Como redirect_url es un único valor, usa un cliente OIDC separado (o un redirect URI adicional) para desarrollo y producción.
05Configuration — config.jsonConfiguración: config.json
The complete schema with defaults. Templates live in the repo as config.sample.json, config.email.sample.json and config.desktop-oauth.sample.json; config.json itself is git-ignored.
El esquema completo con sus valores por defecto. En el repo hay plantillas: config.sample.json, config.email.sample.json y config.desktop-oauth.sample.json; config.json está ignorado por git.
{
"db": {
"host": "localhost", "port": 5432, "user": "meerkat", "name": "meerkat",
"password": "", // prefer DB_PASSWORD
"sslmode": "require" // empty means "require"; use "disable" for a local Postgres
},
"app": {
"port": 15601, // no default — always set it
"environment": "production", // "production" forces secure cookies
"upload_dir": "" // default <cwd>/uploads → files under <cwd>/public/uploads
},
"oauth": {
"client_id": "", "client_secret": "", // prefer OAUTH_CLIENT_SECRET
"redirect_url": "https://meerkat.example.com/oauth/callback", // the FRONTEND origin
"auth_url": "https://auth.example.com/application/o/authorize/",
"token_url": "https://auth.example.com/application/o/token/",
"userinfo_url": "https://auth.example.com/application/o/userinfo/",
"scopes": "openid email profile"
},
"redis": { "host": "127.0.0.1", "port": 6379, "password": "", "db": 0 }, // host "" = in-memory sessions
"auth": {
"cookie_domain": "", // empty = host-only (recommended behind the Pages proxy)
"cookie_secure": true,
"cookie_samesite": "Lax" // Lax | Strict | None
},
"authentik": {
"base_url": "", // optional, derived from oauth.auth_url
"token": "", // prefer AUTHENTIK_TOKEN
"sync_enabled": false,
"sync_interval": "1h"
},
"email": {
"smtp": {
"host": "", "port": 587, "username": "", "password": "", // prefer SMTP_PASSWORD
"from_address": "", "from_name": "Meerkat",
"use_tls": false, "use_starttls": true, "insecure_skip_verify": false
}
}
}
- Sessions last 15 days in a cookie named
hr.sid(HttpOnly).auth.session_cookie_nameandauth.session_ttl_minutesexist in the schema but are not used. - Back up
<working-dir>/public/uploadstogether with the database — it holds avatars, attachments, training media and resumes.
- Las sesiones duran 15 días en una cookie llamada
hr.sid(HttpOnly).auth.session_cookie_nameyauth.session_ttl_minutesexisten en el esquema pero no se usan. - Respalda
<directorio-de-trabajo>/public/uploadsjunto con la base de datos: ahí están los avatares, adjuntos, material de capacitación y CV.
06Environment variablesVariables de entorno
A non-empty environment variable overrides the value from config.json. Use them for secrets (for example in a systemd EnvironmentFile).
Una variable de entorno no vacía reemplaza el valor de config.json. Úsalas para los secretos (por ejemplo, en un EnvironmentFile de systemd).
| VariableVariable | OverridesReemplaza |
|---|---|
DB_HOST DB_PORT DB_USER DB_PASSWORD DB_NAME DB_SSLMODE | db.* |
REDIS_HOST REDIS_PORT REDIS_PASSWORD | redis.* |
OAUTH_CLIENT_SECRET | oauth.client_secret |
SMTP_PASSWORD | email.smtp.password |
AUTHENTIK_BASE_URL AUTHENTIK_TOKEN | authentik.base_url, authentik.token |
APP_BASE_URL | Public frontend origin used in links inside emails and chat messages (fallback for the app_base_url system setting). Set it when self-hosting.Origen público del frontend que se usa en los enlaces de emails y mensajes de chat (respaldo del ajuste de sistema app_base_url). Configúralo si haces self-hosting. |
ROCKETCHAT_WEBHOOK_URL | Fallback for the rocketchat_webhook_url system setting.Respaldo del ajuste de sistema rocketchat_webhook_url. |
MEERKAT_API_PROXY, PORT | Frontend dev server only: proxy target and port.Solo para el servidor de desarrollo del frontend: destino del proxy y puerto. |
System settingsAjustes de sistema
A few runtime settings live in the system_config table and are edited by admins through GET/PUT /api/admin/config. A non-empty database value wins over the environment variable of the same name in uppercase.
Algunos ajustes viven en la tabla system_config y los editan los admins con GET/PUT /api/admin/config. Un valor no vacío en la base tiene prioridad sobre la variable de entorno del mismo nombre en mayúsculas.
curl -X PUT https://meerkat.example.com/api/admin/config \
-H 'Content-Type: application/json' --cookie 'hr.sid=…' \
-d '{"key":"app_base_url","value":"https://meerkat.example.com"}'
07Authentication & SSOAutenticación y SSO
People sign in exclusively through your OIDC provider (authorization-code flow). On first login Meerkat creates the user; afterwards the identity provider stays the source of truth for username, display name and email.
La gente inicia sesión exclusivamente a través de tu proveedor OIDC (flujo authorization code). En el primer login Meerkat crea al usuario; después, el proveedor de identidad sigue siendo la fuente de verdad para el nombre de usuario, el nombre visible y el email.
Set up AuthentikConfigura Authentik
- Create an OAuth2/OpenID providerCrea un provider OAuth2/OpenID
Client type Confidential, redirect URI
https://meerkat.example.com/oauth/callback(plus the localhost one for development), scopesopenid email profile.Tipo de cliente Confidential, redirect URI
https://meerkat.example.com/oauth/callback(más el de localhost para desarrollo), scopesopenid email profile. - Create an application bound to that providerCrea una aplicación vinculada a ese provider
Copy the client ID into
oauth.client_idand the secret intoOAUTH_CLIENT_SECRET.Copia el client ID en
oauth.client_idy el secreto enOAUTH_CLIENT_SECRET. - Fill in the endpointsCompleta los endpoints
Authentik exposes them at
/application/o/authorize/,/application/o/token/and/application/o/userinfo/.Authentik los expone en
/application/o/authorize/,/application/o/token/y/application/o/userinfo/.
The callback must be on the frontend origin: Cloudflare Pages proxies /oauth/* to the backend, and the session cookie is host-only on that origin.
El callback debe estar en el origen del frontend: Cloudflare Pages hace de proxy de /oauth/* hacia el backend y la cookie de sesión queda ligada a ese origen.
Directory sync (optional)Sincronización del directorio (opcional)
OIDC can only describe the person signing in, so Meerkat can also pull the whole directory from Authentik's REST API. That way people appear in the directory and org chart before their first login.
OIDC solo describe a la persona que inicia sesión, así que Meerkat también puede traer el directorio completo desde la API REST de Authentik. Así las personas aparecen en el directorio y el organigrama antes de su primer login.
- Create an Authentik service account allowed to read users and put its token in
AUTHENTIK_TOKEN. - Set
authentik.sync_enabled: trueand async_interval(default1h), or run it on demand from Admin → System, including a dry-run preview. - Sync creates missing people, fills empty job titles, updates emails and names, and sets a manager when the person has none (from
attributes.manager). It never deletes or deactivates anyone.
- Crea en Authentik una service account con permiso para leer usuarios y pon su token en
AUTHENTIK_TOKEN. - Configura
authentik.sync_enabled: truey unsync_interval(por defecto1h), o córrela a demanda desde Admin → System, con vista previa incluida. - La sincronización crea a las personas que faltan, completa puestos vacíos, actualiza emails y nombres, y asigna un responsable cuando la persona no tiene (desde
attributes.manager). Nunca borra ni desactiva a nadie.
08Roles & permissionsRoles y permisos
| FlagFlag | GrantsOtorga |
|---|---|
is_admin | Admin panel (users, groups, badges, skills, apps, API keys, system). Also satisfies the HR and hiring checks.Panel de admin (usuarios, grupos, insignias, habilidades, apps, API keys, sistema). También cumple los chequeos de RRHH y reclutamiento. |
can_hire | Hiring and the Talent pool.Reclutamiento y Talent pool. |
is_hr | Payroll and HR records.Nómina y registros de RRHH. |
| Board rolesRoles de tablero | owner, admin, viewer or member; boards are open or private.owner, admin, viewer o miembro; los tableros son abiertos o privados. |
Every check is enforced server-side; the sidebar simply hides modules a person can't open. Admins toggle flags in Admin → Users.
Todos los chequeos se aplican en el servidor; la barra lateral simplemente oculta los módulos que una persona no puede abrir. Los admins cambian los flags en Admin → Users.
09NotificationsNotificaciones
Assignments, comments, mentions, forum replies and reactions create notifications. Each person chooses channels and event types in Profile → Notifications.
Las asignaciones, comentarios, menciones, respuestas en foros y reacciones generan notificaciones. Cada persona elige canales y tipos de evento en Profile → Notifications.
| ChannelCanal | SetupConfiguración |
|---|---|
| In-app inboxBandeja en la app | Always on; pushed live over SSE. Read items are kept 90 days, everything else 180.Siempre activa; llega en vivo por SSE. Las leídas se guardan 90 días; el resto, 180. |
Set email.smtp in config.json (and SMTP_PASSWORD). Enabled by default per person. Test with POST /api/admin/test-email.Configura email.smtp en config.json (y SMTP_PASSWORD). Activado por defecto para cada persona. Pruébalo con POST /api/admin/test-email. | |
| RocketChat | Set the rocketchat_webhook_url and rocketchat_enabled=true system settings; each person adds their chat handle during the welcome tour or in their profile.Configura los ajustes de sistema rocketchat_webhook_url y rocketchat_enabled=true; cada persona agrega su usuario de chat en el recorrido de bienvenida o en su perfil. |
External channels are queued and delivered by a background worker every 20 seconds, with up to three retries. Set APP_BASE_URL so links point to your domain.
Los canales externos se encolan y un worker los envía cada 20 segundos, con hasta tres reintentos. Configura APP_BASE_URL para que los enlaces apunten a tu dominio.
10Database & migrationsBase de datos y migraciones
SQL migrations are embedded in the binary and applied automatically at startup, in filename order, each in its own transaction. Applied versions are tracked in schema_migrations. If one file fails it is logged and retried on the next start, while the rest still apply.
Las migraciones SQL están embebidas en el binario y se aplican solas al arrancar, en orden de nombre de archivo y cada una en su propia transacción. Las versiones aplicadas se registran en schema_migrations. Si un archivo falla, se registra en el log y se reintenta en el próximo arranque, mientras el resto se sigue aplicando.
# run the same runner by hand (reads SQL from disk)
go run ./cmd/migrate -config ./config.json -dir ./migrations
# tests
go test ./...
Writing a migration? Add migrations/migration-YYYYMMDD[x]_name.sql. Don't add your own transaction control beyond a single outer BEGIN; … COMMIT;, and keep statements idempotent (IF NOT EXISTS). Files using CONCURRENTLY run statement by statement outside a transaction.
¿Escribes una migración? Agrega migrations/migration-YYYYMMDD[x]_nombre.sql. No agregues control de transacciones propio más allá de un único BEGIN; … COMMIT; externo, y mantén las sentencias idempotentes (IF NOT EXISTS). Los archivos con CONCURRENTLY corren sentencia por sentencia fuera de una transacción.
11DeploymentDespliegue
Backend on a Linux serverBackend en un servidor Linux
Build natively on the server (CGO for WebP avatars needs gcc, pkg-config and libwebp-dev), then run the binary under systemd from the directory that holds config.json and public/uploads.
Compila directamente en el servidor (CGO para avatares WebP necesita gcc, pkg-config y libwebp-dev) y corre el binario con systemd desde el directorio que contiene config.json y public/uploads.
sudo apt install -y golang gcc pkg-config libwebp-dev
CGO_ENABLED=1 go build -o /opt/meerkat/meerkat-server .
Example unit — adjust paths and user to your server:
Unidad de ejemplo; ajusta rutas y usuario a tu servidor:
# /etc/systemd/system/meerkat.service
[Unit]
Description=Meerkat backend
After=network.target postgresql.service
[Service]
WorkingDirectory=/opt/meerkat
ExecStart=/opt/meerkat/meerkat-server
EnvironmentFile=/etc/meerkat.env # DB_PASSWORD, OAUTH_CLIENT_SECRET, AUTHENTIK_TOKEN, SMTP_PASSWORD, APP_BASE_URL
Restart=on-failure
User=meerkat
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now meerkat
journalctl -u meerkat -f
Expose the backend over HTTPS on its own origin (for example https://api.example.com) behind your usual reverse proxy. Run a single instance — realtime updates are in-process.
Expón el backend por HTTPS en su propio origen (por ejemplo https://api.example.com) detrás de tu proxy inverso habitual. Corre una sola instancia: las actualizaciones en tiempo real viven en el proceso.
The bundled deploy.shEl deploy.sh incluido
The repository ships a deploy script that checks git is in sync, compiles locally as a sanity check, rsyncs the source to the server, builds there, swaps the binary with a backup, restarts the service, health-checks Postgres and the migration log, and rolls back automatically on failure.
El repositorio incluye un script de despliegue que verifica que git esté sincronizado, compila localmente como control, sincroniza el código al servidor con rsync, compila ahí, reemplaza el binario guardando un respaldo, reinicia el servicio, chequea la salud de Postgres y el log de migraciones, y hace rollback automático si algo falla.
BACKEND_REMOTE_HOST=deploy@server.example.com \
BACKEND_REMOTE_DIR=/opt/meerkat \
SERVICE_NAME=meerkat HEALTH_PORT=15601 \
./deploy.sh all # backend | frontend | migrations | all · --dry-run --no-rollback
Frontend on Cloudflare PagesFrontend en Cloudflare Pages
- Point the proxy at your backendApunta el proxy a tu backend
The Pages Functions in
meerkat-app/functions/{api,oauth,avatars,uploads,img}/[[path]].jsforward requests to a backend origin written in each file. Replace it in all five:Las Pages Functions en
meerkat-app/functions/{api,oauth,avatars,uploads,img}/[[path]].jsreenvían las peticiones a un origen de backend escrito en cada archivo. Reemplázalo en los cinco:const backendUrl = `https://api.example.com${url.pathname}${url.search}`; - Update the other hard-coded originsActualiza los otros orígenes fijos
The CORS allow-list in
main.go, the Workbox API URL patterns inmeerkat-app/vite.config.js, and the project name inmeerkat-app/wrangler.toml/deploy.sh.La lista de CORS permitidos en
main.go, los patrones de URL de la API en Workbox enmeerkat-app/vite.config.js, y el nombre del proyecto enmeerkat-app/wrangler.toml/deploy.sh. - Build and deployCompila y despliega
cd meerkat-app npx wrangler login # first time only npm run deploy # = vite build + wrangler pages deploy dist --project-name=<project>Add your custom domain in the Pages dashboard.
_redirectsprovides the SPA fallback and_headerssets long-lived caching for hashed assets.Agrega tu dominio en el panel de Pages.
_redirectsresuelve el fallback de la SPA y_headersconfigura caché de larga duración para los assets con hash.
Uploads pass through a Pages Function, so Cloudflare's request-body limit for your plan applies (100 MB on Free/Pro) even though the backend accepts training videos up to 500 MB.
Las subidas pasan por una Pages Function, así que aplica el límite de tamaño de petición de tu plan de Cloudflare (100 MB en Free/Pro), aunque el backend acepta videos de capacitación de hasta 500 MB.
12Health & logsSalud y logs
| Endpoint | AuthAuth | ReturnsDevuelve |
|---|---|---|
GET /api/health/postgres | — | {ok, latency_ms} |
GET /api/health/redis | — | In-process cache status (despite the name)Estado de la caché en proceso (pese al nombre) |
GET /version | — | Backend build versionVersión del build del backend |
GET /api/admin/health | admin | Postgres stats, session store, cache, API-key activityEstadísticas de Postgres, almacén de sesiones, caché, actividad de API keys |
Access and application logs go to /var/log/meerkat/meerkat.log (rotated), falling back to ./logs/meerkat.log. Early boot output — config, database connection, migrations — goes to the journal. Every response carries an X-Log-Sink header with the active destination.
Los logs de acceso y de aplicación van a /var/log/meerkat/meerkat.log (con rotación) y, si no se puede, a ./logs/meerkat.log. La salida del arranque (configuración, conexión a la base, migraciones) va al journal. Cada respuesta incluye un header X-Log-Sink con el destino activo.
13REST API
Scripts, bots and internal tools use /api/v1 with API keys created in Admin → API Keys. Keys are shown once, stored hashed, can expire, and revoke instantly. Writes are authored by a system user.
Scripts, bots y herramientas internas usan /api/v1 con API keys creadas en Admin → API Keys. Las keys se muestran una sola vez, se guardan hasheadas, pueden vencer y se revocan al instante. Las escrituras quedan firmadas por un usuario de sistema.
curl https://meerkat.example.com/api/v1/feed \
-H 'Authorization: Bearer bna_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
curl -X POST https://meerkat.example.com/api/v1/tasks \
-H 'Authorization: Bearer bna_…' -H 'Content-Type: application/json' \
-d '{"board_id": 12, "title": "Rotate staging certificates"}'
| Scope | RoutesRutas |
|---|---|
feed:read / feed:write | GET /feed, GET /posts/:id, POST /posts, POST /comments |
projects:read / projects:write | GET /projects[/:id], GET /tasks/:id, POST /tasks, PATCH /tasks/:id, POST /tasks/:id/comments |
directory:read | GET /directory/people[/:id] |
search:read | GET /search?q= |
reports:read / hr:read | GET /reports/projects, /reports/activity, /reports/hiring |
Wildcards * and resource:* are accepted. The key can also be sent as X-API-Key. Errors: 401 for a missing, invalid or expired key; 403 for insufficient scope. Limits: 1000 requests/min per key.
Se aceptan los comodines * y recurso:*. La key también se puede enviar como X-API-Key. Errores: 401 si la key falta, es inválida o venció; 403 si no alcanza el scope. Límite: 1000 peticiones/min por key.
14Desktop autodiscoveryAutodiscovery de escritorio
Desktop and mobile clients can discover the OIDC configuration from the backend origin, without manual setup:
Los clientes de escritorio y móviles pueden descubrir la configuración OIDC desde el origen del backend, sin configuración manual:
curl https://api.example.com/.well-known/meerkat-desktop
{
"version": 1,
"meerkat_base_url": "https://api.example.com",
"authentik": {
"issuer": "https://auth.example.com/application/o",
"authorize_url": "…/authorize/", "token_url": "…/token/", "userinfo_url": "…/userinfo/",
"client_id": "…", "scopes": "openid email profile",
"redirect_uri": "http://localhost:34567/callback",
"pkce_required": true
}
}
This endpoint is served by the backend directly (it is not proxied by Pages) and cached for five minutes.
Este endpoint lo sirve el backend directamente (Pages no lo proxea) y se cachea cinco minutos.
15TroubleshootingSolución de problemas
“invalid oauth state” after signing in«invalid oauth state» después de iniciar sesión
The session cookie didn't survive the round-trip to the identity provider. Leave cookie_domain empty behind the Pages proxy, use cookie_secure: false on plain-HTTP development, and make sure the backend didn't restart mid-login while using in-memory sessions.
La cookie de sesión no sobrevivió al ida y vuelta con el proveedor de identidad. Deja cookie_domain vacío detrás del proxy de Pages, usa cookie_secure: false en desarrollo sin HTTPS y verifica que el backend no se haya reiniciado a mitad del login usando sesiones en memoria.
“Sign in with SSO” shows the app instead of the login page«Sign in with SSO» muestra la app en vez del login
An old service worker is serving the cached app for /oauth/login. Current builds exclude backend paths; hard-reload or unregister the service worker once.
Un service worker viejo está sirviendo la app en caché para /oauth/login. Los builds actuales excluyen las rutas del backend; haz una recarga forzada o desregistra el service worker una vez.
The identity provider rejects the redirect URIEl proveedor de identidad rechaza el redirect URI
oauth.redirect_url must match a registered redirect URI exactly and live on the frontend origin, e.g. https://meerkat.example.com/oauth/callback.
oauth.redirect_url debe coincidir exactamente con un redirect URI registrado y estar en el origen del frontend, por ejemplo https://meerkat.example.com/oauth/callback.
Everyone is signed out after every deployTodos pierden la sesión después de cada despliegue
Sessions are in memory. Configure Redis and check the boot log for using in-memory session store.
Las sesiones están en memoria. Configura Redis y busca using in-memory session store en el log de arranque.
The admin menu is missingNo aparece el menú de admin
There is no bootstrap admin. Set is_admin in SQL for the first person (see Quick start, step 4).
No hay un admin inicial. Asigna is_admin por SQL a la primera persona (ver Inicio rápido, paso 4).
go build fails on go-webpgo build falla en go-webp
libwebp headers are missing. Install libwebp-dev and pkg-config, or build with CGO_ENABLED=0 (avatars are then stored as PNG).
Faltan los headers de libwebp. Instala libwebp-dev y pkg-config, o compila con CGO_ENABLED=0 (los avatares se guardan entonces como PNG).
Local Postgres fails with an SSL errorEl Postgres local falla con un error de SSL
An empty sslmode means require. Set "sslmode": "disable" for a local database without TLS.
Un sslmode vacío equivale a require. Configura "sslmode": "disable" para una base local sin TLS.
Emails or chat messages are not deliveredNo llegan los emails o mensajes de chat
Check email.smtp.host/port in config.json, that people have an email and the channel enabled, and notification_queue.last_error. For RocketChat, set the rocketchat_enabled system setting to true — the seeded database value takes precedence over the environment variable.
Revisa email.smtp.host/port en config.json, que las personas tengan email y el canal activado, y notification_queue.last_error. Para RocketChat, pon el ajuste de sistema rocketchat_enabled en true: el valor precargado en la base tiene prioridad sobre la variable de entorno.
Board updates only reach some peopleLas actualizaciones de tableros solo le llegan a algunos
Realtime assumes one backend process. Run a single instance; clients still refresh every two minutes as a fallback.
El tiempo real asume un solo proceso de backend. Corre una sola instancia; los clientes igual se refrescan cada dos minutos como respaldo.
Links in emails point to the wrong domainLos enlaces de los emails apuntan al dominio equivocado
Set APP_BASE_URL (or the app_base_url system setting) to your frontend origin.
Configura APP_BASE_URL (o el ajuste de sistema app_base_url) con el origen de tu frontend.
Ready to see it in action?¿Listo para verlo en acción?
Click around the interactive preview on the home page.Explora la vista previa interactiva de la página principal.
Open the live previewAbrir la vista previa