{"id":47237120,"url":"https://github.com/aborroy/alfresco-content-lake-ui","last_synced_at":"2026-03-13T23:17:25.331Z","repository":{"id":341599176,"uuid":"1159978577","full_name":"aborroy/alfresco-content-lake-ui","owner":"aborroy","description":"UI extension for Alfresco Content Lake to be used with ACA or ADW","archived":false,"fork":false,"pushed_at":"2026-03-09T17:49:31.000Z","size":63,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-09T20:54:18.077Z","etag":null,"topics":["ai","alfresco","angular","content-lake","docker","rag"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aborroy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-17T11:54:20.000Z","updated_at":"2026-03-09T17:49:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aborroy/alfresco-content-lake-ui","commit_stats":null,"previous_names":["aborroy/alfresco-content-lake-ui"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aborroy/alfresco-content-lake-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aborroy%2Falfresco-content-lake-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aborroy%2Falfresco-content-lake-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aborroy%2Falfresco-content-lake-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aborroy%2Falfresco-content-lake-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aborroy","download_url":"https://codeload.github.com/aborroy/alfresco-content-lake-ui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aborroy%2Falfresco-content-lake-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30479125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T20:45:58.186Z","status":"ssl_error","status_checked_at":"2026-03-13T20:45:20.133Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","alfresco","angular","content-lake","docker","rag"],"created_at":"2026-03-13T23:17:22.708Z","updated_at":"2026-03-13T23:17:25.325Z","avatar_url":"https://github.com/aborroy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Alfresco Content Lake UI\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n[![ADF](https://img.shields.io/badge/Alfresco%20ADF-8.4.0--21916318527-7C4DFF.svg)](https://github.com/Alfresco/alfresco-ng2-components)\n[![Angular](https://img.shields.io/badge/Angular-19.2.18-DD0031.svg)](https://angular.dev/)\n[![Nx](https://img.shields.io/badge/Nx-21.5.2-143055.svg)](https://nx.dev/)\n[![Docker](https://img.shields.io/badge/Docker-Compose-blue.svg)](https://docs.docker.com/compose/)\n[![Status](https://img.shields.io/badge/Status-PoC-yellow.svg)]()\n\n\nUI extension for [alfresco-content-lake](https://github.com/aborroy/alfresco-content-lake) that adds **semantic search** and **RAG question-answering** to Alfresco Content Application (ACA) and Alfresco Digital Workspace (ADW).\n\n## Features\n\n* Semantic search panel: free-text query with configurable `topK` / `minScore`, results grouped by document with similarity scores and expandable chunk snippets\n* Chat-style Q\u0026A: natural language questions answered via RAG, displaying the generated answer, model used, timing breakdown, and referenced source documents with chunks\n* Document-scoped mode: right-click any document and choose *\"Ask AI about this document\"* to open the chat pre-scoped to that file\n* Folder-scoped mode: right-click any folder and choose *\"Ask AI about this folder\"* to scope retrieval to that folder subtree\n* Sidebar tab: compact chat panel in the info-drawer, automatically scoped to the selected document or folder.\n* Conversation sessions: local session list with restore and *New conversation* support across route changes\n* Content Lake scope controls: right-click a folder to add or remove the `cl:indexed` aspect, or use the dedicated *Content Lake* sidebar tab\n* Document override: set `cl:excludeFromLake` on a document from the *Content Lake* sidebar to opt it out of an indexed folder subtree\n* Visual scope indicators: badges show when a folder or document is in Content Lake scope, and when a document is explicitly excluded\n* Document preview: result links open the ACA document viewer; closing the preview returns to the RAG Assistant page\n* Zero custom auth code: authentication is forwarded transparently via the ADF HTTP interceptor and a shared gateway\n\n## Prerequisites\n\n* A running [alfresco-content-lake](https://github.com/aborroy/alfresco-content-lake) deployment with `rag-service` available\n* The `content-lake-repo-model` module deployed in Alfresco Repository so `cl:indexed` and `cl:excludeFromLake` exist\n* ACA (Alfresco Content App) source checkout, or ADW (Alfresco Digital Workspace) source\n* Node.js 18+\n\n## Install into ACA\n\n### 1. Copy the extension\n\n```bash\n# From the root of your alfresco-content-app clone:\ncp -r /path/to/alfresco-content-lake-ui/ext-rag projects/ext-rag\n```\n\n### 2. Register the module\n\nEdit `app/src/app/extensions.module.ts`:\n\n```typescript\nimport { provideRagExtension } from 'projects/ext-rag/src/public-api';\n\nexport function provideApplicationExtensions(): (Provider | EnvironmentProviders)[] {\n  return [\n    ...provideRagExtension(),\n    // keep other extensions here\n  ];\n}\n```\n\n### 3. Add extension assets to the build\n\nEdit `app/project.json` and add to the `build.options.assets` array:\n\n```json\n{\n  \"glob\": \"ext-rag.plugin.json\",\n  \"input\": \"projects/ext-rag/src/assets\",\n  \"output\": \"./assets/plugins\"\n}\n```\n\n### 4. Configure the RAG service URL\n\nAdd to `app/src/app.config.json` (see [`config/app.config.snippet.json`](config/app.config.snippet.json)):\n\n```json\n{\n  \"plugins\": {\n    \"ragService\": {\n      \"baseUrl\": \"/api/rag\",\n      \"searchPath\": \"/search/semantic\",\n      \"promptPath\": \"/prompt\",\n      \"streamPath\": \"/chat/stream\"\n    },\n    \"contentLakeService\": {\n      \"baseUrl\": \"/api/content-lake\"\n    }\n  }\n}\n```\n\n### 5. Configure the dev proxy\n\nAdd to `app/proxy.conf.js` (see [`config/proxy.conf.snippet.js`](config/proxy.conf.snippet.js)):\n\n```javascript\n'/api/rag': {\n  target: 'http://localhost:9091',\n  changeOrigin: true,\n  secure: false,\n  logLevel: 'debug'\n},\n'/api/content-lake': {\n  target: 'http://localhost:9090',\n  changeOrigin: true,\n  secure: false,\n  logLevel: 'debug'\n}\n```\n\n### 6. Run\n\n```bash\nnpm start\n```\n\nOpen `http://localhost:4200`, log in, and find the *RAG Assistant* entry in the left navigation.\n\n## Accessing sidebar features\n\nUse this flow to access all sidebar-driven features from the document list:\n\n1. Open any library or folder in ACA and select a node.\n2. Click the info drawer toggle (right-side panel icon in the top toolbar) to open the right panel.\n3. In the panel header, switch to:\n   * *Ask AI* tab for compact document-scoped chat.\n   * *Content Lake* tab for scope and ingestion controls.\n\nWhat you can do from each tab:\n\n* *Ask AI* (document selected):\n  * Ask questions about the selected document directly from the sidebar.\n  * Keep context while browsing files without leaving the current page.\n* *Content Lake* (folder selected):\n  * Enable or disable Content Lake inclusion for the folder subtree.\n* *Content Lake* (document selected):\n  * Exclude or include the document from inherited Content Lake scope.\n  * Check *Ingestion status* and refresh it using the refresh icon.\n\nNotes:\n\n* Sidebar tabs appear only when the extension is correctly registered (`provideRagExtension`) and `ext-rag.plugin.json` is included in build assets.\n* *Ingestion status* requires `/api/content-lake/*` to be proxied to `batch-ingester` (see proxy/nginx sections below).\n\n## Content Lake scope controls\n\nThe extension also exposes the repository scope model introduced by `alfresco-content-lake`:\n\n* Right-click a folder and use *Enable Content Lake for this folder* or *Disable Content Lake for this folder* to add or remove `cl:indexed`\n* Open the *Content Lake* tab in the ACA info drawer to manage the same folder toggle without leaving the current view\n* Select a document inside an indexed subtree and use *Exclude this document from Content Lake* to set `cl:excludeFromLake=true`\n* Look for the `offline_bolt` badge on nodes that are currently in Content Lake scope, and the `block` badge on documents explicitly excluded from ingestion\n\nThese controls call the standard Alfresco Repository nodes API directly. No extra UI-specific backend service is required.\n\n## Install into ADW\n\nThe mechanism is identical, only the paths change since ADW uses Nx:\n\n1. Place the extension under `libs/ext-rag/` (or generate a new Nx lib and copy the source)\n2. Update `tsconfig.base.json` to map `@myorg/ext-rag` \u003e `libs/ext-rag/src/index.ts`\n3. Import `ExtRagModule` in `apps/content-ee/src/app/extension.module.ts`\n4. Add the plugin JSON asset in `angular.json` under `content-ee` build assets\n5. Configure proxy / gateway the same way\n\n## Docker deployment\n\nThe `docker` directory contains a production-ready Dockerfile that builds ACA with the ext-rag extension pre-installed:\n\n```bash\ndocker build -t alfresco-content-lake-ui -f docker/Dockerfile .\n```\n\nSee [`docker`](docker/) for details on the nginx template and runtime configuration hook.\n\n## Production deployment (nginx)\n\nAdd this block inside the `server { }` in your existing `nginx.conf` (see [`config/nginx.snippet.conf`](config/nginx.snippet.conf)):\n\n```nginx\nlocation /api/rag/ {\n  proxy_pass http://rag-service:9091/api/rag/;\n}\n\nlocation /api/content-lake/ {\n  proxy_pass http://batch-ingester:9090/api/content-lake/;\n}\n```\n\nThis ensures:\n\n* Requests from the browser go to the same origin (no CORS issues)\n* The ADF HTTP interceptor attaches the Alfresco auth ticket automatically\n* `rag-service` receives the ticket and can validate it against the Alfresco authentication API\n* `batch-ingester` serves ingestion-status lookups used by the Content Lake sidebar\n\n## Authentication flow\n\n```\nBrowser (ACA/ADW)\n  │\n  │  POST /api/rag/prompt\n  │  Header: Authorization: Basic \u003calfresco-ticket\u003e\n  │\n  ▼\nnginx / gateway\n  │\n  │  proxy_pass → rag-service:9091\n  │\n  ▼\nrag-service\n  │\n  │  Validates ticket via:\n  │  GET /alfresco/api/-default-/public/authentication/versions/1/tickets/-me-\n  │\n  ▼\nAlfresco Repository\n```\n\nNo custom authentication code is needed in the Angular module. ADF installs an HTTP interceptor that adds the ticket to every same-origin request. The gateway makes `rag-service` reachable on the same origin as Alfresco.\n\n## API contract\n\nThe extension expects the following endpoints from [alfresco-content-lake](https://github.com/aborroy/alfresco-content-lake) `rag-service`:\n\n### `POST /api/rag/search/semantic`\n\nSemantic search across indexed content-lake chunks.\n\n**Request:**\n\n```json\n{\n  \"query\": \"a girl falls in a crater\",\n  \"topK\": 5,\n  \"minScore\": 0.5\n}\n```\n\n**Response:**\n\n```json\n{\n  \"query\": \"a girl falls in a crater\",\n  \"model\": \"OpenAiEmbeddingModel\",\n  \"vectorDimension\": 1024,\n  \"resultCount\": 2,\n  \"totalCount\": 2,\n  \"searchTimeMs\": 739,\n  \"results\": [\n    {\n      \"rank\": 1,\n      \"score\": 0.5760,\n      \"chunkText\": \"found herself falling down a very deep well…\",\n      \"sourceDocument\": {\n        \"documentId\": \"c225f4d5-882b-4b99-81d1-3226af2560a4\",\n        \"nodeId\": \"e0f2943f-5e11-4f78-b294-3f5e116f7823\",\n        \"name\": \"down-the-rabbit-hole.pdf\",\n        \"path\": \"/Company Home/Sites/private/documentLibrary\",\n        \"mimeType\": \"application/pdf\"\n      },\n      \"chunkMetadata\": {\n        \"embeddingId\": \"334f91ec-4ed1-41b8-a1aa-bca6c2b1431e\",\n        \"embeddingType\": \"default\",\n        \"page\": 0,\n        \"paragraph\": 3,\n        \"chunkLength\": 773\n      }\n    }\n  ]\n}\n```\n\nThe UI groups results by `sourceDocument.nodeId`, showing one entry per document with all matching chunks listed underneath.\n\n### `POST /api/rag/prompt`\n\nRAG question-answering with optional conversation session controls.\nFor document scope, the UI translates `nodeId` into a backend `filter`\nexpression (`cin_id = '\u003cnodeId\u003e'`).\n\n**Request:**\n\n```json\n{\n  \"question\": \"Why the girl fell in the hole?\",\n  \"sessionId\": \"demo-session-1\",\n  \"resetSession\": false,\n  \"filter\": \"cin_id = 'e0f2943f-5e11-4f78-b294-3f5e116f7823'\"\n}\n```\n\n**Response:**\n\n```json\n{\n  \"answer\": \"She fell because the rabbit-hole dipped suddenly downward…\",\n  \"question\": \"Why the girl fell in the hole?\",\n  \"sessionId\": \"demo-session-1\",\n  \"retrievalQuery\": \"why the girl fell in the hole\",\n  \"historyTurnsUsed\": 2,\n  \"model\": \"model.gguf\",\n  \"tokenCount\": 672,\n  \"searchTimeMs\": 454,\n  \"generationTimeMs\": 7084,\n  \"totalTimeMs\": 7539,\n  \"sourcesUsed\": 5,\n  \"sources\": [\n    {\n      \"documentId\": \"c225f4d5-882b-4b99-81d1-3226af2560a4\",\n      \"nodeId\": \"e0f2943f-5e11-4f78-b294-3f5e116f7823\",\n      \"name\": \"down-the-rabbit-hole.pdf\",\n      \"path\": \"/Company Home/Sites/private/documentLibrary\",\n      \"chunkText\": \"found herself falling down a very deep well…\",\n      \"score\": 0.6628\n    }\n  ]\n}\n```\n\nThe UI groups sources by `nodeId`, showing one entry per document with all source chunks.\n\n### `POST /api/rag/chat/stream`\n\nStreaming RAG endpoint consumed by the chat panel for progressive rendering.\n\nExpected SSE events:\n\n- `event: token` with incremental token payload (`token`, `delta`, `text`, or `content`)\n- `event: metadata` with final response payload (`RagPromptResponse`)\n- `event: done` to close the stream\n- `event: error` for terminal stream errors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faborroy%2Falfresco-content-lake-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faborroy%2Falfresco-content-lake-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faborroy%2Falfresco-content-lake-ui/lists"}