diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 261cd95..815c4f8 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,14 +2,14 @@ {"id":"ifcurl-4l7","title":"viewer.html: scale= URLs don't load in orthographic mode","description":"applyCameraParam() reads the camera= and fov= parameters from the URL and applies them, but never reads scale= or switches the camera to orthographic (parallel) projection. URLs like ?camera=...\u0026scale=50 will load in perspective mode instead of orthographic. The OBC OrthoPerspectiveCamera can switch modes, but the code path to set parallel projection and apply the scale value is missing from applyCameraParam.","status":"closed","priority":1,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T09:04:51Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:56:29Z","started_at":"2026-04-24T10:50:19Z","closed_at":"2026-04-24T10:56:29Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-362","title":"Add missing server-config files: gitconfig-ifcmerge and gitattributes","description":"forgejo/README.md documents deploying two files that don't exist in the repo: forgejo/server-config/gitconfig-ifcmerge and forgejo/server-config/gitattributes. Both are required for the ifcmerge git merge driver to work in bare Forgejo repos. The README even includes 'sudo cp forgejo/server-config/gitattributes /etc/gitattributes' and 'sudo git config --system include.path .../gitconfig-ifcmerge', but the files themselves are absent. Anyone following the deployment instructions will hit a 'file not found' error. Need to create both files with the content described in the README.","status":"closed","priority":1,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T09:04:31Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:51:47Z","started_at":"2026-04-24T10:50:15Z","closed_at":"2026-04-24T10:51:47Z","close_reason":"Files already exist: forgejo/server-config/gitconfig-ifcmerge and gitattributes are both present and correct. Missed in initial review.","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-9cr","title":"ifc:// URLs in Forgejo issues and PR comments not documented as a collaboration tool","description":"Forgejo's markdown extension renders ifc:// URLs as clickable 3D preview images in file README views, but it works equally in issue bodies, PR descriptions, and comment threads — which is where the actual collaboration happens. This is potentially the most useful feature: a reviewer can paste an ifc:// URL in a PR comment and everyone in the thread sees the 3D view inline. This is not mentioned anywhere in README.md, forgejo/README.md, or SPECIFICATION.md. Add a 'Collaboration workflow' section to the README showing: (1) navigate to view in viewer, (2) copy URL from address bar, (3) paste as [label](ifc://...) in a Forgejo comment/issue, (4) collaborators click the preview image to open the view.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:44Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:47:24Z","started_at":"2026-04-24T11:14:59Z","closed_at":"2026-04-24T11:47:24Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"id":"ifcurl-n00","title":"Forgejo markdown previews fail silently for private repos — no auth path from preview service","description":"The Forgejo markdown extension generates \u003cimg src='http://localhost:8000/preview?url=ifc://...'\u003e tags. The preview service fetches the IFC file server-side using GET /preview with no authentication. For private repos, this returns HTTP 404 or 403 and the preview image shows as broken. There is no mechanism for the Forgejo markdown renderer to pass the user's session token to the preview service. Options to investigate: (1) the Forgejo integration could pass a signed request token; (2) the preview service could run as the Forgejo git user (which has read access to all repos); (3) SSH-based fetch from the service using the Forgejo server's own key. The current state is a silent failure that will confuse users.","status":"open","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:39Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:03:39Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"ifcurl-n00","title":"Forgejo markdown previews fail silently for private repos — no auth path from preview service","description":"The Forgejo markdown extension generates \u003cimg src='http://localhost:8000/preview?url=ifc://...'\u003e tags. The preview service fetches the IFC file server-side using GET /preview with no authentication. For private repos, this returns HTTP 404 or 403 and the preview image shows as broken. There is no mechanism for the Forgejo markdown renderer to pass the user's session token to the preview service. Options to investigate: (1) the Forgejo integration could pass a signed request token; (2) the preview service could run as the Forgejo git user (which has read access to all repos); (3) SSH-based fetch from the service using the Forgejo server's own key. The current state is a silent failure that will confuse users.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:39Z","created_by":"Bruno Postle","updated_at":"2026-04-24T12:39:46Z","started_at":"2026-04-24T11:56:30Z","closed_at":"2026-04-24T12:39:46Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-2y6","title":"Private Forgejo repos work in viewer via session cookie (same-origin) but this is undocumented and untested","description":"When the viewer is served at https://forgejo.example.com/assets/viewer.html, toRawUrl() constructs a same-origin URL like https://forgejo.example.com/org/repo/raw/branch/main/model.ifc. The browser automatically attaches the Forgejo session cookie to this fetch, so private repos on the same Forgejo instance should be accessible to logged-in users without any extra configuration. This is a significant capability that is not documented or tested. Needs: (1) a test or note confirming this works, (2) documentation in forgejo/README.md explaining that private repos work automatically for logged-in users when the viewer is served from the same Forgejo instance, (3) clear note that external repos (other Forgejo, GitHub, GitLab) have no auth path from the browser viewer.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:26Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:47:25Z","started_at":"2026-04-24T11:15:00Z","closed_at":"2026-04-24T11:47:25Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-u8a","title":"PR review: no before/after 3D render when an IFC file is modified","description":"When a Forgejo PR modifies a .ifc file, the Files Changed tab shows raw STEP text diff — completely unreadable. Reviewers cannot see what geometry changed. The system should automatically add before/after rendered PNG images to the PR description or as a PR check comment when an .ifc file is modified. The service can render both the base-branch version and the PR-branch version using the commit hexshas already available in the PR context. This is the single most important workflow gap for IFC code review — currently 100% of the visual review burden falls on the reviewer manually opening the viewer and navigating. This supersedes and expands the existing ifcurl-prc issue.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:21Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:03:21Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"id":"ifcurl-sgv","title":"BCF import in viewer: reconstruct ifc:// URL from a BCF viewpoint file","description":"BCF is a standard exchange format for BIM issue tracking. Reviewers using other tools (Solibri, Navisworks, BIMcollab) will generate BCF files. There is currently no way to open a BCF file in the viewer to see the referenced view. Implement BCF import: accept a .bcf zip via drag-and-drop or a file picker, parse the first viewpoint's camera/clips, construct an ifc:// URL from the Components/Selection GUIDs (as a GUID-based selector), and load the view. This also completes SPECIFICATION.md §6 direction 2. The ifc:// URL base (repo, ref, path) cannot be recovered from BCF alone — the viewer should keep the current model context and only apply the viewpoint.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:07Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:03:07Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"ifcurl-sgv","title":"BCF import in viewer: reconstruct ifc:// URL from a BCF viewpoint file","description":"BCF is a standard exchange format for BIM issue tracking. Reviewers using other tools (Solibri, Navisworks, BIMcollab) will generate BCF files. There is currently no way to open a BCF file in the viewer to see the referenced view. Implement BCF import: accept a .bcf zip via drag-and-drop or a file picker, parse the first viewpoint's camera/clips, construct an ifc:// URL from the Components/Selection GUIDs (as a GUID-based selector), and load the view. This also completes SPECIFICATION.md §6 direction 2. The ifc:// URL base (repo, ref, path) cannot be recovered from BCF alone — the viewer should keep the current model context and only apply the viewpoint.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:07Z","created_by":"Bruno Postle","updated_at":"2026-04-24T12:39:47Z","started_at":"2026-04-24T11:56:31Z","closed_at":"2026-04-24T12:39:47Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-qcw","title":"Viewer: no 'Create Forgejo issue' button — BCF export and Forgejo issues are disconnected","description":"The BCF export downloads a file that the reviewer must then manually attach to a Forgejo issue. There is no direct path from 'I found a problem in the viewer' to 'this is now a Forgejo issue'. The feedback loop — reviewer flags, designer fixes, reviewer verifies — requires the issue to live in Forgejo where the code/model review happens. A 'Report issue' button in the viewer should call the Forgejo API (POST /api/v1/repos/{owner}/{repo}/issues) with the current ifc:// URL pre-filled in the issue description, so the issue body automatically renders a clickable 3D preview. The viewer already knows the repo path (from the URL) and when served by Forgejo the user is already authenticated.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T11:03:03Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:47:24Z","started_at":"2026-04-24T11:14:58Z","closed_at":"2026-04-24T11:47:24Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-unu","title":"Viewer: no 'Copy URL' / share button — relies on users knowing to use the address bar","description":"The viewer continuously updates the browser address bar via history.replaceState so the current view is always shareable. But there is no visible 'Copy link to this view' button. Non-technical users (clients, project managers) will not know to copy from the address bar, especially when the URL is long and truncated. A clipboard button alongside the BCF button — or a dedicated Share toolbar item — would make the core sharing workflow discoverable. Should copy the ifc:// URL (from urlInput, which reflects current camera state) to the clipboard and briefly confirm with a visual indicator.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T11:02:49Z","created_by":"Bruno Postle","updated_at":"2026-04-24T11:47:23Z","started_at":"2026-04-24T11:14:38Z","closed_at":"2026-04-24T11:47:23Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-9rk","title":"pyproject.toml: bcf package not listed as optional service dependency","description":"service.py and bcf.py work correctly because the 'bcf' Python library is installed, but it is not listed in pyproject.toml's [service] or [render] optional dependencies. A fresh install with 'pip install ifcurl[service]' may not install it. Add bcf to the [service] extras to make the dependency explicit.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T10:41:19Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:56:27Z","started_at":"2026-04-24T10:50:11Z","closed_at":"2026-04-24T10:56:27Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"id":"ifcurl-czd","title":"GET /preview has no token parameter — private repos inaccessible","description":"POST /preview accepts a token field in the JSON body for private repository authentication. GET /preview (used by Forgejo \u003cimg src=\u003e tags) only takes a url query parameter with no way to pass a token. The Go markdown extension generates img tags using the GET form. This means inline previews in Forgejo markdown can never authenticate to private repos — they will silently fail or return 404. Either the Go extension should use POST, or a separate signed/session-scoped token mechanism is needed for the GET path.","status":"open","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-04-24T10:40:17Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:40:17Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"id":"ifcurl-czd","title":"GET /preview has no token parameter — private repos inaccessible","description":"POST /preview accepts a token field in the JSON body for private repository authentication. GET /preview (used by Forgejo \u003cimg src=\u003e tags) only takes a url query parameter with no way to pass a token. The Go markdown extension generates img tags using the GET form. This means inline previews in Forgejo markdown can never authenticate to private repos — they will silently fail or return 404. Either the Go extension should use POST, or a separate signed/session-scoped token mechanism is needed for the GET path.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T10:40:17Z","created_by":"Bruno Postle","updated_at":"2026-04-24T12:39:46Z","started_at":"2026-04-24T11:56:09Z","closed_at":"2026-04-24T12:39:46Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-3n4","title":"viewer-url.js: toRawUrl GitLab host detection too broad","description":"toRawUrl() uses host.includes('gitlab') to detect GitLab instances, which matches any hostname containing the string 'gitlab' — e.g. 'not-actually-gitlab.example.com' would be routed to the GitLab raw URL pattern. Should use a more specific check: host === 'gitlab.com' or host.startsWith('gitlab.') to avoid false positives on unrelated hostnames.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T10:40:01Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:56:28Z","started_at":"2026-04-24T10:50:14Z","closed_at":"2026-04-24T10:56:28Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-7wg","title":"service.py: /bcf endpoint doesn't include source URL in BCF description","description":"The viewer's client-side BCF generation records the source ifc:// URL as a \u003cDescription\u003e element in the markup, making the BCF traceable back to its origin. The service POST /bcf endpoint calls build_bcf() without passing any description, so service-generated BCF files contain no reference to the original URL. The URL should be included (in Description or a comment) so the BCF is self-documenting. build_bcf() needs a description parameter, or the url should be passed as comment/description automatically.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T09:05:17Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:56:29Z","started_at":"2026-04-24T10:50:17Z","closed_at":"2026-04-24T10:56:29Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"id":"ifcurl-sto","title":"viewer.html: BCF export ignores visibility mode from URL","description":"The viewer's client-side generateBcf() always writes '\u003cVisibility DefaultVisibility=\"true\"/\u003e' and never adds Selection or Exceptions elements based on the visibility= URL parameter. A URL with visibility=isolate or visibility=ghost generates BCF with no component visibility data, so a BCF tool importing the file will show all elements with no selection. The service /bcf endpoint handles this correctly. The viewer-side BCF should at minimum write the selector string as a Description so the visibility intent is preserved.","status":"closed","priority":2,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-04-24T09:05:14Z","created_by":"Bruno Postle","updated_at":"2026-04-24T10:56:29Z","started_at":"2026-04-24T10:50:18Z","closed_at":"2026-04-24T10:56:29Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/README.md b/README.md index 2eb63f8..1c018fa 100644 --- a/README.md +++ b/README.md @@ -194,8 +194,21 @@ Add to `/etc/forgejo/conf/app.ini`: ```ini [ifcurl] PREVIEW_SERVICE_URL = http://localhost:8000 +; Optional: Forgejo API token for a read-only machine user. +; The preview service will use this token to fetch IFC files from private +; repositories on this Forgejo instance. The token is appended as a query +; parameter in the URL generated by the markdown extension, so it +; is visible in page source. Only set this on trusted private instances. +; SERVICE_TOKEN = ``` +**Private repositories:** for the preview service to access private repos on +this Forgejo instance, create a machine user with read access and set +`SERVICE_TOKEN` to its API token. The service will use this token when +fetching IFC files server-side. Alternatively, configure the preview service's +own credentials in `~/.config/ifcurl/tokens.json` under the service user +account — the service already reads host tokens from that file on startup. + --- ## Browser viewer diff --git a/forgejo/custom/public/assets/viewer-url.js b/forgejo/custom/public/assets/viewer-url.js index 798f387..920fc4a 100644 --- a/forgejo/custom/public/assets/viewer-url.js +++ b/forgejo/custom/public/assets/viewer-url.js @@ -39,7 +39,7 @@ export function buildIfcUrl(repo, ref, path, selector) { const qs = new URLSearchParams(); if (path) qs.set("path", path); if (selector) qs.set("selector", selector); - const qsStr = qs.toString().replace(/%2C/g, ",").replace(/%2B/g, "+"); + const qsStr = qs.toString().replace(/%2C/g, ",").replace(/%2B/g, "+").replace(/%24/g, "$"); return `ifc://${repo}@${ref}${qsStr ? "?" + qsStr : ""}`; } diff --git a/forgejo/custom/public/assets/viewer.html b/forgejo/custom/public/assets/viewer.html index 096440b..38e840e 100644 --- a/forgejo/custom/public/assets/viewer.html +++ b/forgejo/custom/public/assets/viewer.html @@ -64,7 +64,7 @@ } #status:empty { display: none; } body.drag-over::after { - content: "Drop ifc:// URL to load"; + content: "Drop ifc:// URL or .bcf file"; position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; font-size: 24px; color: #f0f0f0; @@ -150,8 +150,10 @@ placeholder="IfcWall" spellcheck="false"> - +