{"owner":"suitenumerique","repo":"docs","hasSkills":true,"totalSkillsCount":5,"totalTokensCount":5157,"categories":["root-instruction","mcp-config","marketplace","plugin-manifest","cursor-rule"],"hasMcp":true,"mcpConfig":{"mcpServers":{"docs":{"command":"npx","args":["-y","@modelcontextprotocol/server-docs"]}}},"found":["AGENTS.md",".cursor/mcp.json",".claude-plugin/marketplace.json",".claude-plugin/plugin.json",".cursorrules (kubernetes-mkdocs-documentation-cursorrules-prompt.mdc)"],"skills":{"AGENTS.md":"# Agent Guidelines for Docs\n\nThis file contains guidelines for AI agents coding in this repository.\n\n## Project Overview\n\n**La Suite Docs** is a collaborative text editor built by DINUM (French government) and ZenDiS (German government). It features real-time editing, offline support, AI actions, and multi-format export (PDF/DOCX/ODT).\n\nRepository: https://github.com/suitenumerique/docs\n\n## Monorepo Structure\n\n- `src/backend/` - Django REST API (Python 3.14+)\n- `src/frontend/apps/impress/` - Main Next.js 15 application (TypeScript)\n- `src/frontend/apps/e2e/` - Playwright E2E tests\n- `src/frontend/packages/i18n/` - Shared i18n utilities\n- `src/frontend/packages/eslint-plugin-docs/` - Custom ESLint plugin\n- `src/frontend/servers/y-provider/` - Conversion service only (Express, `POST /api/convert/`). It no longer serves any websocket\n- `src/yhub-server/` - Collaboration server: a thin TypeScript wrapper around `@y/hub` (websockets, REST routes, worker). It holds the content of the documents\n- `src/mail/` - Email templates (MJML)\n- `src/helm/` - Kubernetes/Helm deployment\n\n## Development Commands\n\n### Setup and Services\n\n```bash\nmake bootstrap          # Full dev setup (build + migrate + demo + run)\nmake build              # Build all Docker containers\nmake run                # Start all services\nmake stop               # Stop services\nmake build-yhub         # Build the collaboration server (yhub) image\nmake migrate-yhub       # Create/upgrade the yhub database schema (`yarn init-db`), safe to re-run\nmake status             # Check running services\n```\n\n### Backend (Python/Django)\n\nTests run inside Docker containers. You must first build the backend image and ensure the `lasuite-network` Docker network exists before running tests.\n\n```bash\nmake build-backend                     # Build the backend Docker image (required before first test run)\ndocker network create lasuite-network  # Create the external network (required once)\nbin/pytest -n auto                     # Run all backend tests in parallel\nbin/pytest -n auto path/to/test        # Run specific test file/directory\nbin/pytest -n auto path/to/test.py::TestClass::test_method  # Run single test via docker compose\nmake lint                              # ruff format + ruff check + pylint\nmake lint-ruff-format                  # Format only\nmake lint-ruff-check                   # Lint only\nmake migrate                           # Run database migrations\nmake makemigrations                    # Create new migrations\nmake resetdb                           # Flush DB + create superuser (admin/admin)\n```\n\n### Frontend (TypeScript/Next.js)\n\n```bash\n# From src/frontend/apps/impress/:\nyarn dev                # Development server (port 3000)\nyarn build              # Production build (includes prettier + stylelint checks)\nyarn lint               # TypeScript check + ESLint\nyarn test               # Run Vitest tests\nyarn prettier           # Format code\nyarn stylelint          # Lint CSS\n\n# From project root:\nmake frontend-lint      # Lint all frontend workspaces\nmake frontend-test      # Run frontend tests\n```\n\n### Collaboration server (yhub, TypeScript)\n\n```bash\n# From src/yhub-server/ (standalone package: its own package.json and yarn.lock,\n# not a workspace of src/frontend):\nyarn test               # Vitest unit tests (@y/hub is mocked, no store needed)\nyarn typecheck          # tsc --noEmit\nyarn lint               # ESLint\nyarn build              # Compile to dist/\nyarn init-db            # Create/upgrade the yhub postgres schema (what `make migrate-yhub` runs)\n```\n\nThe container starts with `node --import ./dist/sentry.js dist/server.js`: keep the\n`--import` when overriding the command. `src/yhub-server/README.md` is the reference\nfor everything this server does (permissions, roles, migration, storage, metrics).\n\n### Mails\n\n```bash\nmake mails-install      # Install dependencies\nmake mails-build        # Convert MJML to HTML + plaintext\n```\n\n### Helm/Kubernetes Deployment\n\n```bash\nmake build-k8s-cluster       # Create local Kind cluster\nmake start-tilt             # Start Tilt for hot-reload\n# From src/helm/: helmfile -n impress -e dev apply/destroy/diff\n```\n\n### Dev Service URLs\n\n- Frontend: http://localhost:3000\n- Backend API/Admin: http://localhost:8071\n- Keycloak (auth): http://localhost:8083\n- MinIO (S3): http://localhost:9000\n- Collaboration server (yhub): http://localhost:3002 (websocket on `/collaboration/ws/v1/docs/{docid}`)\n- yhub PostgreSQL: localhost:5433 (its own database, apart from the backend's on 15432)\n- Mailcatcher: http://localhost:1081\n\n## Architecture\n\n### Backend\n\n- **Framework**: Django + DRF, configured via `django-configurations` (`src/backend/impress/settings.py`)\n- **Main app**: `src/backend/core/` (models, API viewsets, services, authentication)\n- **API**: REST on `/api/v1.0/` with nested routes (e.g., `/documents/{id}/accesses/`)\n- **Auth**: OIDC via `mozilla-django-oidc` (Keycloak in dev)\n- **Background tasks**: Celery + Redis\n- **Database**: PostgreSQL 16 with `django-treebeard` for document hierarchy\n- **Storage**: S3-compatible (MinIO in dev) for attachments and media. **The content of a document is not stored by the backend anymore**: it lives in the collaboration server (yhub). `Document.content`, `save_content` and the S3 object versions are gone; `file_key` only survives as a pointer for the migration of legacy documents\n- **Collaboration server client**: `core/services/yhub_services.py` (`YHubService`: `get_ydoc`, `create_ydoc`, `delete_ydoc`, `restore_ydoc`, `reset_ydoc`, `migrate`, `reset_connections`). It is called synchronously by document creation from a file, `duplicate`, `formatted-content`, and from Celery tasks for delete/restore/access changes. Mock it in tests (`CELERY_TASK_ALWAYS_EAGER=True` in the `Test` configuration, so tasks run inline)\n- **Service-to-service auth**: short-lived RS256 JWTs with an `aud` claim, never a shared bearer token. The backend signs with `JWT_PRIVATE_KEY` (`core/services/jwt_services.py`) and publishes its keys on `/api/v1.0/jwks`; yhub signs with `YHUB_JWT_PRIVATE_KEY` and publishes `/collaboration/jwks/v1`. Dev keys are generated in `data/jwt/` by `make bootstrap`\n- **Removed endpoints**: `documents/{id}/content/` (GET and PATCH), `documents/{id}/versions/`, `documents/{id}/can-edit/`. New ones: `documents/{id}/content-updated/` (called by yhub) and `documents/{id}/accesses/me/`. `documents/{id}/formatted-content/` now reads the content from yhub\n- **Legacy documents**: `python manage.py migrate_documents` hands the S3 content of existing documents to yhub (resumable, idempotent); `SOFT_MIGRATION=true` on yhub seeds a document on first open. See `UPGRADE.md`\n- **Search**: Full-text indexing via `manage.py index`\n- **Load-test tooling**: `src/backend/loadtest/` is a separate Django application that mints sessions for existing users (`create_load_test_sessions`, `revoke_load_test_sessions`). It is only installed by the `LoadTest` configuration (`DJANGO_CONFIGURATION=LoadTest`, a subclass of `Production`); `LOAD_TEST_TOOLS_ENABLED` is `False` everywhere else, pinned in `Production`, and never read from the environment. Anything added for load tests goes there, not in `core`, and must stay off in `Production`\n\n### Frontend\n\n- **Editor**: BlockNote.js 0.46.x (Tiptap-based block editor)\n- **Real-time**: Yjs with the plain `y-websocket` `WebsocketProvider` (`features/docs/doc-management/stores/useProviderStore.tsx`), and an HTTP polling fallback (`@y/yhub-http-fallback`) used while the websocket cannot be opened. Hocuspocus is gone\n- **Offline**: documents are kept locally (`y-indexeddb`) and a service worker (`features/service-worker/`) caches pages and API answers and replays queued mutations when back online\n- **Version history**: built from the activity API of yhub, not from the backend\n- **State**: Zustand (broadcast store for cross-tab sync), TanStack React Query for server state\n- **UI**: Mantine 8 + Cunningham design system\n- **Export**: BlockNote XL packages (PDF, DOCX, ODT)\n- **i18n**: i18next with Crowdin for community translations\n\n### Collaboration Flow\n\nClients connect via WebSocket to the collaboration server (`src/yhub-server`, built on `@y/hub`), authenticated by their Django session cookie.\n\n- On every connection (and permission recheck, REST call, fallback poll) yhub asks the backend who the caller is and what they may do: `GET /users/me/`, `GET /documents/{id}/`, and `GET /documents/{id}/accesses/me/` for the history. The backend stays the source of truth for access rights\n- Updates travel between replicas through Redis/Valkey streams, so yhub replicas are stateless and need no sticky sessions. A worker (`YHUB_ROLE=all|server|worker`) compacts the stream into yhub's own PostgreSQL database (optionally S3 for the blobs)\n- After a compaction that found new content, yhub calls `POST /documents/{id}/content-updated/` so that the backend updates `updated_at` and the search index\n- The backend reads and writes content through the REST routes of yhub with an admin JWT (see `YHubService`)\n\n## Observability\n\n- **Metrics** (opt-in, `PROMETHEUS_METRICS_ENABLED` + a required `PROMETHEUS_API_KEY` bearer token, both services refuse to start without the key):\n  - backend: django-prometheus on `/metrics`, deliberately outside `/api/`, protected by `core.middleware.PrometheusAuthMiddleware`. Multiprocess mode is set up automatically for the uvicorn workers. See `documentation/metrics.md`\n  - yhub: `src/yhub-server/src/metrics.ts`, served on its own port (`9464`) in every role, the worker included. See the \"Metrics\" section of `src/yhub-server/README.md`\n  - chart: `ingressMetrics` publishes `/metrics`, `/metrics/yhub` and `/metrics/yhub-worker` on a dedicated host\n  - never put a document id, a user id or a path in a metric label\n- **Sentry**: backend (`SENTRY_DSN`), y-provider, and yhub (`src/yhub-server/src/sentry.ts`, preloaded, `SENTRY_*` settings; `error`/`fatal` log lines of the shared pino logger are reported)\n- **Profiling**: django-silk, opt-in with `SILK_ENABLED` (`documentation/profiling.md`)\n- `documentation/load-testing.md` is the load-testing guide: tooling, setup of an instance, scenarios. Never against production\n- **Load generators**: `src/loadtest/k6/` (plain k6 scripts: the page-open HTTP sequence and the heavy endpoints; every request tagged with a `name` free of identifiers, CSRF by double-submit with the frontend's `Origin`) and `src/loadtest/swarm/` (standalone TypeScript package, like `src/yhub-server`) opens many Yjs clients on yhub with the frontend's client stack, reading the manifest of `create_load_test_sessions`. Tests run against an in-process y-websocket server (`__tests__/_server.ts`); `src/loadtest/canary/` (same shape, Playwright library) drives a few real Chromium pairs through the frontend to measure page open, editor ready and keystroke propagation, with the manifest's cookies (session + `csrftoken`) set on the context\n\n## Code Style Guidelines\n\n### Python (Backend)\n- **Formatter**: Ruff (line-length: 88)\n- **Linter**: Ruff + Pylint (pylint runs only on files changed from `origin/main`)\n- Imports (Ruff enforced): future, stdlib, django, third-party, impress (`core`), first-party, local\n- Naming: PascalCase classes, snake_case functions/variables, UPPER_SNAKE_CASE constants\n- **Print statements are forbidden** (T20 rule) - CI will reject them in backend code\n- Use `@transaction.atomic`, `select_related`/`prefetch_related`, type hints `list[str]`\n- Run migrations after model changes\n- In `settings.py`, `post_setup` runs after django-configurations has handed the settings to Django: change lists and dicts **in place** there (`append`, `insert`, item assignment), a reassignment is silently ignored\n- Use specific exceptions, no unused imports, double quotes, f-strings\n- **Tests**: Prefer the `settings` fixture from `pytest-django` over `django.test.override_settings`\n\n### TypeScript/React (Frontend)\n- **Formatter**: Prettier (single quotes, trailing commas, semicolons, 80 char width)\n- **Linter**: ESLint 9 with custom `eslint-plugin-docs`\n- **Style**: Stylelint for CSS\n- Imports: React & Next.js, libraries, internal, types, styles\n- Naming: PascalCase components/types, camelCase functions, `use*` hooks, UPPER_SNAKE_CASE constants\n- Strict mode, interfaces for shapes, Zustand for state, React Query for data\n\n### TypeScript (yhub-server)\n- Every environment variable is read, validated and refused at import time in `src/config.ts` (secrets through `secret()` in `src/env.ts`, which supports `NAME_FILE`): add new settings there, with a test in `__tests__/config.spec.ts`\n- Prettier style with single quotes; tests are Vitest and mock `@y/hub`\n- `@y/y` must stay the very copy `@y/hub` resolves (`__tests__/dependencies.spec.ts`)\n\n## Helm/Kubernetes Deployment\n\n### Structure\n- `helmfile.yaml.gotmpl` - Helmfile defining releases and environments\n- `impress/` - Helm chart with templates and default values\n- `env.d/{env}/` - Environment-specific values (dev=local, feature=CI)\n\n### Services\n- Backend (Django + Celery), Frontend (Next.js), yhub (collaboration server, plus an optional separate worker with `yhub.worker.enabled`), yProvider (conversion only)\n- Two standalone Valkey instances from the official `valkey/valkey` chart: `valkey-docs` (backend cache, sessions, Celery) and `valkey-yhub`\n- `dev` only (`monitoring: true` in the helmfile environment): a trimmed `kube-prometheus-stack` release (`env.d/dev/values.prometheus.yaml.gotmpl`, operator + CRDs + one Prometheus at https://docs-prometheus.127.0.0.1.nip.io) scraping the backend and yhub through the `serviceMonitor` of the chart, with the token in the `docs-metrics` Secret it creates, and a Grafana at https://docs-grafana.127.0.0.1.nip.io (admin/admin) whose sidecar loads the dashboards of `src/loadtest/dashboards/` from ConfigMaps (legend `{{` escaped for helm's tpl, as the values file explains)\n- Websocket ingress on `/collaboration/ws/` with no `upstream-hash-by`: any yhub replica serves any document\n- DocSpec (conversion), Posthog (analytics) - optional\n\n### Deployment Model\n- Kind cluster with mkcert HTTPS, local registry (localhost:5001)\n- CoreDNS for nip.io domains, dev-backend deps (Keycloak, PostgreSQL, Minio)\n\n### Helm Guidelines\n- Never commit secrets; use Got templating `{{ now | unixEpoch }}`\n- Follow semantic versioning; values use `@param` annotations\n\n## Git Conventions\n\n### Commit Format\n\n```\n<gitmoji>(type) lowercase title\n\nMandatory description explaining why.\n```\n\n- **No space** between emoji and `(type)`, **one space** after closing parenthesis\n- Types: `backend`, `frontend`, `ci`, `docker`, `dependencies`, `e2e`, `export`, `auth`, etc.\n- Gitmoji examples: `✨` feature, `🐛` fix, `♻️` refactor, `⬆️` dependency upgrade, `🔒️` security\n- Commits must be signed (`-S`) and signed-off (`--signoff`)\n\n### Changelog\n\nUpdate `CHANGELOG.md` under `[Unreleased]` with format: `- <gitmoji>(type) description` (max 80 chars per line).\n\n### PR Checklist\n\nRun before submitting: `make lint && make frontend-lint && make test`\n\n## General Practices\n\n- Commit messages should be clear and descriptive\n- Run `make lint` and tests before committing\n- Use DRF for REST APIs with proper serializers\n- Implement proper error handling with try/except blocks\n- Use Django settings for configuration\n- Internationalize user-facing strings with `_()`\n- Cache expensive operations, use database indexes\n- Write docstrings for classes and complex functions\n- Use type checking: TypeScript (frontend), mypy optional (Python)\n\n## Environment Configuration\n\nConfig files in `env.d/development/`: `common`, `postgresql`, `kc_postgresql`, `crowdin`, `yhub`, `yhub-postgres`. The collaboration server reads its own two files and none of the backend's. Create `.local` overrides (gitignored) for custom settings.\n\n## i18n\n\n```bash\nmake i18n-generate      # Extract translation strings (backend + frontend)\nmake i18n-compile       # Compile translations for all apps\n```\n\nInternationalize user-facing strings with `_()` (backend) or i18next (frontend).\n\n## Key Directories\n\n- `src/backend/` - Django REST API backend\n- `src/frontend/` - Next.js (apps/impress, packages/i18n, servers/y-provider)\n- `src/yhub-server/` - Collaboration server (yhub)\n- `src/helm/` - Helmfile and Helm chart for Kubernetes deployment\n- `src/mail/` - Email template generator (MJML)\n- `documentation/` - Documentation\n- `.github/` - GitHub workflows and templates\n",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/plugin.json)",".cursorrules (kubernetes-mkdocs-documentation-cursorrules-prompt.mdc)":"---\ndescription: \"Cursor rules for Kubernetes development with MkDocs documentation integration.\"\nglobs: **/*\nalwaysApply: false\n---\nYou are an expert Technical Writer with a deep understanding of cloud native technologies, Kubernetes, and technical documentation best practices. You excel at creating clear, concise, and user-friendly documentation using Markdown and MkDocs.\n\nYou always use the latest stable versions of Kubernetes, cloud native tools, and MkDocs. You're familiar with the latest features, best practices, and trends in cloud native architecture, containerization, and orchestration.\n\nDocumentation Style and Structure:\n\nCloud Native and Kubernetes Expertise:\n\nMkDocs Usage:\n\nContent Creation:\n\nTechnical Accuracy and Usability:\n\nDocumentation Best Practices:\n\nMetadata and SEO:\n\nCollaboration and Version Control:\n\nOther Rules to follow:\n\nDon't be lazy, provide thorough and accurate documentation for all requested topics and features.\n"},"files":{"AGENTS.md":"# Agent Guidelines for Docs\n\nThis file contains guidelines for AI agents coding in this repository.\n\n## Project Overview\n\n**La Suite Docs** is a collaborative text editor built by DINUM (French government) and ZenDiS (German government). It features real-time editing, offline support, AI actions, and multi-format export (PDF/DOCX/ODT).\n\nRepository: https://github.com/suitenumerique/docs\n\n## Monorepo Structure\n\n- `src/backend/` - Django REST API (Python 3.14+)\n- `src/frontend/apps/impress/` - Main Next.js 15 application (TypeScript)\n- `src/frontend/apps/e2e/` - Playwright E2E tests\n- `src/frontend/packages/i18n/` - Shared i18n utilities\n- `src/frontend/packages/eslint-plugin-docs/` - Custom ESLint plugin\n- `src/frontend/servers/y-provider/` - Conversion service only (Express, `POST /api/convert/`). It no longer serves any websocket\n- `src/yhub-server/` - Collaboration server: a thin TypeScript wrapper around `@y/hub` (websockets, REST routes, worker). It holds the content of the documents\n- `src/mail/` - Email templates (MJML)\n- `src/helm/` - Kubernetes/Helm deployment\n\n## Development Commands\n\n### Setup and Services\n\n```bash\nmake bootstrap          # Full dev setup (build + migrate + demo + run)\nmake build              # Build all Docker containers\nmake run                # Start all services\nmake stop               # Stop services\nmake build-yhub         # Build the collaboration server (yhub) image\nmake migrate-yhub       # Create/upgrade the yhub database schema (`yarn init-db`), safe to re-run\nmake status             # Check running services\n```\n\n### Backend (Python/Django)\n\nTests run inside Docker containers. You must first build the backend image and ensure the `lasuite-network` Docker network exists before running tests.\n\n```bash\nmake build-backend                     # Build the backend Docker image (required before first test run)\ndocker network create lasuite-network  # Create the external network (required once)\nbin/pytest -n auto                     # Run all backend tests in parallel\nbin/pytest -n auto path/to/test        # Run specific test file/directory\nbin/pytest -n auto path/to/test.py::TestClass::test_method  # Run single test via docker compose\nmake lint                              # ruff format + ruff check + pylint\nmake lint-ruff-format                  # Format only\nmake lint-ruff-check                   # Lint only\nmake migrate                           # Run database migrations\nmake makemigrations                    # Create new migrations\nmake resetdb                           # Flush DB + create superuser (admin/admin)\n```\n\n### Frontend (TypeScript/Next.js)\n\n```bash\n# From src/frontend/apps/impress/:\nyarn dev                # Development server (port 3000)\nyarn build              # Production build (includes prettier + stylelint checks)\nyarn lint               # TypeScript check + ESLint\nyarn test               # Run Vitest tests\nyarn prettier           # Format code\nyarn stylelint          # Lint CSS\n\n# From project root:\nmake frontend-lint      # Lint all frontend workspaces\nmake frontend-test      # Run frontend tests\n```\n\n### Collaboration server (yhub, TypeScript)\n\n```bash\n# From src/yhub-server/ (standalone package: its own package.json and yarn.lock,\n# not a workspace of src/frontend):\nyarn test               # Vitest unit tests (@y/hub is mocked, no store needed)\nyarn typecheck          # tsc --noEmit\nyarn lint               # ESLint\nyarn build              # Compile to dist/\nyarn init-db            # Create/upgrade the yhub postgres schema (what `make migrate-yhub` runs)\n```\n\nThe container starts with `node --import ./dist/sentry.js dist/server.js`: keep the\n`--import` when overriding the command. `src/yhub-server/README.md` is the reference\nfor everything this server does (permissions, roles, migration, storage, metrics).\n\n### Mails\n\n```bash\nmake mails-install      # Install dependencies\nmake mails-build        # Convert MJML to HTML + plaintext\n```\n\n### Helm/Kubernetes Deployment\n\n```bash\nmake build-k8s-cluster       # Create local Kind cluster\nmake start-tilt             # Start Tilt for hot-reload\n# From src/helm/: helmfile -n impress -e dev apply/destroy/diff\n```\n\n### Dev Service URLs\n\n- Frontend: http://localhost:3000\n- Backend API/Admin: http://localhost:8071\n- Keycloak (auth): http://localhost:8083\n- MinIO (S3): http://localhost:9000\n- Collaboration server (yhub): http://localhost:3002 (websocket on `/collaboration/ws/v1/docs/{docid}`)\n- yhub PostgreSQL: localhost:5433 (its own database, apart from the backend's on 15432)\n- Mailcatcher: http://localhost:1081\n\n## Architecture\n\n### Backend\n\n- **Framework**: Django + DRF, configured via `django-configurations` (`src/backend/impress/settings.py`)\n- **Main app**: `src/backend/core/` (models, API viewsets, services, authentication)\n- **API**: REST on `/api/v1.0/` with nested routes (e.g., `/documents/{id}/accesses/`)\n- **Auth**: OIDC via `mozilla-django-oidc` (Keycloak in dev)\n- **Background tasks**: Celery + Redis\n- **Database**: PostgreSQL 16 with `django-treebeard` for document hierarchy\n- **Storage**: S3-compatible (MinIO in dev) for attachments and media. **The content of a document is not stored by the backend anymore**: it lives in the collaboration server (yhub). `Document.content`, `save_content` and the S3 object versions are gone; `file_key` only survives as a pointer for the migration of legacy documents\n- **Collaboration server client**: `core/services/yhub_services.py` (`YHubService`: `get_ydoc`, `create_ydoc`, `delete_ydoc`, `restore_ydoc`, `reset_ydoc`, `migrate`, `reset_connections`). It is called synchronously by document creation from a file, `duplicate`, `formatted-content`, and from Celery tasks for delete/restore/access changes. Mock it in tests (`CELERY_TASK_ALWAYS_EAGER=True` in the `Test` configuration, so tasks run inline)\n- **Service-to-service auth**: short-lived RS256 JWTs with an `aud` claim, never a shared bearer token. The backend signs with `JWT_PRIVATE_KEY` (`core/services/jwt_services.py`) and publishes its keys on `/api/v1.0/jwks`; yhub signs with `YHUB_JWT_PRIVATE_KEY` and publishes `/collaboration/jwks/v1`. Dev keys are generated in `data/jwt/` by `make bootstrap`\n- **Removed endpoints**: `documents/{id}/content/` (GET and PATCH), `documents/{id}/versions/`, `documents/{id}/can-edit/`. New ones: `documents/{id}/content-updated/` (called by yhub) and `documents/{id}/accesses/me/`. `documents/{id}/formatted-content/` now reads the content from yhub\n- **Legacy documents**: `python manage.py migrate_documents` hands the S3 content of existing documents to yhub (resumable, idempotent); `SOFT_MIGRATION=true` on yhub seeds a document on first open. See `UPGRADE.md`\n- **Search**: Full-text indexing via `manage.py index`\n- **Load-test tooling**: `src/backend/loadtest/` is a separate Django application that mints sessions for existing users (`create_load_test_sessions`, `revoke_load_test_sessions`). It is only installed by the `LoadTest` configuration (`DJANGO_CONFIGURATION=LoadTest`, a subclass of `Production`); `LOAD_TEST_TOOLS_ENABLED` is `False` everywhere else, pinned in `Production`, and never read from the environment. Anything added for load tests goes there, not in `core`, and must stay off in `Production`\n\n### Frontend\n\n- **Editor**: BlockNote.js 0.46.x (Tiptap-based block editor)\n- **Real-time**: Yjs with the plain `y-websocket` `WebsocketProvider` (`features/docs/doc-management/stores/useProviderStore.tsx`), and an HTTP polling fallback (`@y/yhub-http-fallback`) used while the websocket cannot be opened. Hocuspocus is gone\n- **Offline**: documents are kept locally (`y-indexeddb`) and a service worker (`features/service-worker/`) caches pages and API answers and replays queued mutations when back online\n- **Version history**: built from the activity API of yhub, not from the backend\n- **State**: Zustand (broadcast store for cross-tab sync), TanStack React Query for server state\n- **UI**: Mantine 8 + Cunningham design system\n- **Export**: BlockNote XL packages (PDF, DOCX, ODT)\n- **i18n**: i18next with Crowdin for community translations\n\n### Collaboration Flow\n\nClients connect via WebSocket to the collaboration server (`src/yhub-server`, built on `@y/hub`), authenticated by their Django session cookie.\n\n- On every connection (and permission recheck, REST call, fallback poll) yhub asks the backend who the caller is and what they may do: `GET /users/me/`, `GET /documents/{id}/`, and `GET /documents/{id}/accesses/me/` for the history. The backend stays the source of truth for access rights\n- Updates travel between replicas through Redis/Valkey streams, so yhub replicas are stateless and need no sticky sessions. A worker (`YHUB_ROLE=all|server|worker`) compacts the stream into yhub's own PostgreSQL database (optionally S3 for the blobs)\n- After a compaction that found new content, yhub calls `POST /documents/{id}/content-updated/` so that the backend updates `updated_at` and the search index\n- The backend reads and writes content through the REST routes of yhub with an admin JWT (see `YHubService`)\n\n## Observability\n\n- **Metrics** (opt-in, `PROMETHEUS_METRICS_ENABLED` + a required `PROMETHEUS_API_KEY` bearer token, both services refuse to start without the key):\n  - backend: django-prometheus on `/metrics`, deliberately outside `/api/`, protected by `core.middleware.PrometheusAuthMiddleware`. Multiprocess mode is set up automatically for the uvicorn workers. See `documentation/metrics.md`\n  - yhub: `src/yhub-server/src/metrics.ts`, served on its own port (`9464`) in every role, the worker included. See the \"Metrics\" section of `src/yhub-server/README.md`\n  - chart: `ingressMetrics` publishes `/metrics`, `/metrics/yhub` and `/metrics/yhub-worker` on a dedicated host\n  - never put a document id, a user id or a path in a metric label\n- **Sentry**: backend (`SENTRY_DSN`), y-provider, and yhub (`src/yhub-server/src/sentry.ts`, preloaded, `SENTRY_*` settings; `error`/`fatal` log lines of the shared pino logger are reported)\n- **Profiling**: django-silk, opt-in with `SILK_ENABLED` (`documentation/profiling.md`)\n- `documentation/load-testing.md` is the load-testing guide: tooling, setup of an instance, scenarios. Never against production\n- **Load generators**: `src/loadtest/k6/` (plain k6 scripts: the page-open HTTP sequence and the heavy endpoints; every request tagged with a `name` free of identifiers, CSRF by double-submit with the frontend's `Origin`) and `src/loadtest/swarm/` (standalone TypeScript package, like `src/yhub-server`) opens many Yjs clients on yhub with the frontend's client stack, reading the manifest of `create_load_test_sessions`. Tests run against an in-process y-websocket server (`__tests__/_server.ts`); `src/loadtest/canary/` (same shape, Playwright library) drives a few real Chromium pairs through the frontend to measure page open, editor ready and keystroke propagation, with the manifest's cookies (session + `csrftoken`) set on the context\n\n## Code Style Guidelines\n\n### Python (Backend)\n- **Formatter**: Ruff (line-length: 88)\n- **Linter**: Ruff + Pylint (pylint runs only on files changed from `origin/main`)\n- Imports (Ruff enforced): future, stdlib, django, third-party, impress (`core`), first-party, local\n- Naming: PascalCase classes, snake_case functions/variables, UPPER_SNAKE_CASE constants\n- **Print statements are forbidden** (T20 rule) - CI will reject them in backend code\n- Use `@transaction.atomic`, `select_related`/`prefetch_related`, type hints `list[str]`\n- Run migrations after model changes\n- In `settings.py`, `post_setup` runs after django-configurations has handed the settings to Django: change lists and dicts **in place** there (`append`, `insert`, item assignment), a reassignment is silently ignored\n- Use specific exceptions, no unused imports, double quotes, f-strings\n- **Tests**: Prefer the `settings` fixture from `pytest-django` over `django.test.override_settings`\n\n### TypeScript/React (Frontend)\n- **Formatter**: Prettier (single quotes, trailing commas, semicolons, 80 char width)\n- **Linter**: ESLint 9 with custom `eslint-plugin-docs`\n- **Style**: Stylelint for CSS\n- Imports: React & Next.js, libraries, internal, types, styles\n- Naming: PascalCase components/types, camelCase functions, `use*` hooks, UPPER_SNAKE_CASE constants\n- Strict mode, interfaces for shapes, Zustand for state, React Query for data\n\n### TypeScript (yhub-server)\n- Every environment variable is read, validated and refused at import time in `src/config.ts` (secrets through `secret()` in `src/env.ts`, which supports `NAME_FILE`): add new settings there, with a test in `__tests__/config.spec.ts`\n- Prettier style with single quotes; tests are Vitest and mock `@y/hub`\n- `@y/y` must stay the very copy `@y/hub` resolves (`__tests__/dependencies.spec.ts`)\n\n## Helm/Kubernetes Deployment\n\n### Structure\n- `helmfile.yaml.gotmpl` - Helmfile defining releases and environments\n- `impress/` - Helm chart with templates and default values\n- `env.d/{env}/` - Environment-specific values (dev=local, feature=CI)\n\n### Services\n- Backend (Django + Celery), Frontend (Next.js), yhub (collaboration server, plus an optional separate worker with `yhub.worker.enabled`), yProvider (conversion only)\n- Two standalone Valkey instances from the official `valkey/valkey` chart: `valkey-docs` (backend cache, sessions, Celery) and `valkey-yhub`\n- `dev` only (`monitoring: true` in the helmfile environment): a trimmed `kube-prometheus-stack` release (`env.d/dev/values.prometheus.yaml.gotmpl`, operator + CRDs + one Prometheus at https://docs-prometheus.127.0.0.1.nip.io) scraping the backend and yhub through the `serviceMonitor` of the chart, with the token in the `docs-metrics` Secret it creates, and a Grafana at https://docs-grafana.127.0.0.1.nip.io (admin/admin) whose sidecar loads the dashboards of `src/loadtest/dashboards/` from ConfigMaps (legend `{{` escaped for helm's tpl, as the values file explains)\n- Websocket ingress on `/collaboration/ws/` with no `upstream-hash-by`: any yhub replica serves any document\n- DocSpec (conversion), Posthog (analytics) - optional\n\n### Deployment Model\n- Kind cluster with mkcert HTTPS, local registry (localhost:5001)\n- CoreDNS for nip.io domains, dev-backend deps (Keycloak, PostgreSQL, Minio)\n\n### Helm Guidelines\n- Never commit secrets; use Got templating `{{ now | unixEpoch }}`\n- Follow semantic versioning; values use `@param` annotations\n\n## Git Conventions\n\n### Commit Format\n\n```\n<gitmoji>(type) lowercase title\n\nMandatory description explaining why.\n```\n\n- **No space** between emoji and `(type)`, **one space** after closing parenthesis\n- Types: `backend`, `frontend`, `ci`, `docker`, `dependencies`, `e2e`, `export`, `auth`, etc.\n- Gitmoji examples: `✨` feature, `🐛` fix, `♻️` refactor, `⬆️` dependency upgrade, `🔒️` security\n- Commits must be signed (`-S`) and signed-off (`--signoff`)\n\n### Changelog\n\nUpdate `CHANGELOG.md` under `[Unreleased]` with format: `- <gitmoji>(type) description` (max 80 chars per line).\n\n### PR Checklist\n\nRun before submitting: `make lint && make frontend-lint && make test`\n\n## General Practices\n\n- Commit messages should be clear and descriptive\n- Run `make lint` and tests before committing\n- Use DRF for REST APIs with proper serializers\n- Implement proper error handling with try/except blocks\n- Use Django settings for configuration\n- Internationalize user-facing strings with `_()`\n- Cache expensive operations, use database indexes\n- Write docstrings for classes and complex functions\n- Use type checking: TypeScript (frontend), mypy optional (Python)\n\n## Environment Configuration\n\nConfig files in `env.d/development/`: `common`, `postgresql`, `kc_postgresql`, `crowdin`, `yhub`, `yhub-postgres`. The collaboration server reads its own two files and none of the backend's. Create `.local` overrides (gitignored) for custom settings.\n\n## i18n\n\n```bash\nmake i18n-generate      # Extract translation strings (backend + frontend)\nmake i18n-compile       # Compile translations for all apps\n```\n\nInternationalize user-facing strings with `_()` (backend) or i18next (frontend).\n\n## Key Directories\n\n- `src/backend/` - Django REST API backend\n- `src/frontend/` - Next.js (apps/impress, packages/i18n, servers/y-provider)\n- `src/yhub-server/` - Collaboration server (yhub)\n- `src/helm/` - Helmfile and Helm chart for Kubernetes deployment\n- `src/mail/` - Email template generator (MJML)\n- `documentation/` - Documentation\n- `.github/` - GitHub workflows and templates\n",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/plugin.json)",".cursorrules (kubernetes-mkdocs-documentation-cursorrules-prompt.mdc)":"---\ndescription: \"Cursor rules for Kubernetes development with MkDocs documentation integration.\"\nglobs: **/*\nalwaysApply: false\n---\nYou are an expert Technical Writer with a deep understanding of cloud native technologies, Kubernetes, and technical documentation best practices. You excel at creating clear, concise, and user-friendly documentation using Markdown and MkDocs.\n\nYou always use the latest stable versions of Kubernetes, cloud native tools, and MkDocs. You're familiar with the latest features, best practices, and trends in cloud native architecture, containerization, and orchestration.\n\nDocumentation Style and Structure:\n\nCloud Native and Kubernetes Expertise:\n\nMkDocs Usage:\n\nContent Creation:\n\nTechnical Accuracy and Usability:\n\nDocumentation Best Practices:\n\nMetadata and SEO:\n\nCollaboration and Version Control:\n\nOther Rules to follow:\n\nDon't be lazy, provide thorough and accurate documentation for all requested topics and features.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/suitenumerique/docs/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Guidelines for Docs\n\nThis file contains guidelines for AI agents coding in this repository.\n\n## Project Overview\n\n**La Suite Docs** is a collaborative text editor built by DINUM (French government) and ZenDiS (German government). It features real-time editing, offline support, AI actions, and multi-format export (PDF/DOCX/ODT).\n\nRepository: https://github.com/suitenumerique/docs\n\n## Monorepo Structure\n\n- `src/backend/` - Django REST API (Python 3.14+)\n- `src/frontend/apps/impress/` - Main Next.js 15 application (TypeScript)\n- `src/frontend/apps/e2e/` - Playwright E2E tests\n- `src/frontend/packages/i18n/` - Shared i18n utilities\n- `src/frontend/packages/eslint-plugin-docs/` - Custom ESLint plugin\n- `src/frontend/servers/y-provider/` - Conversion service only (Express, `POST /api/convert/`). It no longer serves any websocket\n- `src/yhub-server/` - Collaboration server: a thin TypeScript wrapper around `@y/hub` (websockets, REST routes, worker). It holds the content of the documents\n- `src/mail/` - Email templates (MJML)\n- `src/helm/` - Kubernetes/Helm deployment\n\n## Development Commands\n\n### Setup and Services\n\n```bash\nmake bootstrap          # Full dev setup (build + migrate + demo + run)\nmake build              # Build all Docker containers\nmake run                # Start all services\nmake stop               # Stop services\nmake build-yhub         # Build the collaboration server (yhub) image\nmake migrate-yhub       # Create/upgrade the yhub database schema (`yarn init-db`), safe to re-run\nmake status             # Check running services\n```\n\n### Backend (Python/Django)\n\nTests run inside Docker containers. You must first build the backend image and ensure the `lasuite-network` Docker network exists before running tests.\n\n```bash\nmake build-backend                     # Build the backend Docker image (required before first test run)\ndocker network create lasuite-network  # Create the external network (required once)\nbin/pytest -n auto                     # Run all backend tests in parallel\nbin/pytest -n auto path/to/test        # Run specific test file/directory\nbin/pytest -n auto path/to/test.py::TestClass::test_method  # Run single test via docker compose\nmake lint                              # ruff format + ruff check + pylint\nmake lint-ruff-format                  # Format only\nmake lint-ruff-check                   # Lint only\nmake migrate                           # Run database migrations\nmake makemigrations                    # Create new migrations\nmake resetdb                           # Flush DB + create superuser (admin/admin)\n```\n\n### Frontend (TypeScript/Next.js)\n\n```bash\n# From src/frontend/apps/impress/:\nyarn dev                # Development server (port 3000)\nyarn build              # Production build (includes prettier + stylelint checks)\nyarn lint               # TypeScript check + ESLint\nyarn test               # Run Vitest tests\nyarn prettier           # Format code\nyarn stylelint          # Lint CSS\n\n# From project root:\nmake frontend-lint      # Lint all frontend workspaces\nmake frontend-test      # Run frontend tests\n```\n\n### Collaboration server (yhub, TypeScript)\n\n```bash\n# From src/yhub-server/ (standalone package: its own package.json and yarn.lock,\n# not a workspace of src/frontend):\nyarn test               # Vitest unit tests (@y/hub is mocked, no store needed)\nyarn typecheck          # tsc --noEmit\nyarn lint               # ESLint\nyarn build              # Compile to dist/\nyarn init-db            # Create/upgrade the yhub postgres schema (what `make migrate-yhub` runs)\n```\n\nThe container starts with `node --import ./dist/sentry.js dist/server.js`: keep the\n`--import` when overriding the command. `src/yhub-server/README.md` is the reference\nfor everything this server does (permissions, roles, migration, storage, metrics).\n\n### Mails\n\n```bash\nmake mails-install      # Install dependencies\nmake mails-build        # Convert MJML to HTML + plaintext\n```\n\n### Helm/Kubernetes Deployment\n\n```bash\nmake build-k8s-cluster       # Create local Kind cluster\nmake start-tilt             # Start Tilt for hot-reload\n# From src/helm/: helmfile -n impress -e dev apply/destroy/diff\n```\n\n### Dev Service URLs\n\n- Frontend: http://localhost:3000\n- Backend API/Admin: http://localhost:8071\n- Keycloak (auth): http://localhost:8083\n- MinIO (S3): http://localhost:9000\n- Collaboration server (yhub): http://localhost:3002 (websocket on `/collaboration/ws/v1/docs/{docid}`)\n- yhub PostgreSQL: localhost:5433 (its own database, apart from the backend's on 15432)\n- Mailcatcher: http://localhost:1081\n\n## Architecture\n\n### Backend\n\n- **Framework**: Django + DRF, configured via `django-configurations` (`src/backend/impress/settings.py`)\n- **Main app**: `src/backend/core/` (models, API viewsets, services, authentication)\n- **API**: REST on `/api/v1.0/` with nested routes (e.g., `/documents/{id}/accesses/`)\n- **Auth**: OIDC via `mozilla-django-oidc` (Keycloak in dev)\n- **Background tasks**: Celery + Redis\n- **Database**: PostgreSQL 16 with `django-treebeard` for document hierarchy\n- **Storage**: S3-compatible (MinIO in dev) for attachments and media. **The content of a document is not stored by the backend anymore**: it lives in the collaboration server (yhub). `Document.content`, `save_content` and the S3 object versions are gone; `file_key` only survives as a pointer for the migration of legacy documents\n- **Collaboration server client**: `core/services/yhub_services.py` (`YHubService`: `get_ydoc`, `create_ydoc`, `delete_ydoc`, `restore_ydoc`, `reset_ydoc`, `migrate`, `reset_connections`). It is called synchronously by document creation from a file, `duplicate`, `formatted-content`, and from Celery tasks for delete/restore/access changes. Mock it in tests (`CELERY_TASK_ALWAYS_EAGER=True` in the `Test` configuration, so tasks run inline)\n- **Service-to-service auth**: short-lived RS256 JWTs with an `aud` claim, never a shared bearer token. The backend signs with `JWT_PRIVATE_KEY` (`core/services/jwt_services.py`) and publishes its keys on `/api/v1.0/jwks`; yhub signs with `YHUB_JWT_PRIVATE_KEY` and publishes `/collaboration/jwks/v1`. Dev keys are generated in `data/jwt/` by `make bootstrap`\n- **Removed endpoints**: `documents/{id}/content/` (GET and PATCH), `documents/{id}/versions/`, `documents/{id}/can-edit/`. New ones: `documents/{id}/content-updated/` (called by yhub) and `documents/{id}/accesses/me/`. `documents/{id}/formatted-content/` now reads the content from yhub\n- **Legacy documents**: `python manage.py migrate_documents` hands the S3 content of existing documents to yhub (resumable, idempotent); `SOFT_MIGRATION=true` on yhub seeds a document on first open. See `UPGRADE.md`\n- **Search**: Full-text indexing via `manage.py index`\n- **Load-test tooling**: `src/backend/loadtest/` is a separate Django application that mints sessions for existing users (`create_load_test_sessions`, `revoke_load_test_sessions`). It is only installed by the `LoadTest` configuration (`DJANGO_CONFIGURATION=LoadTest`, a subclass of `Production`); `LOAD_TEST_TOOLS_ENABLED` is `False` everywhere else, pinned in `Production`, and never read from the environment. Anything added for load tests goes there, not in `core`, and must stay off in `Production`\n\n### Frontend\n\n- **Editor**: BlockNote.js 0.46.x (Tiptap-based block editor)\n- **Real-time**: Yjs with the plain `y-websocket` `WebsocketProvider` (`features/docs/doc-management/stores/useProviderStore.tsx`), and an HTTP polling fallback (`@y/yhub-http-fallback`) used while the websocket cannot be opened. Hocuspocus is gone\n- **Offline**: documents are kept locally (`y-indexeddb`) and a service worker (`features/service-worker/`) caches pages and API answers and replays queued mutations when back online\n- **Version history**: built from the activity API of yhub, not from the backend\n- **State**: Zustand (broadcast store for cross-tab sync), TanStack React Query for server state\n- **UI**: Mantine 8 + Cunningham design system\n- **Export**: BlockNote XL packages (PDF, DOCX, ODT)\n- **i18n**: i18next with Crowdin for community translations\n\n### Collaboration Flow\n\nClients connect via WebSocket to the collaboration server (`src/yhub-server`, built on `@y/hub`), authenticated by their Django session cookie.\n\n- On every connection (and permission recheck, REST call, fallback poll) yhub asks the backend who the caller is and what they may do: `GET /users/me/`, `GET /documents/{id}/`, and `GET /documents/{id}/accesses/me/` for the history. The backend stays the source of truth for access rights\n- Updates travel between replicas through Redis/Valkey streams, so yhub replicas are stateless and need no sticky sessions. A worker (`YHUB_ROLE=all|server|worker`) compacts the stream into yhub's own PostgreSQL database (optionally S3 for the blobs)\n- After a compaction that found new content, yhub calls `POST /documents/{id}/content-updated/` so that the backend updates `updated_at` and the search index\n- The backend reads and writes content through the REST routes of yhub with an admin JWT (see `YHubService`)\n\n## Observability\n\n- **Metrics** (opt-in, `PROMETHEUS_METRICS_ENABLED` + a required `PROMETHEUS_API_KEY` bearer token, both services refuse to start without the key):\n  - backend: django-prometheus on `/metrics`, deliberately outside `/api/`, protected by `core.middleware.PrometheusAuthMiddleware`. Multiprocess mode is set up automatically for the uvicorn workers. See `documentation/metrics.md`\n  - yhub: `src/yhub-server/src/metrics.ts`, served on its own port (`9464`) in every role, the worker included. See the \"Metrics\" section of `src/yhub-server/README.md`\n  - chart: `ingressMetrics` publishes `/metrics`, `/metrics/yhub` and `/metrics/yhub-worker` on a dedicated host\n  - never put a document id, a user id or a path in a metric label\n- **Sentry**: backend (`SENTRY_DSN`), y-provider, and yhub (`src/yhub-server/src/sentry.ts`, preloaded, `SENTRY_*` settings; `error`/`fatal` log lines of the shared pino logger are reported)\n- **Profiling**: django-silk, opt-in with `SILK_ENABLED` (`documentation/profiling.md`)\n- `documentation/load-testing.md` is the load-testing guide: tooling, setup of an instance, scenarios. Never against production\n- **Load generators**: `src/loadtest/k6/` (plain k6 scripts: the page-open HTTP sequence and the heavy endpoints; every request tagged with a `name` free of identifiers, CSRF by double-submit with the frontend's `Origin`) and `src/loadtest/swarm/` (standalone TypeScript package, like `src/yhub-server`) opens many Yjs clients on yhub with the frontend's client stack, reading the manifest of `create_load_test_sessions`. Tests run against an in-process y-websocket server (`__tests__/_server.ts`); `src/loadtest/canary/` (same shape, Playwright library) drives a few real Chromium pairs through the frontend to measure page open, editor ready and keystroke propagation, with the manifest's cookies (session + `csrftoken`) set on the context\n\n## Code Style Guidelines\n\n### Python (Backend)\n- **Formatter**: Ruff (line-length: 88)\n- **Linter**: Ruff + Pylint (pylint runs only on files changed from `origin/main`)\n- Imports (Ruff enforced): future, stdlib, django, third-party, impress (`core`), first-party, local\n- Naming: PascalCase classes, snake_case functions/variables, UPPER_SNAKE_CASE constants\n- **Print statements are forbidden** (T20 rule) - CI will reject them in backend code\n- Use `@transaction.atomic`, `select_related`/`prefetch_related`, type hints `list[str]`\n- Run migrations after model changes\n- In `settings.py`, `post_setup` runs after django-configurations has handed the settings to Django: change lists and dicts **in place** there (`append`, `insert`, item assignment), a reassignment is silently ignored\n- Use specific exceptions, no unused imports, double quotes, f-strings\n- **Tests**: Prefer the `settings` fixture from `pytest-django` over `django.test.override_settings`\n\n### TypeScript/React (Frontend)\n- **Formatter**: Prettier (single quotes, trailing commas, semicolons, 80 char width)\n- **Linter**: ESLint 9 with custom `eslint-plugin-docs`\n- **Style**: Stylelint for CSS\n- Imports: React & Next.js, libraries, internal, types, styles\n- Naming: PascalCase components/types, camelCase functions, `use*` hooks, UPPER_SNAKE_CASE constants\n- Strict mode, interfaces for shapes, Zustand for state, React Query for data\n\n### TypeScript (yhub-server)\n- Every environment variable is read, validated and refused at import time in `src/config.ts` (secrets through `secret()` in `src/env.ts`, which supports `NAME_FILE`): add new settings there, with a test in `__tests__/config.spec.ts`\n- Prettier style with single quotes; tests are Vitest and mock `@y/hub`\n- `@y/y` must stay the very copy `@y/hub` resolves (`__tests__/dependencies.spec.ts`)\n\n## Helm/Kubernetes Deployment\n\n### Structure\n- `helmfile.yaml.gotmpl` - Helmfile defining releases and environments\n- `impress/` - Helm chart with templates and default values\n- `env.d/{env}/` - Environment-specific values (dev=local, feature=CI)\n\n### Services\n- Backend (Django + Celery), Frontend (Next.js), yhub (collaboration server, plus an optional separate worker with `yhub.worker.enabled`), yProvider (conversion only)\n- Two standalone Valkey instances from the official `valkey/valkey` chart: `valkey-docs` (backend cache, sessions, Celery) and `valkey-yhub`\n- `dev` only (`monitoring: true` in the helmfile environment): a trimmed `kube-prometheus-stack` release (`env.d/dev/values.prometheus.yaml.gotmpl`, operator + CRDs + one Prometheus at https://docs-prometheus.127.0.0.1.nip.io) scraping the backend and yhub through the `serviceMonitor` of the chart, with the token in the `docs-metrics` Secret it creates, and a Grafana at https://docs-grafana.127.0.0.1.nip.io (admin/admin) whose sidecar loads the dashboards of `src/loadtest/dashboards/` from ConfigMaps (legend `{{` escaped for helm's tpl, as the values file explains)\n- Websocket ingress on `/collaboration/ws/` with no `upstream-hash-by`: any yhub replica serves any document\n- DocSpec (conversion), Posthog (analytics) - optional\n\n### Deployment Model\n- Kind cluster with mkcert HTTPS, local registry (localhost:5001)\n- CoreDNS for nip.io domains, dev-backend deps (Keycloak, PostgreSQL, Minio)\n\n### Helm Guidelines\n- Never commit secrets; use Got templating `{{ now | unixEpoch }}`\n- Follow semantic versioning; values use `@param` annotations\n\n## Git Conventions\n\n### Commit Format\n\n```\n<gitmoji>(type) lowercase title\n\nMandatory description explaining why.\n```\n\n- **No space** between emoji and `(type)`, **one space** after closing parenthesis\n- Types: `backend`, `frontend`, `ci`, `docker`, `dependencies`, `e2e`, `export`, `auth`, etc.\n- Gitmoji examples: `✨` feature, `🐛` fix, `♻️` refactor, `⬆️` dependency upgrade, `🔒️` security\n- Commits must be signed (`-S`) and signed-off (`--signoff`)\n\n### Changelog\n\nUpdate `CHANGELOG.md` under `[Unreleased]` with format: `- <gitmoji>(type) description` (max 80 chars per line).\n\n### PR Checklist\n\nRun before submitting: `make lint && make frontend-lint && make test`\n\n## General Practices\n\n- Commit messages should be clear and descriptive\n- Run `make lint` and tests before committing\n- Use DRF for REST APIs with proper serializers\n- Implement proper error handling with try/except blocks\n- Use Django settings for configuration\n- Internationalize user-facing strings with `_()`\n- Cache expensive operations, use database indexes\n- Write docstrings for classes and complex functions\n- Use type checking: TypeScript (frontend), mypy optional (Python)\n\n## Environment Configuration\n\nConfig files in `env.d/development/`: `common`, `postgresql`, `kc_postgresql`, `crowdin`, `yhub`, `yhub-postgres`. The collaboration server reads its own two files and none of the backend's. Create `.local` overrides (gitignored) for custom settings.\n\n## i18n\n\n```bash\nmake i18n-generate      # Extract translation strings (backend + frontend)\nmake i18n-compile       # Compile translations for all apps\n```\n\nInternationalize user-facing strings with `_()` (backend) or i18next (frontend).\n\n## Key Directories\n\n- `src/backend/` - Django REST API backend\n- `src/frontend/` - Next.js (apps/impress, packages/i18n, servers/y-provider)\n- `src/yhub-server/` - Collaboration server (yhub)\n- `src/helm/` - Helmfile and Helm chart for Kubernetes deployment\n- `src/mail/` - Email template generator (MJML)\n- `documentation/` - Documentation\n- `.github/` - GitHub workflows and templates\n","isInternal":false,"tokens":4084,"sizeBytes":16526},{"name":"marketplace.json","path":".claude-plugin/marketplace.json","rawUrl":"https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/marketplace.json","title":"Claude Plugin Marketplace Catalog","category":"marketplace","format":"json","content":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/marketplace.json)","tokens":300,"sizeBytes":198},{"name":"plugin.json","path":".claude-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/plugin.json","title":"claude-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/plugin.json)","tokens":300,"sizeBytes":184},{"name":"mcp.json","path":".cursor/mcp.json","rawUrl":"https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.cursor/mcp.json","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"json","content":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.cursor/mcp.json)","tokens":300,"sizeBytes":177},{"name":".cursorrules","path":".cursorrules (kubernetes-mkdocs-documentation-cursorrules-prompt.mdc)","rawUrl":"https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/main/rules/kubernetes-mkdocs-documentation-cursorrules-prompt.mdc","title":"Awesome Cursorrules: kubernetes mkdocs documentation cursorrules prompt","category":"cursor-rule","format":"markdown","content":"---\ndescription: \"Cursor rules for Kubernetes development with MkDocs documentation integration.\"\nglobs: **/*\nalwaysApply: false\n---\nYou are an expert Technical Writer with a deep understanding of cloud native technologies, Kubernetes, and technical documentation best practices. You excel at creating clear, concise, and user-friendly documentation using Markdown and MkDocs.\n\nYou always use the latest stable versions of Kubernetes, cloud native tools, and MkDocs. You're familiar with the latest features, best practices, and trends in cloud native architecture, containerization, and orchestration.\n\nDocumentation Style and Structure:\n\nCloud Native and Kubernetes Expertise:\n\nMkDocs Usage:\n\nContent Creation:\n\nTechnical Accuracy and Usability:\n\nDocumentation Best Practices:\n\nMetadata and SEO:\n\nCollaboration and Version Control:\n\nOther Rules to follow:\n\nDon't be lazy, provide thorough and accurate documentation for all requested topics and features.\n","tokens":173,"sizeBytes":957}],"systemPromptSnippet":"<yakaai_skills repo=\"suitenumerique/docs\">\n<!-- File: AGENTS.md (Tokens: ~4084 | Category: root-instruction) -->\n# Agent Guidelines for Docs\n\nThis file contains guidelines for AI agents coding in this repository.\n\n## Project Overview\n\n**La Suite Docs** is a collaborative text editor built by DINUM (French government) and ZenDiS (German government). It features real-time editing, offline support, AI actions, and multi-format export (PDF/DOCX/ODT).\n\nRepository: https://github.com/suitenumerique/docs\n\n## Monorepo Structure\n\n- `src/backend/` - Django REST API (Python 3.14+)\n- `src/frontend/apps/impress/` - Main Next.js 15 application (TypeScript)\n- `src/frontend/apps/e2e/` - Playwright E2E tests\n- `src/frontend/packages/i18n/` - Shared i18n utilities\n- `src/frontend/packages/eslint-plugin-docs/` - Custom ESLint plugin\n- `src/frontend/servers/y-provider/` - Conversion service only (Express, `POST /api/convert/`). It no longer serves any websocket\n- `src/yhub-server/` - Collaboration server: a thin TypeScript wrapper around `@y/hub` (websockets, REST routes, worker). It holds the content of the documents\n- `src/mail/` - Email templates (MJML)\n- `src/helm/` - Kubernetes/Helm deployment\n\n## Development Commands\n\n### Setup and Services\n\n```bash\nmake bootstrap          # Full dev setup (build + migrate + demo + run)\nmake build              # Build all Docker containers\nmake run                # Start all services\nmake stop               # Stop services\nmake build-yhub         # Build the collaboration server (yhub) image\nmake migrate-yhub       # Create/upgrade the yhub database schema (`yarn init-db`), safe to re-run\nmake status             # Check running services\n```\n\n### Backend (Python/Django)\n\nTests run inside Docker containers. You must first build the backend image and ensure the `lasuite-network` Docker network exists before running tests.\n\n```bash\nmake build-backend                     # Build the backend Docker image (required before first test run)\ndocker network create lasuite-network  # Create the external network (required once)\nbin/pytest -n auto                     # Run all backend tests in parallel\nbin/pytest -n auto path/to/test        # Run specific test file/directory\nbin/pytest -n auto path/to/test.py::TestClass::test_method  # Run single test via docker compose\nmake lint                              # ruff format + ruff check + pylint\nmake lint-ruff-format                  # Format only\nmake lint-ruff-check                   # Lint only\nmake migrate                           # Run database migrations\nmake makemigrations                    # Create new migrations\nmake resetdb                           # Flush DB + create superuser (admin/admin)\n```\n\n### Frontend (TypeScript/Next.js)\n\n```bash\n# From src/frontend/apps/impress/:\nyarn dev                # Development server (port 3000)\nyarn build              # Production build (includes prettier + stylelint checks)\nyarn lint               # TypeScript check + ESLint\nyarn test               # Run Vitest tests\nyarn prettier           # Format code\nyarn stylelint          # Lint CSS\n\n# From project root:\nmake frontend-lint      # Lint all frontend workspaces\nmake frontend-test      # Run frontend tests\n```\n\n### Collaboration server (yhub, TypeScript)\n\n```bash\n# From src/yhub-server/ (standalone package: its own package.json and yarn.lock,\n# not a workspace of src/frontend):\nyarn test               # Vitest unit tests (@y/hub is mocked, no store needed)\nyarn typecheck          # tsc --noEmit\nyarn lint               # ESLint\nyarn build              # Compile to dist/\nyarn init-db            # Create/upgrade the yhub postgres schema (what `make migrate-yhub` runs)\n```\n\nThe container starts with `node --import ./dist/sentry.js dist/server.js`: keep the\n`--import` when overriding the command. `src/yhub-server/README.md` is the reference\nfor everything this server does (permissions, roles, migration, storage, metrics).\n\n### Mails\n\n```bash\nmake mails-install      # Install dependencies\nmake mails-build        # Convert MJML to HTML + plaintext\n```\n\n### Helm/Kubernetes Deployment\n\n```bash\nmake build-k8s-cluster       # Create local Kind cluster\nmake start-tilt             # Start Tilt for hot-reload\n# From src/helm/: helmfile -n impress -e dev apply/destroy/diff\n```\n\n### Dev Service URLs\n\n- Frontend: http://localhost:3000\n- Backend API/Admin: http://localhost:8071\n- Keycloak (auth): http://localhost:8083\n- MinIO (S3): http://localhost:9000\n- Collaboration server (yhub): http://localhost:3002 (websocket on `/collaboration/ws/v1/docs/{docid}`)\n- yhub PostgreSQL: localhost:5433 (its own database, apart from the backend's on 15432)\n- Mailcatcher: http://localhost:1081\n\n## Architecture\n\n### Backend\n\n- **Framework**: Django + DRF, configured via `django-configurations` (`src/backend/impress/settings.py`)\n- **Main app**: `src/backend/core/` (models, API viewsets, services, authentication)\n- **API**: REST on `/api/v1.0/` with nested routes (e.g., `/documents/{id}/accesses/`)\n- **Auth**: OIDC via `mozilla-django-oidc` (Keycloak in dev)\n- **Background tasks**: Celery + Redis\n- **Database**: PostgreSQL 16 with `django-treebeard` for document hierarchy\n- **Storage**: S3-compatible (MinIO in dev) for attachments and media. **The content of a document is not stored by the backend anymore**: it lives in the collaboration server (yhub). `Document.content`, `save_content` and the S3 object versions are gone; `file_key` only survives as a pointer for the migration of legacy documents\n- **Collaboration server client**: `core/services/yhub_services.py` (`YHubService`: `get_ydoc`, `create_ydoc`, `delete_ydoc`, `restore_ydoc`, `reset_ydoc`, `migrate`, `reset_connections`). It is called synchronously by document creation from a file, `duplicate`, `formatted-content`, and from Celery tasks for delete/restore/access changes. Mock it in tests (`CELERY_TASK_ALWAYS_EAGER=True` in the `Test` configuration, so tasks run inline)\n- **Service-to-service auth**: short-lived RS256 JWTs with an `aud` claim, never a shared bearer token. The backend signs with `JWT_PRIVATE_KEY` (`core/services/jwt_services.py`) and publishes its keys on `/api/v1.0/jwks`; yhub signs with `YHUB_JWT_PRIVATE_KEY` and publishes `/collaboration/jwks/v1`. Dev keys are generated in `data/jwt/` by `make bootstrap`\n- **Removed endpoints**: `documents/{id}/content/` (GET and PATCH), `documents/{id}/versions/`, `documents/{id}/can-edit/`. New ones: `documents/{id}/content-updated/` (called by yhub) and `documents/{id}/accesses/me/`. `documents/{id}/formatted-content/` now reads the content from yhub\n- **Legacy documents**: `python manage.py migrate_documents` hands the S3 content of existing documents to yhub (resumable, idempotent); `SOFT_MIGRATION=true` on yhub seeds a document on first open. See `UPGRADE.md`\n- **Search**: Full-text indexing via `manage.py index`\n- **Load-test tooling**: `src/backend/loadtest/` is a separate Django application that mints sessions for existing users (`create_load_test_sessions`, `revoke_load_test_sessions`). It is only installed by the `LoadTest` configuration (`DJANGO_CONFIGURATION=LoadTest`, a subclass of `Production`); `LOAD_TEST_TOOLS_ENABLED` is `False` everywhere else, pinned in `Production`, and never read from the environment. Anything added for load tests goes there, not in `core`, and must stay off in `Production`\n\n### Frontend\n\n- **Editor**: BlockNote.js 0.46.x (Tiptap-based block editor)\n- **Real-time**: Yjs with the plain `y-websocket` `WebsocketProvider` (`features/docs/doc-management/stores/useProviderStore.tsx`), and an HTTP polling fallback (`@y/yhub-http-fallback`) used while the websocket cannot be opened. Hocuspocus is gone\n- **Offline**: documents are kept locally (`y-indexeddb`) and a service worker (`features/service-worker/`) caches pages and API answers and replays queued mutations when back online\n- **Version history**: built from the activity API of yhub, not from the backend\n- **State**: Zustand (broadcast store for cross-tab sync), TanStack React Query for server state\n- **UI**: Mantine 8 + Cunningham design system\n- **Export**: BlockNote XL packages (PDF, DOCX, ODT)\n- **i18n**: i18next with Crowdin for community translations\n\n### Collaboration Flow\n\nClients connect via WebSocket to the collaboration server (`src/yhub-server`, built on `@y/hub`), authenticated by their Django session cookie.\n\n- On every connection (and permission recheck, REST call, fallback poll) yhub asks the backend who the caller is and what they may do: `GET /users/me/`, `GET /documents/{id}/`, and `GET /documents/{id}/accesses/me/` for the history. The backend stays the source of truth for access rights\n- Updates travel between replicas through Redis/Valkey streams, so yhub replicas are stateless and need no sticky sessions. A worker (`YHUB_ROLE=all|server|worker`) compacts the stream into yhub's own PostgreSQL database (optionally S3 for the blobs)\n- After a compaction that found new content, yhub calls `POST /documents/{id}/content-updated/` so that the backend updates `updated_at` and the search index\n- The backend reads and writes content through the REST routes of yhub with an admin JWT (see `YHubService`)\n\n## Observability\n\n- **Metrics** (opt-in, `PROMETHEUS_METRICS_ENABLED` + a required `PROMETHEUS_API_KEY` bearer token, both services refuse to start without the key):\n  - backend: django-prometheus on `/metrics`, deliberately outside `/api/`, protected by `core.middleware.PrometheusAuthMiddleware`. Multiprocess mode is set up automatically for the uvicorn workers. See `documentation/metrics.md`\n  - yhub: `src/yhub-server/src/metrics.ts`, served on its own port (`9464`) in every role, the worker included. See the \"Metrics\" section of `src/yhub-server/README.md`\n  - chart: `ingressMetrics` publishes `/metrics`, `/metrics/yhub` and `/metrics/yhub-worker` on a dedicated host\n  - never put a document id, a user id or a path in a metric label\n- **Sentry**: backend (`SENTRY_DSN`), y-provider, and yhub (`src/yhub-server/src/sentry.ts`, preloaded, `SENTRY_*` settings; `error`/`fatal` log lines of the shared pino logger are reported)\n- **Profiling**: django-silk, opt-in with `SILK_ENABLED` (`documentation/profiling.md`)\n- `documentation/load-testing.md` is the load-testing guide: tooling, setup of an instance, scenarios. Never against production\n- **Load generators**: `src/loadtest/k6/` (plain k6 scripts: the page-open HTTP sequence and the heavy endpoints; every request tagged with a `name` free of identifiers, CSRF by double-submit with the frontend's `Origin`) and `src/loadtest/swarm/` (standalone TypeScript package, like `src/yhub-server`) opens many Yjs clients on yhub with the frontend's client stack, reading the manifest of `create_load_test_sessions`. Tests run against an in-process y-websocket server (`__tests__/_server.ts`); `src/loadtest/canary/` (same shape, Playwright library) drives a few real Chromium pairs through the frontend to measure page open, editor ready and keystroke propagation, with the manifest's cookies (session + `csrftoken`) set on the context\n\n## Code Style Guidelines\n\n### Python (Backend)\n- **Formatter**: Ruff (line-length: 88)\n- **Linter**: Ruff + Pylint (pylint runs only on files changed from `origin/main`)\n- Imports (Ruff enforced): future, stdlib, django, third-party, impress (`core`), first-party, local\n- Naming: PascalCase classes, snake_case functions/variables, UPPER_SNAKE_CASE constants\n- **Print statements are forbidden** (T20 rule) - CI will reject them in backend code\n- Use `@transaction.atomic`, `select_related`/`prefetch_related`, type hints `list[str]`\n- Run migrations after model changes\n- In `settings.py`, `post_setup` runs after django-configurations has handed the settings to Django: change lists and dicts **in place** there (`append`, `insert`, item assignment), a reassignment is silently ignored\n- Use specific exceptions, no unused imports, double quotes, f-strings\n- **Tests**: Prefer the `settings` fixture from `pytest-django` over `django.test.override_settings`\n\n### TypeScript/React (Frontend)\n- **Formatter**: Prettier (single quotes, trailing commas, semicolons, 80 char width)\n- **Linter**: ESLint 9 with custom `eslint-plugin-docs`\n- **Style**: Stylelint for CSS\n- Imports: React & Next.js, libraries, internal, types, styles\n- Naming: PascalCase components/types, camelCase functions, `use*` hooks, UPPER_SNAKE_CASE constants\n- Strict mode, interfaces for shapes, Zustand for state, React Query for data\n\n### TypeScript (yhub-server)\n- Every environment variable is read, validated and refused at import time in `src/config.ts` (secrets through `secret()` in `src/env.ts`, which supports `NAME_FILE`): add new settings there, with a test in `__tests__/config.spec.ts`\n- Prettier style with single quotes; tests are Vitest and mock `@y/hub`\n- `@y/y` must stay the very copy `@y/hub` resolves (`__tests__/dependencies.spec.ts`)\n\n## Helm/Kubernetes Deployment\n\n### Structure\n- `helmfile.yaml.gotmpl` - Helmfile defining releases and environments\n- `impress/` - Helm chart with templates and default values\n- `env.d/{env}/` - Environment-specific values (dev=local, feature=CI)\n\n### Services\n- Backend (Django + Celery), Frontend (Next.js), yhub (collaboration server, plus an optional separate worker with `yhub.worker.enabled`), yProvider (conversion only)\n- Two standalone Valkey instances from the official `valkey/valkey` chart: `valkey-docs` (backend cache, sessions, Celery) and `valkey-yhub`\n- `dev` only (`monitoring: true` in the helmfile environment): a trimmed `kube-prometheus-stack` release (`env.d/dev/values.prometheus.yaml.gotmpl`, operator + CRDs + one Prometheus at https://docs-prometheus.127.0.0.1.nip.io) scraping the backend and yhub through the `serviceMonitor` of the chart, with the token in the `docs-metrics` Secret it creates, and a Grafana at https://docs-grafana.127.0.0.1.nip.io (admin/admin) whose sidecar loads the dashboards of `src/loadtest/dashboards/` from ConfigMaps (legend `{{` escaped for helm's tpl, as the values file explains)\n- Websocket ingress on `/collaboration/ws/` with no `upstream-hash-by`: any yhub replica serves any document\n- DocSpec (conversion), Posthog (analytics) - optional\n\n### Deployment Model\n- Kind cluster with mkcert HTTPS, local registry (localhost:5001)\n- CoreDNS for nip.io domains, dev-backend deps (Keycloak, PostgreSQL, Minio)\n\n### Helm Guidelines\n- Never commit secrets; use Got templating `{{ now | unixEpoch }}`\n- Follow semantic versioning; values use `@param` annotations\n\n## Git Conventions\n\n### Commit Format\n\n```\n<gitmoji>(type) lowercase title\n\nMandatory description explaining why.\n```\n\n- **No space** between emoji and `(type)`, **one space** after closing parenthesis\n- Types: `backend`, `frontend`, `ci`, `docker`, `dependencies`, `e2e`, `export`, `auth`, etc.\n- Gitmoji examples: `✨` feature, `🐛` fix, `♻️` refactor, `⬆️` dependency upgrade, `🔒️` security\n- Commits must be signed (`-S`) and signed-off (`--signoff`)\n\n### Changelog\n\nUpdate `CHANGELOG.md` under `[Unreleased]` with format: `- <gitmoji>(type) description` (max 80 chars per line).\n\n### PR Checklist\n\nRun before submitting: `make lint && make frontend-lint && make test`\n\n## General Practices\n\n- Commit messages should be clear and descriptive\n- Run `make lint` and tests before committing\n- Use DRF for REST APIs with proper serializers\n- Implement proper error handling with try/except blocks\n- Use Django settings for configuration\n- Internationalize user-facing strings with `_()`\n- Cache expensive operations, use database indexes\n- Write docstrings for classes and complex functions\n- Use type checking: TypeScript (frontend), mypy optional (Python)\n\n## Environment Configuration\n\nConfig files in `env.d/development/`: `common`, `postgresql`, `kc_postgresql`, `crowdin`, `yhub`, `yhub-postgres`. The collaboration server reads its own two files and none of the backend's. Create `.local` overrides (gitignored) for custom settings.\n\n## i18n\n\n```bash\nmake i18n-generate      # Extract translation strings (backend + frontend)\nmake i18n-compile       # Compile translations for all apps\n```\n\nInternationalize user-facing strings with `_()` (backend) or i18next (frontend).\n\n## Key Directories\n\n- `src/backend/` - Django REST API backend\n- `src/frontend/` - Next.js (apps/impress, packages/i18n, servers/y-provider)\n- `src/yhub-server/` - Collaboration server (yhub)\n- `src/helm/` - Helmfile and Helm chart for Kubernetes deployment\n- `src/mail/` - Email template generator (MJML)\n- `documentation/` - Documentation\n- `.github/` - GitHub workflows and templates\n\n<!-- File: .claude-plugin/marketplace.json (Tokens: ~300 | Category: marketplace) -->\n# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/marketplace.json)\n\n<!-- File: .claude-plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.claude-plugin/plugin.json)\n\n<!-- File: .cursor/mcp.json (Tokens: ~300 | Category: mcp-config) -->\n# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/suitenumerique/docs/HEAD/.cursor/mcp.json)\n\n<!-- File: .cursorrules (kubernetes-mkdocs-documentation-cursorrules-prompt.mdc) (Tokens: ~173 | Category: cursor-rule) -->\n---\ndescription: \"Cursor rules for Kubernetes development with MkDocs documentation integration.\"\nglobs: **/*\nalwaysApply: false\n---\nYou are an expert Technical Writer with a deep understanding of cloud native technologies, Kubernetes, and technical documentation best practices. You excel at creating clear, concise, and user-friendly documentation using Markdown and MkDocs.\n\nYou always use the latest stable versions of Kubernetes, cloud native tools, and MkDocs. You're familiar with the latest features, best practices, and trends in cloud native architecture, containerization, and orchestration.\n\nDocumentation Style and Structure:\n\nCloud Native and Kubernetes Expertise:\n\nMkDocs Usage:\n\nContent Creation:\n\nTechnical Accuracy and Usability:\n\nDocumentation Best Practices:\n\nMetadata and SEO:\n\nCollaboration and Version Control:\n\nOther Rules to follow:\n\nDon't be lazy, provide thorough and accurate documentation for all requested topics and features.\n</yakaai_skills>"}