Skip to content

feat: stabilize public http interface & slimmer docker #882

Merged
gildesmarais merged 5 commits intomainfrom
fix/build-frontend
Mar 15, 2026
Merged

feat: stabilize public http interface & slimmer docker #882
gildesmarais merged 5 commits intomainfrom
fix/build-frontend

Conversation

@gildesmarais
Copy link
Copy Markdown
Member

@gildesmarais gildesmarais commented Mar 15, 2026

This pull request restructures how the frontend assets and OpenAPI specification are built, served, and referenced throughout the application. The changes standardize the output locations, improve Docker and CI integration, and update documentation and code references to reflect these new conventions. The most important changes are grouped below.

Frontend build and serving changes:

  • The frontend build output is now placed in frontend/dist instead of public/frontend, and the app serves static assets from this new directory at the root path (/). This affects the Docker build, static file serving configuration, and bookmarklet logic. ([[1]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557L96-R96), [[2]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-f965f92b425fb2f75d38b491b2625fe21b8af20b7666217546bce8a42b198ea4R34-R35), [[3]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-f965f92b425fb2f75d38b491b2625fe21b8af20b7666217546bce8a42b198ea4R85-R88), [[4]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-f965f92b425fb2f75d38b491b2625fe21b8af20b7666217546bce8a42b198ea4L103-R110), [[5]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-97c6e2c429ec483132c584137a18a1ade2ff6c3f4f6485f4a83db604d0323d7cR5), [[6]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-97c6e2c429ec483132c584137a18a1ade2ff6c3f4f6485f4a83db604d0323d7cL22-R23), [[7]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-7252f6c43b3cf192bd50ce66192ddce81eca27815a4b99eb57366d25e3715f07L9-R9), [[8]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-1f633b86af4bf00bbb33177b2e1a51a960711d1bb9901ce853b34e53d6bd7d14L275-R281), [[9]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L104-R104), [[10]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L23-R23), README.md, docs/README.md)

OpenAPI specification changes:

  • The OpenAPI YAML file is now generated to and served from public/openapi.yaml instead of docs/api/v1/openapi.yaml. All references, build scripts, and tests have been updated accordingly. The versioned API route /api/v1/openapi.yaml now redirects to /openapi.yaml. ([[1]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52L105-R124), [[2]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-ee98e028c59b193d58fde56ab4daf54d43c486ae674e63d50ddf300b07943e0fL99-R106), [[3]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-74d6d27981dace9acd4886bdcdc2fb9776477f7b22557e92832eb4cf46fb98cdL18-R18), [[4]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-28a08a74a84f026c2e107160e332d32db8c8338eaf53cf6c7930f6ff00afe952L26-R26), [[5]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-28a08a74a84f026c2e107160e332d32db8c8338eaf53cf6c7930f6ff00afe952L58-L80), [[6]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-da6498268e99511d9ba0df3c13e439d10556a812881c9d03955b2ef7c6c1c655L14-R15), [[7]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-0f9368690552ac79a208dde6e3f09cf9f4e350e910d0de10c35dc2cc235479b1L85-R85), [[8]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-1f633b86af4bf00bbb33177b2e1a51a960711d1bb9901ce853b34e53d6bd7d14L56-R56), [[9]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-347625202f0133fd177c976e7499085afcda2d709947a82294435a16276bd228L12-R12), [[10]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-7725db5f3a9f3b853587e27b2462cf1b84ead50477855af692f72bb6e159cca5L452-L466), [[11]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-39eaafdff54bffed770574d0dd758902acc94553d5bb2fb5eab86903fc2efff5L117-R117), [[12]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-39eaafdff54bffed770574d0dd758902acc94553d5bb2fb5eab86903fc2efff5L142-R147), [[13]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-0b5ca119d2be595aa307d34512d9679e49186307ef94201e4b3dfa079aa89938L7-R12), [[14]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-0b5ca119d2be595aa307d34512d9679e49186307ef94201e4b3dfa079aa89938L58-R58), README.md, docs/README.md)

Continuous Integration and Docker improvements:

  • The CI workflow now installs frontend dependencies and verifies both the OpenAPI spec and client generation in a single step using make openapi-verify. Node dependencies are cached for faster builds, and the Docker build uses the new frontend output path. ([[1]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-b803fcb7f17ed9235f1e5cb1fcd2f5d3b2838429d4368ae4c57ce4436577f03fR61-R69), [[2]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-b803fcb7f17ed9235f1e5cb1fcd2f5d3b2838429d4368ae4c57ce4436577f03fL86-L88), [[3]](https://github.com/html2rss/html2rss-web/pull/882/files#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557L96-R96), .dockerignore)

Documentation and tests:

  • All documentation, helper text, and tests have been updated to match the new asset and OpenAPI spec locations, ensuring consistency and preventing confusion for contributors. (README.md, docs/README.md, frontend/package.json, frontend/src/__tests__, spec/html2rss/web/api/v1_spec.rb)

Miscellaneous:

  • The frontend favicon is now referenced as /favicon.ico instead of an inline SVG. ([frontend/index.htmlL11-R11](https://github.com/html2rss/html2rss-web/pull/882/files#diff-959f9cada636604db33bc1ba82fed347457dcb032c37ac195b4343c5f0ea6e72L11-R11))

@gildesmarais gildesmarais requested a review from Copilot March 15, 2026 20:08
@gildesmarais gildesmarais changed the title Fix/build frontend feat: stabilize public http interface Mar 15, 2026
@gildesmarais gildesmarais changed the title feat: stabilize public http interface feat: stabilize public http interface & slimmer docker Mar 15, 2026
@gildesmarais gildesmarais marked this pull request as ready for review March 15, 2026 20:13
@gildesmarais gildesmarais merged commit fe3f4be into main Mar 15, 2026
12 checks passed
@gildesmarais gildesmarais deleted the fix/build-frontend branch March 15, 2026 20:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR standardizes how the app builds and serves the Preact frontend and how it generates/serves the OpenAPI contract, aligning Docker/CI, runtime routing, and tests/docs around the new public HTTP interface.

Changes:

  • Move Vite build output to frontend/dist and serve assets from /assets (with the app entry at /).
  • Generate and serve the OpenAPI spec from public/openapi.yaml, updating metadata and redirecting /api/v1/openapi.yaml to /openapi.yaml.
  • Update CI, Docker image assembly, and Ruby/frontend tests and docs to match the new paths.

Reviewed changes

Copilot reviewed 21 out of 25 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
app.rb Serve Vite assets from frontend/dist and load frontend/dist/index.html for /.
app/web/routes/api_v1/metadata_routes.rb Redirect versioned OpenAPI route to the public spec URL.
app/web/api/v1/root_metadata.rb Update openapi_url in API metadata to /openapi.yaml.
public/openapi.yaml Update generated OpenAPI to reflect route changes (removes self-serving path entry).
Rakefile Generate/verify OpenAPI output at public/openapi.yaml.
Makefile Update OpenAPI targets and lint commands to use public/openapi.yaml.
.github/workflows/ci.yml Consolidate OpenAPI spec + client verification via make openapi-verify and cache Node deps.
Dockerfile Copy frontend/dist into the runtime image at ./frontend/dist.
.dockerignore Exclude frontend/dist/ from build context.
.gitignore Stop ignoring legacy public/frontend output.
frontend/vite.config.ts Set base: '/' and output build to ./dist.
frontend/index.html Switch favicon reference to /favicon.ico.
frontend/src/components/Bookmarklet.tsx Update bookmarklet target to root entry (/?url=).
frontend/package.json Point openapi-ts generation/verification to ../public/openapi.yaml.
frontend/src/api/generated/types.gen.ts Remove generated types for the dropped /openapi.yaml operation.
frontend/src/api/generated/sdk.gen.ts Remove generated SDK call for the dropped /openapi.yaml operation.
frontend/src/api/generated/index.ts Remove OpenAPI SDK/type exports.
frontend/src/__tests__/mocks/server.ts Update mocked openapi_url to /openapi.yaml.
frontend/src/__tests__/App.test.tsx Update tests for new openapi_url and bookmarklet behavior.
frontend/src/__tests__/App.contract.test.tsx Update contract test fixture for new openapi_url.
spec/support/openapi.rb Write RSpec::OpenAPI output to public/openapi.yaml.
spec/html2rss/web/api/v1_spec.rb Expect metadata to advertise /openapi.yaml and validate redirect from versioned path.
spec/html2rss/web/app_spec.rb Add a regression test ensuring legacy frontend entrypoint is not served.
README.md Update contributor docs to the new frontend/OpenAPI output locations.
docs/README.md Update internal docs to reference public/openapi.yaml and new frontend serving path.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread docs/README.md
Keep this file short, current, and operational. Do not add planning docs, migration diaries, redesign notes, or parallel architecture narratives back into this directory.

The only other file that belongs in `docs/` is the generated OpenAPI contract at [`docs/api/v1/openapi.yaml`](/Users/gil/versioned/html2rss/html2rss-web/docs/api/v1/openapi.yaml).
The only generated artifact intentionally exposed by the app is [`public/openapi.yaml`](/Users/gil/versioned/html2rss/html2rss-web/public/openapi.yaml).
Comment thread app.rb
Comment on lines +85 to +88
plugin :static,
['/assets'],
root: FRONTEND_DIST_PATH,
headers: { 'Cache-Control' => 'public, max-age=31536000, immutable' }
gildesmarais added a commit that referenced this pull request May 1, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.1.0](html2rss-web-v1.0.0...html2rss-web/v1.1.0)
(2026-05-01)


### Features

* add help text on error page
([eeee345](eeee345)),
closes [#338](#338)
* add routed frontend feed creation workflow
([#963](#963))
([2d1b71a](2d1b71a))
* **auto_source:** add support for `auto_source` feature
([#676](#676))
([531dced](531dced))
* default browserless onboarding and request strategies
([#895](#895))
([377cff0](377cff0))
* **deps:** use html2rss in latest development status
([#728](#728))
([5885d1d](5885d1d))
* **docker:** switch to alpine 21
([7adcc89](7adcc89))
* **docker:** upgrade to use ruby 3.3 image
([ceafe24](ceafe24))
* **docker:** use multilayer build to cut image size in half
([2f6e322](2f6e322))
* **docker:** use Ruby 3.4
([4f7d795](4f7d795))
* **frontend:** polish result experience and validation tooling
([#964](#964))
([b11665e](b11665e))
* **frontend:** relaunch the app with a focused v1 flow
([e0692d7](e0692d7))
* **frontend:** unify feed/result state flow
([#943](#943))
([6dfa1a9](6dfa1a9))
* **health_check:** add HTTP Basic authentication to `GET
/health_check.txt`
([#559](#559))
([d0ccd83](d0ccd83))
* improve example feed config in feed.yml and link to it
([#552](#552))
([de08695](de08695))
* install Gemfile.lock specified bundler version
([4190160](4190160))
* integrate request_service and use ssrf_filter strategy by default
([#707](#707))
([b7516fd](b7516fd))
* link included feeds to the instance feed directory
([#901](#901))
([51ce79a](51ce79a))
* optionally allow APM using Sentry via env variable
([#696](#696))
([94477d5](94477d5))
* redact sensitive feed data in structured logs
([#903](#903))
([ee7df73](ee7df73))
* remove dependency on activesupport
([048cb73](048cb73))
* **runtime:** rebuild feed and api behavior around typed v1 services
([b61602d](b61602d))
* simplify feed creation contract & backend error handling
([#962](#962))
([dfca027](dfca027))
* stabilize public http interface & slimmer docker
([#882](#882))
([fe3f4be](fe3f4be))
* unify web and feed result surfaces
([#896](#896))
([e747b23](e747b23))
* use parallel processing for feed retrieval in health_check.rb
([#665](#665))
([4a24997](4a24997))


### Bug Fixes

* ArgumentError when RACK_TIMEOUT_SERVICE_TIMEOUT env var is set
([96acbab](96acbab)),
closes [#527](#527)
* **auto_source:** respect headers from global config
([#691](#691))
([3e9ba91](3e9ba91))
* **build:** only cleanup when there is a test container
([f7bafa6](f7bafa6))
* caching with dynamic parameters yields incorrect rss
([#589](#589))
([bb945c2](bb945c2)),
closes [#587](#587)
* **ci:** repair Ruby, OpenAPI, and frontend checks
([#880](#880))
([ec6673b](ec6673b))
* defects for token/retry/loading UX
([#924](#924))
([2d38633](2d38633))
* **docker:** missing curl installation for health check
([0bd9157](0bd9157))
* example feed in config/feeds.yml broken
([#664](#664))
([b961897](b961897))
* **frontend:** preserve created feeds when preview loading fails
([#915](#915))
([383ecc3](383ecc3))
* **frontend:** streamline web ux
([#916](#916))
([85e79bf](85e79bf))
* harden container config defaults
([392997c](392997c))
* healthcheck broken due to missing curl
([c97e746](c97e746))
* keep unknown api v1 paths inside the api contract
([a820478](a820478))
* responds with http status 422
([#738](#738))
([ad9394c](ad9394c))
* **runtime:** polish relaunch smoke behavior and health checks
([65e1644](65e1644))
* stylesheets not included in feed
([#779](#779))
([9116d9d](9116d9d))
* tzdata package not installed but required for tz conversion
([#663](#663))
([55814d2](55814d2))
* **web:** harden feed reader fallback and rss rendering
([#944](#944))
([438d9f6](438d9f6))
* **web:** harden observability env handling and Sentry log redaction
([#917](#917))
([ed2b3e9](ed2b3e9))


### Performance Improvements

* enable YJIT
([729f31f](729f31f))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
gildesmarais added a commit that referenced this pull request May 1, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.2.0](v1.1.0...v1.2.0)
(2026-05-01)


### Features

* add help text on error page
([eeee345](eeee345)),
closes [#338](#338)
* add routed frontend feed creation workflow
([#963](#963))
([2d1b71a](2d1b71a))
* **auto_source:** add support for `auto_source` feature
([#676](#676))
([531dced](531dced))
* default browserless onboarding and request strategies
([#895](#895))
([377cff0](377cff0))
* **deps:** use html2rss in latest development status
([#728](#728))
([5885d1d](5885d1d))
* **docker:** switch to alpine 21
([7adcc89](7adcc89))
* **docker:** upgrade to use ruby 3.3 image
([ceafe24](ceafe24))
* **docker:** use multilayer build to cut image size in half
([2f6e322](2f6e322))
* **docker:** use Ruby 3.4
([4f7d795](4f7d795))
* **frontend:** polish result experience and validation tooling
([#964](#964))
([b11665e](b11665e))
* **frontend:** relaunch the app with a focused v1 flow
([e0692d7](e0692d7))
* **frontend:** unify feed/result state flow
([#943](#943))
([6dfa1a9](6dfa1a9))
* **health_check:** add HTTP Basic authentication to `GET
/health_check.txt`
([#559](#559))
([d0ccd83](d0ccd83))
* improve example feed config in feed.yml and link to it
([#552](#552))
([de08695](de08695))
* install Gemfile.lock specified bundler version
([4190160](4190160))
* integrate request_service and use ssrf_filter strategy by default
([#707](#707))
([b7516fd](b7516fd))
* link included feeds to the instance feed directory
([#901](#901))
([51ce79a](51ce79a))
* optionally allow APM using Sentry via env variable
([#696](#696))
([94477d5](94477d5))
* redact sensitive feed data in structured logs
([#903](#903))
([ee7df73](ee7df73))
* remove dependency on activesupport
([048cb73](048cb73))
* **runtime:** rebuild feed and api behavior around typed v1 services
([b61602d](b61602d))
* simplify feed creation contract & backend error handling
([#962](#962))
([dfca027](dfca027))
* stabilize public http interface & slimmer docker
([#882](#882))
([fe3f4be](fe3f4be))
* unify web and feed result surfaces
([#896](#896))
([e747b23](e747b23))
* use parallel processing for feed retrieval in health_check.rb
([#665](#665))
([4a24997](4a24997))


### Bug Fixes

* ArgumentError when RACK_TIMEOUT_SERVICE_TIMEOUT env var is set
([96acbab](96acbab)),
closes [#527](#527)
* **auto_source:** respect headers from global config
([#691](#691))
([3e9ba91](3e9ba91))
* **build:** only cleanup when there is a test container
([f7bafa6](f7bafa6))
* caching with dynamic parameters yields incorrect rss
([#589](#589))
([bb945c2](bb945c2)),
closes [#587](#587)
* **ci:** repair Ruby, OpenAPI, and frontend checks
([#880](#880))
([ec6673b](ec6673b))
* **ci:** robustly parse release tags and align config
([#972](#972))
([2efd6ef](2efd6ef))
* defects for token/retry/loading UX
([#924](#924))
([2d38633](2d38633))
* **docker:** missing curl installation for health check
([0bd9157](0bd9157))
* example feed in config/feeds.yml broken
([#664](#664))
([b961897](b961897))
* **frontend:** preserve created feeds when preview loading fails
([#915](#915))
([383ecc3](383ecc3))
* **frontend:** streamline web ux
([#916](#916))
([85e79bf](85e79bf))
* harden container config defaults
([392997c](392997c))
* healthcheck broken due to missing curl
([c97e746](c97e746))
* keep unknown api v1 paths inside the api contract
([a820478](a820478))
* responds with http status 422
([#738](#738))
([ad9394c](ad9394c))
* **runtime:** polish relaunch smoke behavior and health checks
([65e1644](65e1644))
* stylesheets not included in feed
([#779](#779))
([9116d9d](9116d9d))
* tzdata package not installed but required for tz conversion
([#663](#663))
([55814d2](55814d2))
* **web:** harden feed reader fallback and rss rendering
([#944](#944))
([438d9f6](438d9f6))
* **web:** harden observability env handling and Sentry log redaction
([#917](#917))
([ed2b3e9](ed2b3e9))


### Performance Improvements

* enable YJIT
([729f31f](729f31f))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants