StackAlchemist is a micro-SaaS (Next.js 15 + .NET 10 + Supabase + Cloudflare R2 + Stripe + Anthropic Claude) that generates compile-verified code repos from natural language. A full audit reveals critical production gaps: the LLM engine silently falls back to mock data in prod, no retry logic on API failures, no cost tracking, mobile-broken editor pages, zero SEO infrastructure, legacy "Bolt.new" references in code, and 40KB monolith components. This plan addresses all of it.
File: src/StackAlchemist.Engine/Program.cs:83-97
- Add
ANTHROPIC_API_KEY,SUPABASE_SERVICE_ROLE_KEY,R2_ACCESS_KEY_IDto therequiredarray - Add startup log warning when MockLlmClient is active (lines 217-225)
- Why: Prod currently starts fine without an API key and silently returns fake code to paying users
- Verify: Start engine in Production mode without
ANTHROPIC_API_KEY-- must throwInvalidOperationException
File: src/StackAlchemist.Engine/Services/AnthropicLlmClient.cs:56-70
File: src/StackAlchemist.Engine/Program.cs:185-189 (HttpClient registration)
- Add
Microsoft.Extensions.Http.Resiliencestandard resilience handler on the HttpClient, OR implement retry loop inGenerateAsyncwith: retry on 429/500/502/503/529, parseretry-afterheader, exponential backoff (1s base), max 3 retries, jitter - Verify: Unit test with mock HttpMessageHandler returning 429 twice then 200
File: src/StackAlchemist.Engine/Services/ILlmClient.cs
File: src/StackAlchemist.Engine/Services/AnthropicLlmClient.cs:72-76
File: src/StackAlchemist.Engine/Services/GenerationOrchestrator.cs:69
File: src/StackAlchemist.Engine/Services/CompileWorkerService.cs:163
- Change
ILlmClient.GenerateAsyncreturn fromTask<string>toTask<LlmResponse>(new record:Text,InputTokens,OutputTokens,Model) - Add Supabase migration:
input_tokens,output_tokens,model_usedcolumns ongenerations - Add
UpdateTokenUsageAsynctoIDeliveryService/SupabaseDeliveryService - Update both callers
- Verify: Run generation, query DB, confirm token columns populated
File: src/StackAlchemist.Engine/Services/SchemaExtractionService.cs:68-86
File: src/StackAlchemist.Web/src/lib/actions.ts:207
- After
MapToSchema, validate: max 20 entities, max 30 fields/entity, max 30 relationships. ThrowSchemaValidationExceptionif exceeded - Add matching client-side validation in
actions.ts - Verify: Submit schema with 25 entities -- rejected with clear error
File: src/StackAlchemist.Engine/Services/PromptBuilderService.cs:82-129
- Create
SanitizeUserInput(string input, int maxLength)that: caps length (500 chars descriptions, 50 names), strips[[FILE:,[[END_FILE]],##line starts, unicode control chars - Apply to all personalization fields before prompt interpolation
- Verify: Submit generation with
BusinessDescriptioncontaining[[FILE:etc/passwd]]-- stripped
File: src/StackAlchemist.Engine/Services/SupabaseDeliveryService.cs:84-123
- Create Supabase migration with
append_build_log(gen_id uuid, chunk text)Postgres function (atomic concatenation) - Replace fetch-append-patch with single RPC call
- Verify: Concurrent appends produce complete, ordered log
File: src/StackAlchemist.Engine/Program.cs:60-79
File: src/StackAlchemist.Engine/appsettings.json:15
- Add
["Anthropic:Model"] = Ev("ANTHROPIC_MODEL")to env mapping - Verify current model identifier is latest stable Claude 3.5 Sonnet
- Verify: Set
ANTHROPIC_MODELenv var, confirm engine uses it
File: src/StackAlchemist.Web/src/app/layout.tsx:19-26
- Add
export const viewport: Viewportwithwidth: "device-width",initialScale: 1,maximumScale: 5,viewportFit: "cover" - Import
Viewportfromnext - Verify: Inspect
<meta name="viewport">in page source
File: src/StackAlchemist.Web/src/app/advanced/AdvancedModePage.tsx:612,616
- Replace
hidden lg:flexwith collapsible "Preview" toggle visible on mobile/tablet - Replace
minHeight: "400px"withmin-h-[250px] md:min-h-[400px] - Verify: Test at 375px, 768px, 1024px viewports
File: src/StackAlchemist.Web/src/app/simple/SimpleModePage.tsx
- Enable
panOnDrag,zoomOnPinchon React Flow - Fix modal
fixed inset-0 py-8for mobile keyboard avoidance (usepb-safeor dynamic viewport unitsdvh) - Verify: Test touch interactions on mobile emulator
File: src/StackAlchemist.Web/src/app/page.tsx:290-296
File: src/StackAlchemist.Web/src/app/pricing/page.tsx (similar lines)
- Replace
h-[800px] w-[800px]withh-[300px] w-[300px] md:h-[600px] md:w-[600px] lg:h-[800px] lg:w-[800px] - Same for 600px blobs
- Verify: No horizontal overflow on 375px viewport
File: src/StackAlchemist.Web/src/components/navbar.tsx
- Convert to client component with hamburger toggle (Menu/X from lucide-react)
- Add mobile dropdown with navigation links
- Home page (
page.tsx:347-368) already has working mobile menu -- extract and share pattern - Verify: Hamburger appears at 375px, links accessible
File: src/StackAlchemist.Web/src/app/globals.css
- Add
@media (prefers-reduced-motion: reduce)rule zeroing animation/transition durations - Verify: Enable "Reduce motion" in OS, confirm no animations
File: src/StackAlchemist.Web/src/app/globals.css
- Add
:focus-visible { outline: 2px solid var(--color-electric, #4da6ff); outline-offset: 2px; } - Verify: Tab through pages, all interactive elements show visible outline
File: src/StackAlchemist.Web/src/app/layout.tsx:19-26
- Expand
metadatawithmetadataBase,openGraph(type, title, description, siteName, images),twitter(card, title, description, images) - Use template pattern:
title: { default: "StackAlchemist", template: "%s | StackAlchemist" } - Create
public/og-image.png(1200x630) with StackAlchemist branding - Verify: metatags.io or Twitter Card Validator
Files missing metadata (confirmed -- only root layout and docs layout have it):
src/app/about/page.tsxsrc/app/pricing/page.tsxsrc/app/story/page.tsxsrc/app/login/page.tsxsrc/app/register/page.tsxsrc/app/dashboard/page.tsxsrc/app/simple/page.tsxsrc/app/advanced/page.tsx- Add
export const metadata: Metadatato each with unique title + description - For client-component pages, metadata must be in the server
page.tsxwrapper - Verify: View source on each page, confirm unique
<title>tags
New files (confirmed neither exists):
src/StackAlchemist.Web/src/app/sitemap.ts-- all static routes + dynamic doc slugssrc/StackAlchemist.Web/src/app/robots.ts-- allow public pages, disallow/dashboard,/generate,/api- Verify: Visit
/sitemap.xmland/robots.txtin browser
File: src/StackAlchemist.Web/src/app/layout.tsx
- Add
SoftwareApplicationschema via<script type="application/ld+json"> - Add
Productschema on pricing page with tier pricing - Verify: Google Rich Results Test
File: src/StackAlchemist.Web/next.config.ts
- Add
images: { formats: ["image/avif", "image/webp"] } - Audit all
<Image>components for missingalttext - Verify: Network tab shows WebP/AVIF format
File: src/StackAlchemist.Web/src/app/simple/SimpleModePage.tsx (859 lines, ~40KB)
- Extract:
simple/types.ts,simple/constants.ts,simple/hooks/useSchemaGraph.ts - Extract shared:
components/schema-editor.tsx,components/tier-selector.tsx - Keep
SimpleModePage.tsxas orchestrator - Verify:
pnpm lint,pnpm build, manual test of simple mode flow
File: src/StackAlchemist.Web/src/app/advanced/AdvancedModePage.tsx (671 lines, ~36KB)
- Extract each step:
steps/StepEntities.tsx,steps/StepRelationships.tsx,steps/StepEndpoints.tsx,steps/StepReview.tsx,steps/StepTier.tsx - Extract shared types to
advanced/types.ts - Reuse
tier-selector.tsxfrom Task 4.1 - Verify:
pnpm lint,pnpm build, manual test all 5 wizard steps
Confirmed locations:
src/StackAlchemist.Web/src/app/error.tsx:23-- "In Bolt.new this usually means a backend-only path was reached" -- rewrite to StackAlchemist contextsrc/StackAlchemist.Web/src/lib/demo-data.ts:86,91-- demo data references Bolt.new -- update to StackAlchemistdocs/product/Market Requirements Document.md:19-- competitor mention, this one is intentional/correct- Verify:
grep -r "Bolt.new" src/returns only the intentional docs reference
New files:
src/app/simple/error.tsxsrc/app/advanced/error.tsxsrc/app/generate/[id]/error.tsxsrc/app/dashboard/error.tsx- Each: context-appropriate error message + "Try Again" button, StackAlchemist branding (not generic slate-800)
- Verify: Temporarily throw in each route, confirm boundary catches
File: src/StackAlchemist.Engine/appsettings.json
- Remove empty-string secret values (ApiKey, SecretKey, etc.) -- they come from env vars via
Program.csmapping - Keep only non-secret config: Model, MaxTokens, BucketName, PresignedUrlExpiryHours
- Verify:
dotnet build, engine starts in dev mode
File: src/StackAlchemist.Web/.eslintrc.json
- Add:
no-console(warn, allow warn/error),@typescript-eslint/no-unused-vars(warn),react-hooks/exhaustive-deps(warn) - Run
pnpm lint --fix, address warnings - Verify:
pnpm lintpasses clean
31 docs across 6 directories. Priority order:
README.md-- first thing users/contributors see. Verify quickstart commands, dependency versions, feature listdocs/user/getting-started.md-- verify matches current UI flowdocs/architecture/Software Design Document.md-- verify matches current implementationdocs/advanced-docs/architecture-overview.md-- verify current statedocs/user/(7 files) -- verify UI flows, tiers, pricing ($299/$599/$999), screenshots if anydocs/architecture/(8 files) -- verify ERD matches migrations, state machine matchesGenerationStateMachine.cs, data flow matches current endpointsconductor/(7 files) -- verify operational procedures still valid, remove stale runbooksCI-CD-STATUS-REPORT.md-- update or remove if staleAGENTS.md-- verify agent descriptions match current codedocs/product/(6 files) -- verify product docs reflect current feature set
Check for:
- References to phases as "future work" when already implemented
- Code snippets that no longer compile
- API endpoints that changed
- Pricing that doesn't match UI
- Any remaining "Bolt.new" references (intentional competitor mentions OK)
- Use
/audit-websiteskill against the deployed site URL - Address findings in Phase 3 tasks or create follow-up items
- Verify: Re-run audit, confirm score improvements
Week 1:
Dev A (Backend): Phase 1 tasks 1.1-1.7
Dev B (Frontend): Phase 2 tasks 2.1-2.7 + Phase 3 tasks 3.1-3.5
Week 2:
Dev A: Phase 4 tasks 4.1-4.2 (component decomposition)
Dev B: Phase 4 tasks 4.3-4.6 (cleanup)
Week 3:
Both: Phase 5 (docs revision) + integration testing + SEO audit
Dependencies:
- Task 1.3 and 1.6 need Supabase migrations (can be batched)
- Task 4.2 depends on 4.1 (shared
tier-selectorcomponent) - Phase 5 should run last so docs reflect final state
- All other tasks are independent and parallelizable
- Engine refuses to start in prod without
ANTHROPIC_API_KEY - LLM calls retry on 429/5xx with backoff
- Token usage persisted to DB after each generation
- Schema with 25+ entities rejected
- Prompt injection in personalization fields stripped
- Build logs survive concurrent appends
- All pages render correctly at 375px, 768px, 1024px
- React Flow visible and interactive on mobile
- No horizontal overflow on any page
- Tab navigation shows focus rings on all interactive elements
- Animations respect prefers-reduced-motion
- Every page has unique
<title>and<meta description> -
/sitemap.xmland/robots.txtserve valid content - OG tags render in social media preview tools
- JSON-LD validates in Google Rich Results Test
- No "Bolt.new" references in application code
-
pnpm lintandpnpm buildpass clean -
dotnet buildanddotnet testpass - All docs accurate to current implementation