Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
node_modules
.next
.source
dist
.astro
.git
.env*
.vercel
*.tsbuildinfo
8 changes: 6 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ jobs:
- run: npm run verify
- uses: actions/upload-artifact@v4
with:
name: docs-static-site
path: dist
name: docs-next-build
include-hidden-files: true
path: |
.next/standalone
.next/static
public
34 changes: 25 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
node_modules/
dist/
.astro/
# deps
/node_modules

# generated content
.source

# test & build
/coverage
/.next/
/out/
/build
*.tsbuildinfo

# misc
.DS_Store
.vercel/
output/
.playwright-cli/
.env
.env.*
!.env.example
*.pem
/.pnp
.pnp.js
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# others
.env*.local
.vercel
next-env.d.ts
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.

This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
13 changes: 10 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ ARG SITE_URL=https://docs.innflow.ai
ENV SITE_URL=$SITE_URL
RUN npm run build && npm run verify

FROM nginxinc/nginx-unprivileged:stable-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
FROM node:24-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=8080
ENV HOSTNAME=0.0.0.0
COPY --from=build --chown=node:node /app/.next/standalone ./
COPY --from=build --chown=node:node /app/.next/static ./.next/static
COPY --from=build --chown=node:node /app/public ./public
USER node
EXPOSE 8080
CMD ["node", "server.js"]
54 changes: 54 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Documentation migration evidence

Reference structure: https://docs.sim.ai/academy (inspected 2026-09-23). The implementation adopts separate documentation/academy navigation, topic groups, lesson objectives, article outlines, and sequential reading links. Copy and lessons are original Innflow material.

## Current scope

- 37 original MDX pages migrated, with original public paths preserved.
- 15 new Academy pages including two practical exercises.
- One new AI Decision reference with availability caveat.
- Self-hostable Next.js/Fumadocs site with local full-text search.
- Original Mintlify MDX components adapted to React/Fumadocs components.

## Source checks for new or corrected material

Application repository: `../innflow`.

| Topic | Evidence |
| --- | --- |
| Application, workspace, files, tables, knowledge base, credentials, public API boundaries | `ARCHITECTURE.md` |
| Loop items, result expression, error handling, iteration bounds | `src/tool-configs/loop/block.ts` |
| Rule and LLM conditions | `src/tool-configs/condition/block.ts` |
| Tables operations and output path | `src/tool-configs/tables/block.ts` |
| Multiple trigger authoring remains gated | `src/features/triggers/lib/entrypoint.ts` and editor callers |
| AI Decision questions, review path, and rollout restrictions | `docs/ai-decision/README.md` |

This verifies source behavior, not production enablement or an end-to-end product acceptance run.

## Follow-up content review

The original reference is not fully refreshed. Before treating the entire reference as current, check all node families against registered and visible blocks; check per-operation fields and outputs; verify plans/limits and service availability; refresh UI instructions and screenshots; verify API and CLI examples against current contracts; distinguish deployed behavior from disabled features. Existing migrated pages retain their earlier content unless explicitly corrected above.

No DNS changes, remote publish, or subscription cancellation occurred as part of this local build.

## Local verification

- `npm run types:check` and `npm run build` passed.
- All 53 content routes returned HTTP 200 from the local production server; sitemap, robots, llms index, and legacy `/index` redirect also passed (57 checks).
- Content link scan found no missing local destination paths.
- Production search returned results for Loop; browser search selection opened the Loop lesson.
- Browser checks covered section navigation, light/dark themes, and a 390px mobile sidebar with document width equal to viewport width.
- No browser console errors were observed in the final Academy preview.

These are local checks, not a claim of deployment or a complete content accuracy audit.

## Brand and MCP reference addition

- Header assets copied unchanged from `../innflow/public/assets/innflow/innflow-{black,white}-full.svg`; the black full SVG is used by `src/features/auth/components/auth-showcase.tsx`. Favicon copied from `public/logos/innflow-icon-black.svg`.
- Six MCP pages checked against `../mcp/src/config.ts`, `src/server.ts`, `src/tools/innflow/{workflows,executions,authoring}.ts`, and application `src/features/mcp-servers/{components/mcp-servers-settings.tsx,server/routers.ts}`, `src/tool-configs/mcp/block.ts`, and `src/features/tools/components/mcp/{mcp-client,executor}.ts`.
- Current source overrides older MCP skill/README statements: the service has product API tools and gated authoring, and the application settings form currently exposes bearer credentials rather than a general OAuth connection flow.
- MCP endpoint defaults are documented as configuration values; no live authentication or production enablement claim is made.

## Reconciliation with the Astro migration on main

Merged the independent content edits from `origin/main` into `content/docs/`, including signup and billing corrections. Retained Fumadocs, Academy, MCP reference, independent-trigger guidance, and the current logo. Removed the superseded Astro source/configuration and adapted CI, verification, Vercel configuration, and Docker to the Next.js standalone runtime. Historical hosting and content-review notes from main are preserved; deployment has not been performed by this merge.
65 changes: 34 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,57 @@
# Innflow Docs
# Innflow Docs and Academy

Innflow's documentation, built with Astro and Starlight. The site produces static HTML, CSS, JavaScript, fonts, and a Pagefind search index. It runs without a Mintlify subscription or a hosted search service.
Self-hostable documentation built with Next.js, Fumadocs, and MDX. No Mintlify account, database, paid search service, or API key is needed to run it.

## Local Development
## Develop

Use Node.js 24 LTS and npm:

```bash
```sh
npm ci
npm run dev
```

Open http://localhost:4321. Edit pages in `src/content/docs/` and sidebar groups in `navigation.json`. The original 37 MDX pages retain their public paths. The homepage is `/`, with `/index` redirected there. The initial migration preserved product prose; subsequent content reviews are recorded in `CONTENT-REVIEW.md`.
Open http://localhost:3000/academy for the Academy, `/` for documentation, or `/api-reference/introduction` for the API reference.

Validate and preview the production build:
## Verify and run

```bash
npm run check
```sh
npm run types:check
npm run build
npm run verify
npm run preview
npm start
```

`verify` checks every content page, navigation entry, local asset/link, search index, and the 404 output. GitHub Actions builds and uploads `dist/` on pull requests and pushes to main.
`npm start` serves the production build. Set `PORT` as needed. Set `SITE_URL` at build time for canonical URLs, the sitemap, and robots.txt; it defaults to https://docs.innflow.ai. Any host that runs a supported Node.js version and Next.js can serve this application. Search runs locally using Fumadocs/Orama. No external search account is required.

## Publishing
## Content

Publish `dist/` to a static host. Build command: `npm run build && npm run verify`. Output directory: `dist`. Set `SITE_URL` at build time if the canonical hostname differs from `https://docs.innflow.ai`.
- `content/docs/mcp/`: MCP connection, tool, workflow-node, operator configuration, and troubleshooting reference.
- `content/docs/academy/`: 15 original lessons and exercises, grouped by workflows, AI, workspace resources, and use cases.
- `content/docs/`: all 37 former Mintlify pages at their original public routes, plus the new AI Decision reference.
- `meta.json` files control navigation order and section roots.
- `components/mdx.tsx` provides MDX components, including compatibility for existing cards, steps, columns, and callouts.
- `public/` contains served logos, images, and favicon.
- `docs.json` is the previous Mintlify configuration retained as a migration reference; Fumadocs uses the content metadata instead.
- `/api/search`, `/sitemap.xml`, `/robots.txt`, and `/llms.txt` are generated from the same content source.

### Run on your own server
Add an MDX page with `title` and `description` frontmatter, then add its filename (without extension) to its folder's `meta.json`. Check links and run the build before publishing. The Academy is written instruction; no video course is claimed or embedded.

```bash
docker compose up -d --build
```
## Content accuracy

The unprivileged Nginx container serves the site on `127.0.0.1:8080`. Put the server's HTTPS reverse proxy in front of that address. It must preserve directory routes and return the provided 404 page with HTTP 404 for unknown paths.
The Academy is newly written and selected behavior was checked against the application source. The migrated reference pages are preserved content, not a claim that every old instruction, price, or integration option has been reverified. See `MIGRATION.md` for evidence and the remaining content review.

### Production deployment
## Publishing

https://docs.innflow.ai is served by the `flowlabs-inc/innflow-docs` Vercel project. GitHub pushes to `main` publish production; pull requests receive previews. Edit `src/content/docs/`, open a pull request, and merge after the build checks pass.
The existing repository deployment notes identify `flowlabs-inc/innflow-docs` as the Vercel project for `docs.innflow.ai`, with production publishing from `main`. This merge retains that setup and changes its checked-in framework configuration to Next.js. It does not change DNS or deploy anything itself. Confirm the project has no dashboard override still forcing Astro or `dist` before publishing.

The custom domain was released from Mintlify on 2026-09-18 and its CNAME now points to `bbc5a1816ac40fb3.vercel-dns-016.com.`. The alternate address is https://innflow-docs.vercel.app.
The earlier migration recorded the domain cutover on 2026-09-18 and preserved Mintlify on `archive/mintlify`. See `CONTENT-REVIEW.md` for that historical record; this local merge has not reverified live hosting or subscription state.

The previous Mintlify source is preserved on `archive/mintlify` at commit `4afb04a83863782c328882501e15654dc56ff338`. Mintlify tracks that archive branch instead of main. Its account and subscription were not deleted or cancelled. Rolling back the hostname requires releasing it from this Vercel project, attaching it in Mintlify, and restoring Mintlify's DNS target; changing DNS alone is insufficient.
GitHub Actions runs `npm ci`, `npm run check`, `npm run build`, and `npm run verify`. Verification starts the built standalone server and checks content routes, navigation, local links/assets, search, and the 404 response. Artifacts contain the standalone server, static chunks, and public assets; they are not a static HTML export.

### Run on your own server

```sh
docker compose up -d --build
```

## Structure
The unprivileged Node container runs the standalone Next.js server on `127.0.0.1:8080` through the existing Compose port mapping. Place your HTTPS reverse proxy in front of it. Search requires the server runtime; do not serve this build with the previous static Nginx configuration.

- `src/content/docs/` contains the MDX documentation.
- `navigation.json` controls the sidebar.
- `src/components/` supports the existing cards, columns, steps, and callouts.
- `src/styles/brand.css` and `src/assets/` contain brand styles and canonical Innflow logos.
- `public/` contains images and the favicon.
- `docs.json` retains the previous Mintlify configuration for migration reference; it does not drive the new site.
The default `npm start` command also runs the built application from a complete checkout. For a standalone bundle, copy `public/` and `.next/static/` into their corresponding locations under `.next/standalone/`, then run its `server.js`.
12 changes: 12 additions & 0 deletions app/(docs)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { source } from '@/lib/source';
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/notebook/page';
import { notFound } from 'next/navigation';
import { getMDXComponents } from '@/components/mdx';
import type { Metadata } from 'next';
type Props = { params: Promise<{ slug?: string[] }> };
export default async function Page({ params }: Props) {
const { slug } = await params; const page = source.getPage(slug); if (!page) notFound(); const MDX = page.data.body;
return <DocsPage toc={page.data.toc} full={page.data.full}><div className="page-eyebrow">{slug?.[0] === 'academy' ? 'INNFLOW ACADEMY' : slug?.[0] === 'mcp' ? 'MCP REFERENCE' : slug?.[0] === 'api-reference' ? 'DEVELOPER REFERENCE' : 'INNFLOW DOCUMENTATION'}</div><DocsTitle>{page.data.title}</DocsTitle><DocsDescription>{page.data.description}</DocsDescription><DocsBody><MDX components={getMDXComponents()} /></DocsBody></DocsPage>;
}
export async function generateStaticParams() { return source.generateParams(); }
export async function generateMetadata({ params }: Props): Promise<Metadata> { const page = source.getPage((await params).slug); if (!page) notFound(); return { title: page.data.title, description: page.data.description, alternates: { canonical: page.url } }; }
7 changes: 7 additions & 0 deletions app/(docs)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { navigation } from '@/lib/navigation';
import { DocsLayout } from 'fumadocs-ui/layouts/notebook';
import { baseOptions } from '@/lib/layout.shared';

export default function Layout({ children }: { children: React.ReactNode }) {
return <DocsLayout tree={navigation} {...baseOptions()} nav={{ ...baseOptions().nav, mode: 'top' }} tabMode="navbar">{children}</DocsLayout>;
}
4 changes: 4 additions & 0 deletions app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';

export const { GET } = createFromSource(source);
35 changes: 35 additions & 0 deletions app/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
:root { --color-fd-primary: #3659d9; --color-fd-primary-foreground: #fff; --color-fd-background: #fff; --color-fd-muted: #f6f7f9; --color-fd-accent: #edf1fe; --color-fd-accent-foreground: #2449bf; }
.dark { --color-fd-primary: #9badff; --color-fd-primary-foreground: #10172e; --color-fd-background: #111215; --color-fd-muted: #1b1d22; --color-fd-accent: #222a42; --color-fd-accent-foreground: #becaff; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; letter-spacing: -.012em; }
.brand { display:flex; align-items:center; gap:9px; font-size:23px; font-weight:650; letter-spacing:-1px; }
.brand-label { margin-left:7px; padding-left:16px; border-left:1px solid var(--color-fd-border); font-size:14px; letter-spacing:0; color:var(--color-fd-muted-foreground); font-weight:450; }
.section-tabs { display:flex; flex-wrap:wrap; gap:14px; border-bottom:1px solid var(--color-fd-border); padding:8px 0 13px; font-size:12px; }
.section-tabs a { color:var(--color-fd-muted-foreground); padding-bottom:5px; }
.section-tabs a[aria-current] { color:var(--color-fd-primary); box-shadow:0 2px 0 var(--color-fd-primary); }
.page-eyebrow,.learning-label { font-family:ui-monospace,monospace; font-size:10px; letter-spacing:.12em; color:var(--color-fd-muted-foreground); font-weight:600; }
.learning-goals { border:1px solid var(--color-fd-border); border-left:3px solid var(--color-fd-primary); padding:18px 22px; border-radius:6px; margin:24px 0; background:var(--color-fd-muted); }
.learning-goals p:first-child { margin-top:0; } .learning-goals ul { margin-bottom:0; }
.doc-columns { display:grid; grid-template-columns:repeat(var(--columns,2),minmax(0,1fr)); gap:12px; margin:24px 0; }
.doc-card { display:block; border:1px solid var(--color-fd-border); padding:18px; border-radius:8px; text-decoration:none!important; color:inherit!important; }
a.doc-card:hover { background:var(--color-fd-muted); border-color:var(--color-fd-primary); }
.doc-card-title { display:flex; justify-content:space-between; gap:12px; font-size:14px; font-weight:600; }
.doc-card-title > span { color:var(--color-fd-muted-foreground); }
.doc-card-body { font-size:13px; line-height:1.7; color:var(--color-fd-muted-foreground); margin-top:7px; }
.doc-card-body p { margin:0; }
.workflow-map { display:flex; align-items:center; gap:12px; margin:28px 0 32px; padding:24px 20px; border:1px solid var(--color-fd-border); border-radius:8px; background:var(--color-fd-muted); }
.workflow-map > div { flex:1; display:flex; flex-direction:column; gap:8px; }
.workflow-map span { font-family:ui-monospace,monospace; font-size:9px; letter-spacing:.08em; color:var(--color-fd-primary); }
.workflow-map strong { font-size:16px; } .workflow-map small { font-size:11px; color:var(--color-fd-muted-foreground); line-height:1.6; }
.workflow-map b { color:var(--color-fd-muted-foreground); font-weight:400; }
@media(max-width:640px) { .doc-columns { grid-template-columns:1fr; } .workflow-map { align-items:stretch; flex-direction:column; } .workflow-map b { transform:rotate(90deg); align-self:center; } }

.skip-link { position:fixed; left:16px; top:-80px; z-index:100; padding:12px 20px; background:var(--color-fd-background); color:var(--color-fd-foreground); border:1px solid var(--color-fd-border); }
.skip-link:focus { top:12px; }

.brand-logo { width:124px; height:30px; object-fit:contain; }
.brand-logo-dark { display:none; }
.dark .brand-logo-light { display:none; }
.dark .brand-logo-dark { display:block; }
5 changes: 5 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { RootProvider } from 'fumadocs-ui/provider/next';
import type { Metadata } from 'next';
import './global.css';
export const metadata: Metadata = { metadataBase: new URL(process.env.SITE_URL || 'https://docs.innflow.ai'), title: { default: 'Innflow Docs', template: '%s | Innflow Docs' }, description: 'Learn to build, connect, and operate workflows with Innflow.', icons: { icon: '/favicon.svg' } };
export default function Layout({ children }: { children: React.ReactNode }) { return <html lang="en" suppressHydrationWarning><body><a href="#nd-page" className="skip-link">Skip to content</a><RootProvider theme={{ defaultTheme: 'light' }}>{children}</RootProvider></body></html>; }
2 changes: 2 additions & 0 deletions app/llms.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { source } from '@/lib/source';
export function GET() { return new Response('# Innflow Documentation\n\n' + source.getPages().map(p => `- [${p.data.title}](${p.url}): ${p.data.description || ''}`).join('\n'), { headers: { 'Content-Type': 'text/plain; charset=utf-8' } }); }
2 changes: 2 additions & 0 deletions app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import type { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots { return { rules: { userAgent: '*', allow: '/' }, sitemap: `${process.env.SITE_URL || 'https://docs.innflow.ai'}/sitemap.xml` }; }
3 changes: 3 additions & 0 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { source } from '@/lib/source';
import type { MetadataRoute } from 'next';
export default function sitemap(): MetadataRoute.Sitemap { const base = process.env.SITE_URL || 'https://docs.innflow.ai'; return source.getPages().map(p => ({ url: new URL(p.url, base).href })); }
Loading
Loading