Skip to content

Add frontend marketing site and plugin host API package - #3

Merged
benjaminLedel merged 11 commits into
mainfrom
claude/create-frontend-tailwind-5DDTl
Apr 15, 2026
Merged

Add frontend marketing site and plugin host API package#3
benjaminLedel merged 11 commits into
mainfrom
claude/create-frontend-tailwind-5DDTl

Conversation

@benjaminLedel

Copy link
Copy Markdown
Owner

Summary

This PR introduces the Fiely frontend marketing site and the foundational @fiely/host package that defines the plugin contract. It also restructures the Docker build to embed the frontend into the backend as a single container, and updates CI/CD to build both frontend and backend.

Key Changes

Frontend (fiely-frontend/)

  • Marketing site with React + Vite + TypeScript + Tailwind CSS
    • Hero section with value proposition ("Your files. Your rules. Your AI.")
    • Feature showcase (chunked uploads, versioning, sharing, teams, audit, on-premise)
    • AI features section (semantic search, auto-tagging, chat with files, content generation)
    • Audience targeting (families, teams, schools, public sector, self-hosters)
    • Tech stack overview
    • Public roadmap (Phase 1–3)
    • Call-to-action and footer
  • Responsive design with dark mode support
  • Tailwind configuration with custom brand and ink color palettes
  • SPA-ready structure for future authenticated UI

Plugin Host API (packages/fiely-host/)

  • @fiely/host npm package — the contract plugins compile against
    • FielyHost interface with user info, theme tokens, and API surface
    • FielyFilesApi — typed wrappers for file operations (get, list, download, upload, delete)
    • FielyUiApi — user-visible effects (toast, confirm, navigate, openFile)
    • Entry-point types: PageProps, FileActionProps, SettingsPanelProps
    • Event subscription system (host.on())
    • PermissionError for permission-denied scenarios
    • Manifest schema (PluginManifest, EntryPoint, AppPermission)
    • Bundle loading helpers (loadPluginBundle, MOUNT_CLASS for CSS scoping)
  • Peer dependencies on react, react-dom, and @fiely/host (pinned via import map)
  • TypeScript-first, framework-agnostic design

Docker & Deployment

  • Root Dockerfile — 3-stage build:
    1. Frontend: Node 22 → builds fiely-frontend/ to dist/
    2. Backend: Gradle 8.11 + JDK 21 → builds fiely-backend/, embedding frontend dist as Spring Boot static resources
    3. Runtime: Slim JRE → runs the fat JAR
  • docker-compose.yml — quick-start with PostgreSQL (pgvector) + Fiely
  • .dockerignore — excludes build artifacts, docs, and local config
  • .env.example — template for compose environment variables

Backend Integration

  • SpaWebConfig.kt — Spring Boot web config for SPA fallback
    • Serves real files under /static/ as-is
    • Rewrites deep links to index.html for client-side routing
    • Exempts /api/ and /actuator/ from rewriting

CI/CD

  • .github/workflows/ci.yml — updated to build both frontend and backend
    • Frontend job: Node 22, npm ci, npm run build
    • Backend job: Gradle build with frontend dist embedded
    • Docker build and push to GHCR

Documentation

  • docs/plugin-architecture.md — expanded Phase 4 (Third-Party Apps) with detailed frontend plugin mechanism
    • Bundle layout and manifest schema
    • Import-map-based loader with React/host externalized
    • In-process mounting with CSS scoping
    • Aggregate manifest endpoint
    • Content-hashed, long-cacheable bundle serving
    • Strict CSP rules
    • hostApiVersion compatibility gating
    • Admin install flow and permission approval
    • create-fiely-plugin scaffold and @fiely/plugin-dev Vite plugin
  • packages/fiely-host/README.md — plugin author guide with examples (pages, file actions, events, permissions)
  • **`fiely-frontend/

https://claude.ai/code/session_01WyDtWm5QXTFa79B1K3L5Wi

claude added 11 commits April 14, 2026 20:08
Introduces fiely-frontend/ — the web UI package for Fiely. Ships a full
landing page (hero, features, AI features, audience, tech stack, roadmap,
CTA, footer) with a cohesive design system in Tailwind, dark-mode ready
tokens, Inter typography and accessible, responsive layouts.

Set up with Vite, TypeScript strict mode and a production build that
type-checks cleanly.
Expands "Frontend Plugin Mechanism" from a sketch into an actionable
contract: goals, bundle layout with content-hashed serving, full
manifest schema with hostApiVersion gating, an import-map + native ESM
loader (rejecting Module Federation with reasoning), a three-tier
trust model (core / first-party in-process / third-party iframe +
postMessage), a versioned @fiely/host API surface, typed entry-point
props, routing ownership, shared @fiely/ui styling rules, aggregate
manifest endpoint, frontend security model per tier, and a DX story
with create-fiely-plugin + @fiely/plugin-dev.

Updates the Decisions summary and Phase 4 roadmap to match.
Adds packages/fiely-host/ — the contract every Fiely plugin compiles
against. The package exposes:

- FielyHost interface (files, ui, fetch, events, config, theme, i18n)
- Entry-point prop types (PageProps, FileActionProps, SettingsPanelProps,
  SidebarWidgetProps)
- HostEvent union + narrowing helpers
- PluginManifest schema with entry-point type guards
- HOST_API_VERSION constant and PermissionError class
- @fiely/host/mount subpath: loadPluginBundle, entryPointBundleUrl,
  pluginAssetUrl, and the shared MOUNT_CLASS

Plugins run in-process: the core loads the bundle via dynamic import()
under the browser's import map, builds a permission-scoped FielyHost,
and renders the plugin's exported component as a React child. No iframe,
no postMessage RPC — isolation comes from admin review at install time,
backend enforcement of AppPermission on every API call, CSP that pins
script-src/connect-src to the core origin, and per-plugin CSS scoping
inside .fiely-plugin-root.

Also updates docs/plugin-architecture.md to drop the iframe trust tier
and document the unified in-process model and layered security story.
Move to a root Dockerfile that builds the React frontend with Node,
embeds the resulting dist into fiely-core as Spring Boot static
resources, and produces one runtime image.

- Dockerfile at repo root: frontend (node:22-alpine) -> backend
  (gradle:8.11-jdk21) -> runtime (eclipse-temurin:21-jre). Frontend
  assets land under classpath:/static/ and are served by Spring.
- SpaWebConfig adds a resource resolver that serves real files, returns
  404 for missing assets (extension check), skips /api/ and /actuator/
  routes so they behave as before, and otherwise falls back to
  index.html so React Router deep links work on refresh.
- .dockerignore at root covers both frontend and backend build
  artifacts.
- CI: split out a 'frontend' job (Node 22, npm ci + build, dist
  artifact) alongside the existing backend build; docker-build now
  uses the root Dockerfile with context '.', depends on both.
- Remove the now-redundant fiely-backend/Dockerfile and .dockerignore.
- .gitignore excludes the staged static/ directory so a local build
  never leaks into commits.
- README: describe the single-container build/run flow.

Smoke-tested locally: /api/ping returns JSON, / and /dashboard and
/apps/my-app all return the SPA shell (identical bytes), /assets/*
returns the real bundle, /foo.png and /api/unknown return 404.
Add a root-level docker-compose.yml that brings up PostgreSQL (with
pgvector, pre-provisioned for the planned semantic search in phase 2)
and the Fiely container together with a single 'docker compose up'.

- Persistent named volume for the database
- pg_isready healthcheck so the Fiely container waits for the DB
- Configurable via .env (port, DB name/user/password); defaults are
  local-only dev values
- Database port is not exposed to the host by default
- Build targets the root Dockerfile at context '.'

.env.example documents the available overrides.
README: replace the "coming soon" note with a real quick start
section, keep the manual 'docker build' + 'docker run' flow as an
alternative.
Previously 'docker compose up' always triggered a full local build
(frontend + backend, a few minutes on the first run). Flip the default
so the compose file references the image CI publishes to GHCR and only
falls back to the local build context if the pull fails.

- docker-compose.yml: image defaults to ghcr.io/benjaminledel/fiely:latest,
  overridable via FIELY_IMAGE; pull_policy: missing; build: stays as a
  fallback so 'docker compose up' works on a fresh checkout even before
  the image is published
- .env.example: document FIELY_IMAGE with an example of pinning a SHA tag
- README: clarify the pull-first / build-fallback behavior and show the
  'docker compose pull' / '--build' / 'down -v' commands
- ci.yml: clean up IMAGE_NAME from the doubled
  ghcr.io/<repo>/fiely to ghcr.io/<repo> (the repo already is fiely)
Adds a dev overlay that runs alongside the base compose:

    docker compose -f docker-compose.yml -f docker-compose.dev.yml up

- New fiely-frontend-dev service (node:22-alpine) running `vite --host`
  with a bind mount to ./fiely-frontend/ so source edits HMR instantly.
  node_modules lives in a named volume so host platform differences
  (macOS/Windows) don't break native deps.
- File-watch polling enabled (CHOKIDAR_USEPOLLING) so mounts work
  reliably on all Linux kernels.
- Vite config now reads VITE_API_PROXY (falls back to localhost:8080)
  and proxies /api + /actuator to the backend container, so the dev
  frontend talks to a real Spring Boot backend without CORS.
- Dev overlay forces 'fiely' to build locally (pull_policy: never,
  tag fiely:dev) rather than pulling the GHCR image.
- @types/node added as a devDependency for vite.config.ts's process
  access.
- README documents the dev workflow (port table, HMR behavior, how
  to rebuild the backend).
Drop the two-port setup (Vite on :5173, backend on :8080). Everything
now lives behind Spring Boot on :8080 in dev too, mirroring how prod
works.

How it works:

- SpaWebConfig now reads spring.web.resources.static-locations instead
  of hardcoding classpath:/static/. Both the resource handler and the
  SPA index.html fallback walk the configured locations in order, so
  operators can prepend a filesystem path without patching code.
- docker-compose.dev.yml replaces fiely-frontend-dev (npm run dev with
  HMR + proxy) with fiely-frontend-watch (vite build --watch) writing
  into a shared named volume.
- The fiely backend mounts that volume read-only at /app/frontend-dist
  and is told to serve from there first via
  SPRING_WEB_RESOURCES_STATIC_LOCATIONS=file:/app/frontend-dist/,classpath:/static/.
  Spring streams the freshest bytes on every request — no backend
  restart needed after a frontend edit.
- A healthcheck on the watcher (tests for /dist-out/index.html) gates
  the backend's depends_on so users never hit 404 on the first load.
- README updated: one port, one URL (localhost:8080), single workflow.
  Still documents the host-Vite path for users who want real React
  Fast Refresh with state preservation.

Verified locally: started the JAR with a temp file: location,
filesystem dist took precedence, classpath fallback worked for assets
only present there, overwriting index.html was reflected on the next
request without a restart.
Fiely is a self-hosted product container, not a marketing site — the
first thing a user should see on localhost:8080 is the Nextcloud-style
login, not an eight-section sales pitch. A real marketing site belongs
on fiely.cloud and can be built separately.

- Remove Hero, Features, AIFeatures, Audience, TechStack, Roadmap,
  CTA, Header, Footer components.
- Add Login.tsx: centered card with username + password (show/hide
  toggle), "stay signed in" checkbox, forgot-password link, submit
  button wired to POST /api/auth/login, inline error surface, and a
  disabled SSO button placeholder for the upcoming OIDC/SAML auth
  plugin.
- Add LegalFooter.tsx: Imprint · Privacy · Terms · "Open source · MIT"
  shown on unauthenticated pages. Links point at /legal/* routes the
  settings plugin will own.
- App.tsx collapses to the unauthenticated shell that mounts Login.
- index.html: title → "Sign in · Fiely", description → product copy.
- Design-system tokens in index.css (.btn-primary, .btn-ghost,
  .gradient-text, brand palette) are preserved so the authenticated
  surfaces can build on them.

Bundle drops: CSS 31.96 → 16.93 kB (-47 %), JS 184.50 → 152.06 kB
(-18 %).
After merging origin/main, /api/auth/login is real. Adjust the form:

- Send only { username, password } (backend ignores 'remember').
- Read error messages from body.error (AuthController's ErrorResponse
  field) with a fallback to body.message for future providers.
- On success, store TokenPair.accessToken + refreshToken in localStorage
  (when 'Stay signed in' is ticked) or sessionStorage otherwise. The
  authenticated shell will pick it up; a real cookie-backed session
  can replace this later.
@benjaminLedel
benjaminLedel merged commit 9baf6ba into main Apr 15, 2026
3 checks passed
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