1. System Architecture Overview
SolidContext is a split-architecture system. Laravel handles content management and the web frontend. A dedicated Python (FastAPI) inference service handles all AI/LLM-facing requests — vector search, RAG queries, and embedding — because PHP is too slow for real-time inference workloads.
| Component | Technology | Role | Repo |
|---|---|---|---|
| CMS + Doc Generation | Laravel 12 Module | Content ingestion from Library domain, doc generation pipeline, admin management, web frontend API (browse/list/read) | platform-backend/Modules/SolidContext/ |
| Inference API | Python (FastAPI) + LlamaIndex | Vector search, RAG retrieval, LLM answer synthesis, embedding. All MCP/AI tool requests hit this service. | solidcontext-api/ (new repo) |
| Web Frontend | Nuxt 4 (SSR) | Public docs website — browse, search, read docs. SEO-indexed. Talks to Laravel for content, FastAPI for AI search. | solidcontext/ (new repo) |
| MCP Server | TypeScript npm package | Connects AI tools (Claude Code, Cursor, Copilot) to the Inference API. Distributed via npx. | solidcontext-mcp/ (new repo) |
2. Laravel Module (CMS): Modules/SolidContext/
Content ingestion, doc generation, and web browsing API. Follows nwidart/laravel-modules v12 conventions. Does not serve AI/LLM requests — those go to the FastAPI inference service.
Module Registration
// Modules/SolidContext/module.json { "name": "SolidContext", "alias": "solidcontext", "active": true, "providers": [ "Modules\\SolidContext\\Providers\\SolidContextServiceProvider" ] }
Models
SolidContextDoc — The core entity
Each doc is a generated, structured piece of documentation derived from Library content.
class SolidContextDoc extends Model { use HasFactory, UsesUuid, SoftDeletes; protected $table = 'solid_context_docs'; protected $fillable = [ 'software_id', 'title', 'slug', 'content', 'summary', 'software_version', 'tags', 'difficulty', 'token_count', 'snippet_count', 'tier', 'source_type', 'source_id', 'published_at', ]; protected function casts(): array { return [ 'tags' => 'array', 'published_at' => 'datetime', 'tier' => SolidContextTier::class, 'difficulty' => SolidContextDifficulty::class, ]; } public function software(): BelongsTo { return $this->belongsTo(SolidContextSoftware::class, 'software_id'); } protected static function newFactory(): SolidContextDocFactory { return SolidContextDocFactory::new(); } }
SolidContextSoftware — Software catalog mirror
class SolidContextSoftware extends Model { use HasFactory, UsesUuid; protected $table = 'solid_context_software'; protected $fillable = [ 'library_software_id', 'name', 'slug', 'description', 'versions', 'doc_count', 'logo_url', ]; protected function casts(): array { return [ 'versions' => 'array', ]; } public function docs(): HasMany { return $this->hasMany(SolidContextDoc::class, 'software_id'); } protected static function newFactory(): SolidContextSoftwareFactory { return SolidContextSoftwareFactory::new(); } }
Services
DocGenerationService
Transforms Library domain content into SolidContext docs. This is the heart of the system.
class DocGenerationService { /** * Generate docs for a specific software. * Reads from Library domain models (Lesson, CourseVersion). * Applies visibility rules from LibraryAggregator. */ public function generateForSoftware(Software $software): int { $docsGenerated = 0; $software->courseVersions() ->where(fn ($q) => $q ->whereHas('status', fn ($q) => $q->where('tag', 'published')) ->whereHas('privacy', fn ($q) => $q->where('tag', 'public')) ) ->with(['sections.lessons']) ->chunkById(50, function ($versions) use (&$docsGenerated) { $versions->each(function (CourseVersion $version) use (&$docsGenerated) { $version->sections->flatMap->lessons->each( function (Lesson $lesson) use ($version, &$docsGenerated) { $this->generateDocFromLesson($lesson, $version); $docsGenerated++; } ); }); }); return $docsGenerated; } /** * Transform a Lesson into a SolidContext doc. * Uses the lesson_script accessor (strips HTML, URL-decodes, unescapes). */ private function generateDocFromLesson(Lesson $lesson, CourseVersion $version): SolidContextDoc { return SolidContextDoc::updateOrCreate( ['source_type' => 'lesson', 'source_id' => $lesson->uuid], [ 'title' => $lesson->name, 'slug' => $lesson->slug, 'content' => $lesson->lesson_script, // sanitized via accessor 'summary' => Str::words($lesson->lesson_script, 200), 'tags' => $lesson->tags, 'tier' => $this->determineTier($lesson, $version), // ... remaining fields ] ); } }
DocSearchService (Laravel — basic text search for web frontend)
Simple Eloquent search for the Nuxt 4 browsing experience. Not used by MCP or AI tools.
class DocSearchService { public function search( string $query, ?string $softwareSlug = null, ?string $version = null, int $limit = 10, ): LengthAwarePaginator { return SolidContextDoc::query() ->whereNotNull('published_at') ->when($softwareSlug, fn ($q, $slug) => $q->whereHas('software', fn ($q) => $q->where('slug', $slug)) ) ->when($version, fn ($q, $v) => $q->where('software_version', $v) ) ->where(fn ($q) => $q->where('title', 'like', "%{$query}%") ->orWhereJsonContains('tags', $query) ->orWhere('content', 'like', "%{$query}%") ) ->paginate($limit); } }
DocSearchService is a basic text search for the web frontend's browsing experience. All AI-powered semantic search (vector similarity, RAG retrieval) happens in the FastAPI inference service using LlamaIndex + pgvector/Pinecone. MCP tools and AI clients never touch Laravel directly.
Artisan Command
// php artisan solidcontext:generate-docs // Regenerates all docs from Library content. Safe to re-run (uses updateOrCreate). // Run on schedule (weekly) or manually after content publishes. class GenerateDocsCommand extends Command { protected $signature = 'solidcontext:generate-docs {--software= : Filter by software slug}'; public function handle(DocGenerationService $service): int { $total = Software::query() ->isVisible()->isPublished() ->when($this->option('software'), fn ($q, $slug) => $q->where('slug', $slug) ) ->get() ->sum(function (Software $software) use ($service) { $count = $service->generateForSoftware($software); $this->info("Generated {$count} docs for {$software->name}"); return $count; }); $this->info("Total: {$total} docs generated."); return Command::SUCCESS; } }
3. Data Pipeline
Content flows from the Library domain through a generation pipeline into SolidContext docs.
Source Data
| Source | Model | Key Fields | Location |
|---|---|---|---|
| Lesson Transcripts | Lesson |
lesson_script (via accessor: strips HTML, URL-decodes, unescapes entities), name, slug, duration, difficulty_level, tags via lessonTags() |
app/Library/Courses/Models/Lesson.php |
| Course Metadata | CourseVersion |
name, description, version, language, sections hierarchy, lesson_tags (aggregated) |
app/Library/Courses/Models/CourseVersion.php |
| Software Catalog | Software |
name, slug, description, visibility, status |
app/Library/Software/Models/Software.php |
| Transcript Segments | VideoTranscriptSegment |
text, start/end timestamps, lesson context. Already chunked. Indexed in Typesense (not Algolia). |
app/Library/Models/VideoTranscriptSegment.php |
Visibility Rules (What Gets Published)
The generation pipeline reuses the Library domain's existing visibility logic:
- Software:
visibility.tag === 'everyone'ANDstatus.tag === 'published'(fromLibraryAggregator.shouldSoftwareBeSearchable()) - CourseVersion:
isSearchable()— not deleted, has course, status=PUBLISHED, privacy=PUBLIC, non-member access ≠ COURSE_INVISIBLE, within 10 years (fromCourseVersion.isSearchable()) - Lesson: Not soft-deleted, has section, section has version, version passes
isSearchable()(fromLibraryAggregator.shouldLessonBeSearchable())
Tier Determination
| Condition | Tier | Content Served |
|---|---|---|
Course has FIRST_FIVE_UNLOCKED non-member access AND lesson is in first 5 |
Free | Full content + summary |
| Introductory / fundamentals courses (first course in family) | Free | Full content + summary |
| All other published, public content | Premium | Summary only (free tier), full content (premium tier) |
Pipeline Steps
- Query Library models — Filter by visibility rules, eager load sections + lessons + tags
- Extract content — Read
lesson_script(auto-sanitized by Eloquent accessor), gather metadata - Generate doc — Create/update
SolidContextDocwith content, summary, tags, tier, token count - Index for search — (MVP: no-op, uses LIKE queries. v2: push to Algolia
solid_contextindex) - Cache software counts — Update
doc_countonSolidContextSoftware
4. Database Schema
-- Modules/SolidContext/database/migrations/ CREATE TABLE solid_context_software ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, uuid CHAR(36) UNIQUE NOT NULL, library_software_id BIGINT UNSIGNED, -- FK to software table name VARCHAR(255) NOT NULL, slug VARCHAR(255) UNIQUE NOT NULL, description TEXT, versions JSON, -- ["2024", "2025", "Evergreen"] doc_count INT UNSIGNED DEFAULT 0, logo_url VARCHAR(500), created_at TIMESTAMP, updated_at TIMESTAMP ); CREATE TABLE solid_context_docs ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, uuid CHAR(36) UNIQUE NOT NULL, software_id BIGINT UNSIGNED NOT NULL, -- FK to solid_context_software title VARCHAR(500) NOT NULL, slug VARCHAR(500) NOT NULL, content LONGTEXT, -- Full doc content (markdown) summary TEXT, -- ~200 word summary (free tier) software_version VARCHAR(50), -- "2024", "Evergreen" tags JSON, -- ["features", "sweep"] difficulty VARCHAR(20), -- beginner, intermediate, advanced token_count INT UNSIGNED DEFAULT 0, snippet_count INT UNSIGNED DEFAULT 0, tier VARCHAR(20) NOT NULL DEFAULT 'premium', -- free, premium source_type VARCHAR(50), -- lesson, course_version source_id CHAR(36), -- UUID of source entity published_at TIMESTAMP NULL, created_at TIMESTAMP, updated_at TIMESTAMP, deleted_at TIMESTAMP NULL, INDEX idx_software_id (software_id), INDEX idx_slug (slug), INDEX idx_tier (tier), INDEX idx_software_version (software_version), INDEX idx_source (source_type, source_id), UNIQUE idx_software_slug (software_id, slug, software_version), FOREIGN KEY (software_id) REFERENCES solid_context_software(id) );
5. API Design
Two separate API surfaces. Laravel serves the content management and web browsing endpoints. FastAPI serves the performance-critical inference endpoints that AI tools and MCP hit.
Laravel CMS API — /api/solidcontext/v1/
Content browsing, listing, and reading. Powers the Nuxt 4 frontend. Standard Laravel module routes.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/solidcontext/v1/software |
Public | List all software with doc counts and versions |
GET |
/api/solidcontext/v1/software/{slug} |
Public | Software detail with version list |
GET |
/api/solidcontext/v1/software/{slug}/docs |
Public | List docs for a software (paginated). Returns summaries for premium docs. |
GET |
/api/solidcontext/v1/docs/{uuid} |
Public | Single doc. Free tier docs: full content. Premium docs: summary only. |
GET |
/api/solidcontext/v1/docs/{uuid}/full |
API Key | Full content for premium docs. Requires X-SolidContext-Key header. |
FastAPI Inference API — inference.solidcontext.com/v1/
High-performance vector search and RAG retrieval. This is what MCP servers and AI tools call. Python + LlamaIndex.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/v1/query |
Free / API Key | RAG query — vector search + LLM synthesis. Returns an answer with source citations. Tier determines content depth. |
GET |
/v1/search |
Free / API Key | Semantic vector search. Params: q, software, version, top_k. Returns ranked doc chunks. |
GET |
/v1/resolve/{name} |
Public | Fuzzy-resolve a software name to a SolidContext software object. Used by MCP resolve-software tool. |
POST |
/v1/embed |
Enterprise | Upload and embed private content for a tenant. Used by VARs to index their proprietary docs. |
API Resources
// SolidContextDocResource — controls tier-based content visibility class SolidContextDocResource extends JsonResource { public function toArray($request): array { $isPremiumAuthorized = $this->isAuthorizedForFullContent($request); return [ 'uuid' => $this->uuid, 'title' => $this->title, 'slug' => $this->slug, 'software' => SolidContextSoftwareResource::make($this->whenLoaded('software')), 'software_version' => $this->software_version, 'tags' => $this->tags, 'difficulty' => $this->difficulty, 'token_count' => $this->token_count, 'snippet_count' => $this->snippet_count, 'tier' => $this->tier, 'summary' => $this->summary, 'content' => $this->when( $this->tier === SolidContextTier::Free || $isPremiumAuthorized, $this->content ), 'published_at' => $this->published_at, ]; } }
6. MVP Pages (Nuxt 4 Frontend)
| Route | Page | SSR | Description |
|---|---|---|---|
/ |
pages/index.vue |
Yes | Homepage — hero, search bar, software grid, featured docs |
/software |
pages/software/index.vue |
Yes | Full software catalog with doc counts |
/software/:slug |
pages/software/[slug].vue |
Yes | Software detail — version filter, doc listing, description |
/software/:slug/:doc |
pages/software/[slug]/[doc].vue |
Yes | Doc detail — full content, related docs, "powered by SolidProfessor" CTA |
/search |
pages/search.vue |
No | Search results with filters (software, version, tier, difficulty) |
/library/ app's routeRules.
7. Nuxt 4 Configuration
Following the /library/ app pattern exactly:
// solidcontext/nuxt.config.ts import tailwindcss from '@tailwindcss/vite' export default defineNuxtConfig({ compatibilityDate: '2026-03-14', ssr: true, app: { head: { title: 'SolidContext — Engineering Docs for AI', link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap' }, ], }, }, vite: { plugins: [tailwindcss()], }, routeRules: { '/': { ssr: true }, '/software': { ssr: true }, '/software/**': { ssr: true }, '/search': { ssr: false }, }, runtimeConfig: { public: { cmsApiBase: process.env.NUXT_PUBLIC_CMS_API_BASE || 'http://localhost:8080/api/solidcontext/v1', inferenceBase: process.env.NUXT_PUBLIC_INFERENCE_BASE || 'http://localhost:8000/v1', spUrl: process.env.NUXT_PUBLIC_SP_URL || 'https://www.solidprofessor.com', }, }, devServer: { port: 3140 }, typescript: { strict: true }, modules: ['@pinia/nuxt'], })
Composables
// composables/useSolidContextApi.ts // Two API bases: Laravel for content browsing, FastAPI for AI search export function useSolidContextApi() { const config = useRuntimeConfig() const cms = config.public.cmsApiBase // Laravel: /api/solidcontext/v1 const inference = config.public.inferenceBase // FastAPI: inference.solidcontext.com/v1 return { // Content browsing (Laravel CMS API) listSoftware: () => useFetch(`${cms}/software`), getSoftware: (slug: string) => useFetch(`${cms}/software/${slug}`), listDocs: (slug: string, params?: Record<string, string>) => useFetch(`${cms}/software/${slug}/docs`, { params }), getDoc: (uuid: string) => useFetch(`${cms}/docs/${uuid}`), // AI-powered search (FastAPI Inference API) search: (params: Record<string, string>) => useFetch(`${inference}/search`, { params }), query: (prompt: string, software?: string) => useFetch(`${inference}/query`, { method: 'POST', body: { prompt, software }, }), } }
8. MCP Server
TypeScript npm package using @modelcontextprotocol/sdk. All MCP tool calls hit the FastAPI Inference API (not Laravel). Two operating modes:
| Mode | Data Source | When |
|---|---|---|
| API Mode (default) | Queries the FastAPI inference service at runtime | User has internet. Freshest data. Pro/Enterprise tiers require API key. |
| Bundled Mode | Pre-built JSON data bundle shipped with npm package | Offline use. Free tier only. Updated on npm publish. |
MCP Tools
| Tool | Input | Output | Inference API Call |
|---|---|---|---|
resolve-software |
{ name: "solidworks" } |
Software object with slug, versions, doc count | GET /v1/resolve/{name} |
query-docs |
{ softwareId, query, version? } |
RAG answer with source citations + ranked doc chunks | POST /v1/query |
Distribution
# Users install with a single line in their MCP config: { "mcpServers": { "solidcontext": { "command": "npx", "args": ["-y", "@solidprofessorhub/solidcontext-mcp"], "env": { "SOLIDCONTEXT_API_KEY": "sc_..." // optional, for premium tier } } } }
9. Authentication & Tiers
API Key Model
SolidContext uses its own API key system, separate from Passport OAuth2. These are long-lived keys for MCP/programmatic access, not user sessions.
Free
For individuals
- Public Repos
- Access Control
- OAuth 2.0
Pro
For professionals
- Private Repos
- Team Collaboration
- Unlimited API Calls
Enterprise
For enterprises
- SOC-2 and GDPR
- SSO (SAML / OIDC)
- Self-Hosted
API Access by Tier
| Tier | Auth | Content Access | Rate Limit |
|---|---|---|---|
| Free | None required | Public repos, doc metadata, summaries, free-tier doc content | 60 req/min per IP |
| Pro | X-SolidContext-Key header |
Everything in Free + private repos, full content for all docs, team collaboration | Unlimited |
| Enterprise | X-SolidContext-Key + SSO (SAML / OIDC) |
Everything in Pro + self-hosted deployment, SOC-2 and GDPR compliance | Unlimited |
10. Core RAG Pipeline
SolidContext is a domain-specific Retrieval-Augmented Generation (RAG) system. The competitive advantage is the quality of answers derived from proprietary mechanical engineering content, not just a search wrapper.
Ingestion & Parsing
The ingestion pipeline processes internal SME documentation from the Library domain. Course materials (Markdown lesson scripts, video transcripts, CAD metadata) are extracted and cleaned through the existing Eloquent accessors and dedicated parsers.
| Source | Parser | Notes |
|---|---|---|
| Lesson scripts | Eloquent accessor (lesson_script) |
Already strips HTML, URL-decodes, unescapes entities |
| Video transcripts | VideoTranscriptSegment |
Pre-chunked in Typesense with timestamps |
| Course metadata | CourseVersion + relationships |
Name, description, version, section hierarchy |
| PDFs / CAD docs | LlamaParse or Unstructured.io | Future: parse supplemental materials and CAD metadata |
Chunking & Embedding
Documents are broken into logical chunks (by paragraph, course module, or lesson) and converted into numerical vectors via an embedding model.
# solidcontext-api/app/pipeline/embed.py # Runs in the FastAPI service — called by Laravel via internal API after doc generation from llama_index.core import Document, VectorStoreIndex from llama_index.core.node_parser import SentenceSplitter async def embed_document(doc: SolidContextDoc, vector_store: VectorStore): splitter = SentenceSplitter(chunk_size=512, chunk_overlap=50) nodes = splitter.get_nodes_from_documents([ Document( text=doc.content, metadata={ "tenant_id": "solidprofessor", "software": doc.software_slug, "version": doc.software_version, "tier": doc.tier, "source_id": doc.uuid, }, ) ]) await vector_store.async_add(nodes)
Vector Storage & Retrieval
Vectors are stored in a database optimized for similarity search. When a user asks a question, it's converted to a vector, the most relevant chunks are retrieved, and fed to an LLM to synthesize an answer.
| Option | Pros | Best For |
|---|---|---|
| pgvector (via Supabase) | Single database for auth, relational data, and vectors. No new infrastructure. | MVP — simplest path to production |
| Pinecone | Purpose-built for vector search. Managed, scales automatically. Native metadata filtering. | Scale — when query volume justifies dedicated infra |
| Weaviate | Open-source, self-hostable. Hybrid search (vector + keyword). GraphQL API. | Enterprise — self-hosted deployments |
text-embedding-3-small for cost efficiency. Evaluate open-source alternatives like BGE-m3 for self-hosted Enterprise tier where data must not leave the customer's infrastructure.
11. Multi-Tenancy (Enterprise / VARs)
The Enterprise tier enables Value Added Resellers (VARs) to search SolidProfessor's foundational content plus their own private content, with strict data isolation between tenants.
Metadata Filtering Architecture
Instead of separate databases per tenant, every vector is tagged with a tenant_id. Query-time filtering enforces isolation. This runs in the FastAPI inference service, not Laravel.
# solidcontext-api/app/services/search.py # Multi-tenant retrieval — filters at query time class MultiTenantSearchService: def __init__(self, vector_store: VectorStore): self.vector_store = vector_store async def search( self, query: str, user: AuthenticatedUser, top_k: int = 10, ) -> list[DocChunk]: tenant_filter = self._resolve_tenants(user) return await self.vector_store.similarity_search( query=query, top_k=top_k, filter={"tenant_id": {"$in": tenant_filter}}, ) def _resolve_tenants(self, user: AuthenticatedUser) -> list[str]: match user.tier: case Tier.ENTERPRISE: return ["solidprofessor", user.tenant_id] case Tier.PRO: return ["solidprofessor"] case _: return ["solidprofessor"]
Tier Access Model
| Tier | Content Access | Data Isolation |
|---|---|---|
| Free | Vectors tagged tenant_id: solidprofessor (public content only) |
Shared — read-only base content |
| Pro | All SolidProfessor vectors (public + premium content) | Shared — full SP content library |
| Enterprise | tenant_id: solidprofessor OR tenant_id: {var_id} |
Isolated — VAR's private content never visible to other tenants |
12. Usage-Based Billing
Pro and Enterprise tiers are billed based on actual consumption — token usage across search queries and generated answers.
Token Tracking
Every search query and RAG-generated answer consumes LLM tokens. An observability gateway sits between the application and the LLM provider to automatically log usage per user or API key.
| Tool | Role | Key Feature |
|---|---|---|
| Helicone | LLM proxy / observability | One-line integration, per-user token tracking, cost analytics, caching |
| Langfuse | LLM observability / tracing | Open-source, detailed trace visualization, prompt management, self-hostable |
Billing Engine
Token usage data feeds into a metered billing platform. Monthly aggregation with configurable markup on base LLM costs.
# solidcontext-api/app/middleware/token_tracking.py # FastAPI middleware — tracks token usage on every inference request from fastapi import Request, Response from starlette.middleware.base import BaseHTTPMiddleware class TrackTokenUsage(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next) -> Response: response = await call_next(request) if token_usage := response.headers.get("X-Token-Usage"): await self.usage_store.record( api_key_id=request.state.api_key.id, tenant_id=request.state.api_key.tenant_id, tokens_used=int(token_usage), endpoint=request.url.path, ) return response
Billing Integration
| Option | Type | Best For |
|---|---|---|
| Stripe Metered Billing | SaaS billing platform | Already integrated in platform-backend via Laravel Cashier. Natural fit. |
| Lago | Open-source billing engine | Complex pricing models, self-hostable, granular usage events |
13. Full Module Structure
14. Tech Stack Summary
CMS + Web Frontend
| Component | Technology | Version |
|---|---|---|
| CMS Backend | Laravel | v12 |
| Module System | nwidart/laravel-modules | v12 |
| PHP | PHP | 8.4 |
| Web Frontend | Nuxt | 4.x |
| CSS | Tailwind CSS | v4 (via @tailwindcss/vite) |
| State Management | Pinia | v2 |
Inference API (AI/LLM-facing)
| Component | Technology | Version |
|---|---|---|
| Inference Framework | FastAPI (Python) | 0.115+ |
| Python | Python | 3.12+ |
| MCP SDK | @modelcontextprotocol/sdk | latest |
| MCP Runtime | TypeScript + tsx | latest |
RAG & AI Layer
| Component | Technology | Purpose |
|---|---|---|
| Orchestration | LlamaIndex | Domain-specific document structuring and advanced retrieval |
| Embeddings | OpenAI text-embedding-3-small | Convert content chunks into vectors (cost-efficient) |
| Embeddings (self-hosted) | BGE-m3 | Open-source alternative for Enterprise self-hosted deployments |
| Vector Store (MVP) | pgvector via Supabase | Auth, relational data, and vectors in one database |
| Vector Store (Scale) | Pinecone | Managed, auto-scaling, native metadata filtering for multi-tenancy |
| Document Parsing | LlamaParse / Unstructured.io | Extract text from PDFs, CAD docs, supplemental materials |
| LLM Provider | OpenAI / Anthropic API | Answer synthesis from retrieved context chunks |
Observability & Billing
| Component | Technology | Purpose |
|---|---|---|
| LLM Observability | Helicone or Langfuse | Token tracking, cost analytics, per-user usage logging |
| Billing | Stripe Metered Billing (via Laravel Cashier) | Usage-based invoicing, overage billing, subscription management |
| Billing (alt) | Lago | Open-source, complex pricing models, self-hostable |
Testing & Quality
| Component | Technology | Version |
|---|---|---|
| Testing (Backend) | Pest | v3 |
| Testing (Frontend) | Vitest + Vue Test Utils | latest |
| Formatting | Laravel Pint + ESLint | latest |
15. Estimated Timeline
| Phase | Scope | Duration |
|---|---|---|
| Phase 1: Laravel Module + RAG Pipeline | Models, migrations, ingestion pipeline, chunking, embedding, pgvector setup, artisan command, API endpoints (free tier only) | 2-3 weeks |
| Phase 2: Nuxt 4 Frontend | 5 MVP pages, composables, basic Tailwind styling, SSR config | 1-2 weeks |
| Phase 3: MCP Server | TypeScript MCP server, 2 tools, API mode, npm publishing | 1 week |
| Phase 4: Pro Tier + Billing | API key auth, Stripe metered billing, Helicone/Langfuse integration, token tracking, rate limiting | 1-2 weeks |
| Phase 5: Enterprise + Multi-Tenancy | Tenant metadata filtering, VAR content upload pipeline, SSO (SAML/OIDC), self-hosted vector store option, SOC-2/GDPR compliance | 2-3 weeks |