Production-Ready AI-Powered Etsy Listing Generator
A comprehensive full-stack application that transforms raw product descriptions into optimized Etsy listings using advanced AI processing, field-by-field validation, and robust error handling.
- Smart Title Generation: SEO-optimized titles with length validation (35-85 chars)
- Intelligent Tag Creation: 5+ SEO tags + 1 audience tag with tri-layer structure
- Rich Descriptions: 7-section format with CTA blocks and keyword integration
- Handmade-Flex Logic: Toggle between "handmade" and "artisan" terminology
- Field-by-Field Processing: Individual retry logic and validation per field
- Comprehensive Validation: 4-layer validation system (input → prompt → output → final)
- Quality Scoring: Automated quality assessment with metrics tracking
- Robust Error Handling: Graceful fallbacks and detailed error reporting
- React 18 SPA: Modern, responsive user interface
- Real-time Validation: Live badge status updates (green/yellow/red)
- Copy-to-Clipboard: One-click content copying with validation checks
- Collapsible Panels: Organized content display with status indicators
- Firestore Logging: Complete audit trail with run IDs and timestamps
- Performance Metrics: Token usage, response times, and success rates
- Validation Tracking: Detailed warning/error categorization
- E2E Test Coverage: Comprehensive Cypress test suite
- Node.js 20+ (LTS recommended)
- Firebase CLI (
npm install -g firebase-tools) - OpenAI API Key (GPT-4 access required)
# Clone repository
git clone https://github.com/yourusername/etsy-ai-hacker.git
cd etsy-ai-hacker
# Install dependencies
npm install
cd functions && npm install
cd ../frontend && npm install
cd ..# Create environment file
echo "OPENAI_API_KEY=your-openai-key-here" > functions/.env
# Configure Firebase project
firebase use --add # Select your Firebase project# Start all services (Backend + Frontend + Database)
npm run dev:full
# Or start services individually:
npm run emulators # Firebase Functions + Firestore
cd frontend && npm run dev # React development server
# Run tests
npm test # Jest unit tests (38 tests)
npm run test:e2e # Cypress E2E tests (4 tests)# Test the core API endpoint
curl -X POST http://localhost:5001/etsy-ai-hacker/us-central1/api_generateListingFromDump \
-H "Content-Type: application/json" \
-d '{"text":"handmade wooden jewelry box with velvet interior"}'POST api_spendCredits
Body: { "amount": <number>, "reason": "optioneel", "requestId": "optioneel idempotency key" }
Header: Authorization: Bearer <ID_TOKEN>
Voorbeeld PowerShell:
$body = @{ amount = 250; reason = "test"; requestId = [guid]::NewGuid().ToString() } | ConvertTo-Json
Invoke-RestMethod -Method Post \
-Uri "http://127.0.0.1:5001/<project>/us-central1/api_spendCredits" \
-Headers @{ Authorization = "Bearer $token" } \
-ContentType "application/json" -Body $bodyAntwoord: { uid, credits } (nieuw saldo). Bij te weinig saldo: HTTP 422.
# 1. Start emulators (functions + auth + firestore)
cd functions
npm run emul:funcYou should see Auth on port 9099 and Functions on 5001.
# 2. Obtain an ID token from the Auth emulator
$token = $(npm run -s dev:token) # prints JWT
# 3. Make a request (PowerShell example)
$body = @{ text = "Test dump"; allow_handmade = $false; gift_mode = $false } | ConvertTo-Json
Invoke-RestMethod -Method Post `
-Uri "http://127.0.0.1:5001/<project-id>/us-central1/api_generateListingFromDump" `
-Headers @{ Authorization = "Bearer $token" } `
-ContentType "application/json" -Body $bodyThe request should return either 200 OK (mock path) or a validation error (422) but never 401 or CORS issues.
Run the full payment → wallet flow with zero UI in three shells:
# Terminal A – Functions + Firestore + Auth on localhost
npm run emul:func # (= firebase emulators:start --only functions,firestore,auth)
# Terminal B – Stripe CLI listener
stripe listen --forward-to http://127.0.0.1:5001/<project-id>/us-central1/stripeWebhook
# Terminal C – Execute Cypress-like headless test (requires TEST_ALLOW_CLI_CHECKOUT=1 in functions/.env)
npm run test:e2e # creates checkout.session, grants credits, debits 250 ⇒ saldo 750For quick rules validation only:
firebase emulators:exec --only firestore "npm run test:rules" # runs Jest suite against 127.0.0.1:8089- Configureer Stripe secrets lokaal (emulators):
Plaats dit in
{ "stripe": { "secret": "<STRIPE_SECRET_KEY>", "webhook_secret": "<STRIPE_WEBHOOK_SECRET>" }, "app": { "base_url": "http://localhost:5173" } }functions/.runtimeconfig.jsonof viafirebase functions:config:set. - Start de emulators:
cd functions npm run emul:func - Maak een Checkout-sessie (client stuurt alléén
priceId):curl -X POST http://127.0.0.1:5001/<project-id>/us-central1/api_createCheckoutSession \ -H "Content-Type: application/json" \ -d '{"priceId":"price_basic_monthly"}'
- Rond de testbetaling af; de webhook crediteert nu
plan.creditsinusers/<uid>.
- Zet in
functions/.env:DAILY_CREDITS=500 # of kleiner voor tests USE_FIRESTORE_CREDITS=1 - Start de emulators:
cd functions npm run emul:func
- Haal een JWT-token op:
$token = $(npm run -s dev:token)
- Doe een call; het credits-saldo wordt nu transactioneel in Firestore beheerd:
$body = @{ text = "Houten sieradendoos" } | ConvertTo-Json Invoke-RestMethod -Method Post ` -Uri "http://127.0.0.1:5001/<project-id>/us-central1/api_generateListingFromDump" ` -Headers @{ Authorization = "Bearer $token" } ` -ContentType "application/json" -Body $body
🤔 Bij overschrijding van het daglimiet (DAILY_CREDITS) retourneert de API 429 Daily credits exhausted.
functions/
├── prompts/ # Versioned AI prompts (v3.0.2-v3.0.3)
│ ├── title_prompt.txt
│ ├── tag_prompt.txt
│ └── description_prompt.txt
├── utils/
│ ├── validators/ # 4-layer validation system
│ ├── generators/ # Field-specific AI generation
│ └── logging/ # Firestore integration
└── __tests__/ # 38 Jest unit tests
frontend/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── StatusBadge.tsx
│ │ └── CollapsiblePanels.tsx
│ └── App.tsx # Main application logic
├── cypress/ # E2E test suite
└── public/ # Static assets
- Structured Logging: Run IDs, timestamps, validation metrics
- Performance Tracking: Token usage, response times
- Error Monitoring: Detailed failure analysis
- 38/38 Jest Tests Passing (100% success rate)
- 4/4 E2E Tests Passing (Full user journey validation)
- Zero High-Severity Errors (Production-ready validation)
- API Response Time: 9-11 seconds (AI processing)
- Validation Speed: <5ms per validator
- Frontend Load Time: <2 seconds
- Test Execution: <30 seconds (full suite)
- Prompt Versioning: Semantic versioning with change tracking
- Validator v4: Soft-fail mechanism with detailed reporting
- Security: Production-ready Firestore rules
- Error Handling: Comprehensive fallback strategies
# functions/.env
OPENAI_API_KEY=your-key-here
# Optional: Custom model configuration
OPENAI_MODEL=gpt-4
MAX_TOKENS=2000{
"functions": {
"runtime": "nodejs20",
"source": "functions"
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"emulators": {
"functions": {"port": 5001},
"firestore": {"port": 9081},
"ui": {"enabled": true}
}
}- Het daglimiet per gebruiker wordt bepaald door de omgevingsvariabele
DAILY_CREDITS(fallbackDEFAULT_USER_CREDITS, standaard 500). - De limiet wordt runtime uit de omgeving gelezen (geen hard-coded constant meer).
- In tests wordt het in-memory creditsgeheugen per test leeggemaakt met
_resetTestState().
_resetTestState()bevindt zich infunctions/utils/credits.js.- Wordt in
functions/__tests__/credits.test.jsaangeroepen inbeforeEach()zodat elke spec met een schone bucket start.
cd functions
npm test
# Expected: 38 tests passingcd frontend
npm run test:e2e
# Tests: API integration, UI validation, error handling- Backend API: Test core generation endpoint
- Frontend UI: Verify badge colors and copy functionality
- Database: Check Firestore logging and metrics
- Validation: Test edge cases and error scenarios
- Development Guide: Detailed setup and development workflow
- Project Decisions Log: Complete audit trail
- API Documentation: Endpoint specifications and examples
- Prompt Documentation: AI prompt versions and changes
# Deploy to Firebase staging
firebase deploy --project your-staging-project
# Deploy frontend to Netlify/Vercel
cd frontend && npm run build# Full production deployment
firebase deploy --project your-production-project
# Monitor deployment
firebase functions:log --project your-production-project- Fork the repository
- Create feature branch:
git checkout -b feature/amazing-feature - Run tests:
npm test && npm run test:e2e - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open Pull Request
- Follow existing code style and patterns
- Add tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting PR
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenAI GPT-4: Core AI processing engine
- Firebase: Backend infrastructure and hosting
- React: Frontend framework
- Cypress: E2E testing framework
- Tailwind CSS: UI styling system
Status: Production Ready | Version: 3.0.4 | Last Updated: August 2025
- Emulator UI: http://localhost:4001
- Firestore logs: Navigate to runs > [runId] > logs
- Token tracking: Per-field usage and retry metrics
firebase deploy --only functions
firebase deploy --only firestore:indexesSee README-DEV.md for detailed development setup, testing procedures, and emulator configuration.
- Deliverable 1: Router-refactor & Prompt Upgrade (22-07-2025)
- Deliverable 2: Prompt-upgrade v2.7 (23-07-2025) - Emulator validated
- Deliverable 3: Classifier-patch v3.3 (In Progress)
- Runtime: Node.js 20, Firebase Functions
- AI: OpenAI GPT-4o (v5 SDK)
- Database: Firestore with compound indexes
- Testing: Jest with Firebase emulator integration
- CI/CD: GitHub Actions (planned)
Zie docs/fail_policy_table_v1.md voor de actuele fail-policy-matrix (v1.0).
Waarom: uniforme hard/soft-beslissingen per fouttype.
Waar toegepast: functions/utils/validators/failPolicy.js + flow‐projectie in functions/generateFromDumpCore.js.
Per veldlog (title|tags|description) worden toegevoegd:
• fail_severity: 'hard' | 'soft' | null
• policy_version: 'v1.0'
{ "overall_status": "ok" | "partial" | "error", "field_status": { "title": "ok" | "partial" | "error", "description": "ok" | "partial" | "error", "tags": "ok" | "partial" | "error" }, "fail_reasons": { "title": ["..."], "description": ["..."], "tags": ["..."] }, "policy_version": "v1.0" }