| # Digi-Biz Next.js Implementation Plan |
|
|
| **Date:** March 18, 2026 |
| **Based on:** User Requirements (Answers to 10 Questions) |
| **Status:** Ready to Implement |
|
|
| --- |
|
|
| ## π― **USER REQUIREMENTS SUMMARY** |
|
|
| | # | Feature | Choice | Implementation | |
| |---|---------|--------|----------------| |
| | 1 | User Flow | **Option C** | Hybrid (Upload β Auto-redirect to Profile) | |
| | 2 | Processing | **Option A** | Progress bar with agent status | |
| | 3 | Profile Design | **Option A** | Business website + More details | |
| | 4 | Edit Interface | **Option B** | Separate edit page with forms | |
| | 5 | Data Storage | **Demo Mode** | No DB, Export functionality | |
| | 6 | Image Storage | **Option A** | Local file system | |
| | 7 | Service Details | **Option B** | Tabs (Overview | Itinerary | Info | FAQ) | |
| | 8 | Multiple Profiles | **Option B** | Dashboard to select profiles | |
| | 9 | API Endpoints | **Full CRUD** | All REST endpoints | |
| | 10 | Design System | **A + B** | Tailwind CSS + shadcn/ui | |
|
|
| --- |
|
|
| ## ποΈ **ARCHITECTURE OVERVIEW** |
|
|
| ### **User Flow:** |
| ``` |
| βββββββββββββββββββ |
| β Landing Page β |
| β (Upload ZIP) β |
| ββββββββββ¬βββββββββ |
| β |
| β Upload Complete |
| βββββββββββββββββββ |
| β Processing β |
| β (Real-time β |
| β Progress) β |
| ββββββββββ¬βββββββββ |
| β |
| β Processing Complete |
| βββββββββββββββββββ |
| β Profile β |
| β Dashboard β |
| β (All Profiles) β |
| ββββββββββ¬βββββββββ |
| β |
| β Select Profile |
| βββββββββββββββββββ |
| β Profile View β |
| β (Landing Page) β |
| ββββββββββ¬βββββββββ |
| β |
| β Click Edit |
| βββββββββββββββββββ |
| β Edit Page β |
| β (Forms) β |
| βββββββββββββββββββ |
| ``` |
|
|
| --- |
|
|
| ## π **FILE STRUCTURE** |
|
|
| ``` |
| digi-biz/ |
| βββ backend/ |
| β βββ api/ |
| β β βββ main.py # FastAPI server |
| β β βββ routes/ |
| β β β βββ upload.py # POST /api/upload |
| β β β βββ status.py # GET /api/status/{job_id} |
| β β β βββ profile.py # GET/PUT/DELETE /api/profile/{job_id} |
| β β β βββ export.py # POST /api/profile/{job_id}/export |
| β β βββ middleware/ |
| β β βββ cors.py |
| β βββ agents/ # Existing agents (unchanged) |
| β βββ storage/ |
| β βββ profiles/ # Store profiles as JSON files |
| β |
| βββ frontend/ |
| β βββ src/ |
| β β βββ app/ |
| β β β βββ page.tsx # Landing page (upload) |
| β β β βββ processing/ |
| β β β β βββ [job_id]/ |
| β β β β βββ page.tsx # Processing page |
| β β β βββ profiles/ |
| β β β β βββ page.tsx # Profile dashboard |
| β β β β βββ [job_id]/ |
| β β β β βββ page.tsx # Profile view (landing page) |
| β β β β βββ edit/ |
| β β β β βββ page.tsx # Edit page |
| β β β βββ layout.tsx |
| β β β βββ globals.css |
| β β βββ components/ |
| β β β βββ ui/ # shadcn/ui components |
| β β β β βββ button.tsx |
| β β β β βββ card.tsx |
| β β β β βββ progress.tsx |
| β β β β βββ tabs.tsx |
| β β β β βββ ... |
| β β β βββ UploadZone.tsx |
| β β β βββ ProcessingProgress.tsx |
| β β β βββ ProfileDashboard.tsx |
| β β β βββ BusinessProfile.tsx |
| β β β βββ ServiceCard.tsx |
| β β β βββ ServiceDetails.tsx |
| β β β βββ EditForms.tsx |
| β β β βββ ImageGallery.tsx |
| β β βββ lib/ |
| β β β βββ api.ts # API client |
| β β β βββ utils.ts |
| β β β βββ types.ts |
| β β βββ data/ |
| β β βββ mockData.json |
| β βββ package.json |
| β βββ tailwind.config.ts |
| β |
| βββ api.py # Update existing FastAPI |
| ``` |
|
|
| --- |
|
|
| ## π§ **BACKEND CHANGES** |
|
|
| ### **1. Update api.py - Add All Endpoints** |
|
|
| **File:** `backend/api/main.py` |
|
|
| ```python |
| from fastapi import FastAPI, UploadFile, File, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
| from fastapi.responses import JSONResponse |
| import os |
| import json |
| from pathlib import Path |
| from datetime import datetime |
| import uuid |
| |
| app = FastAPI(title="Digi-Biz API") |
| |
| # CORS for Next.js |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["http://localhost:3000"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
| |
| # Storage paths |
| PROFILES_DIR = Path("./storage/profiles") |
| PROFILES_DIR.mkdir(parents=True, exist_ok=True) |
| |
| # In-memory job status (replace with DB in production) |
| jobs = {} |
| |
| @app.post("/api/upload") |
| async def upload_zip(file: UploadFile = File(...)): |
| """Upload ZIP and start processing""" |
| job_id = str(uuid.uuid4()) |
| |
| # Save file |
| upload_path = PROFILES_DIR / f"{job_id}_{file.filename}" |
| with open(upload_path, "wb") as f: |
| content = await file.read() |
| f.write(content) |
| |
| # Initialize job status |
| jobs[job_id] = { |
| "job_id": job_id, |
| "status": "processing", |
| "progress": 0.0, |
| "current_phase": "upload", |
| "created_at": datetime.now().isoformat(), |
| "profile_path": None |
| } |
| |
| # Start background processing |
| import asyncio |
| asyncio.create_task(process_job(job_id, str(upload_path))) |
| |
| return {"job_id": job_id, "status": "processing"} |
| |
| @app.get("/api/status/{job_id}") |
| async def get_status(job_id: str): |
| """Get processing status""" |
| job = jobs.get(job_id) |
| if not job: |
| raise HTTPException(404, "Job not found") |
| |
| return job |
| |
| @app.get("/api/profiles") |
| async def list_profiles(): |
| """List all profiles""" |
| profiles = [] |
| for profile_file in PROFILES_DIR.glob("*.json"): |
| if profile_file.name.startswith("profile_"): |
| with open(profile_file) as f: |
| profile = json.load(f) |
| profiles.append({ |
| "job_id": profile.get("job_id"), |
| "name": profile.get("business_info", {}).get("name"), |
| "created_at": profile.get("created_at"), |
| "service_count": len(profile.get("services", [])) |
| }) |
| return {"profiles": profiles} |
| |
| @app.get("/api/profile/{job_id}") |
| async def get_profile(job_id: str): |
| """Get complete profile""" |
| profile_path = PROFILES_DIR / f"profile_{job_id}.json" |
| |
| if not profile_path.exists(): |
| raise HTTPException(404, "Profile not found") |
| |
| with open(profile_path) as f: |
| profile = json.load(f) |
| |
| return profile |
| |
| @app.put("/api/profile/{job_id}") |
| async def update_profile(job_id: str, profile: dict): |
| """Update profile (edit)""" |
| profile_path = PROFILES_DIR / f"profile_{job_id}.json" |
| |
| if not profile_path.exists(): |
| raise HTTPException(404, "Profile not found") |
| |
| # Add updated timestamp |
| profile["updated_at"] = datetime.now().isoformat() |
| |
| # Save |
| with open(profile_path, "w") as f: |
| json.dump(profile, f, indent=2) |
| |
| return {"success": True, "message": "Profile updated"} |
| |
| @app.delete("/api/profile/{job_id}") |
| async def delete_profile(job_id: str): |
| """Delete profile""" |
| profile_path = PROFILES_DIR / f"profile_{job_id}.json" |
| |
| if not profile_path.exists(): |
| raise HTTPException(404, "Profile not found") |
| |
| profile_path.unlink() |
| |
| return {"success": True, "message": "Profile deleted"} |
| |
| @app.post("/api/profile/{job_id}/export") |
| async def export_profile(job_id: str): |
| """Export profile as JSON""" |
| profile_path = PROFILES_DIR / f"profile_{job_id}.json" |
| |
| if not profile_path.exists(): |
| raise HTTPException(404, "Profile not found") |
| |
| with open(profile_path) as f: |
| profile = json.load(f) |
| |
| return JSONResponse( |
| content=profile, |
| headers={"Content-Disposition": f"attachment; filename=profile_{job_id}.json"} |
| ) |
| |
| # Background processing function |
| async def process_job(job_id: str, file_path: str): |
| """Process job in background with progress updates""" |
| from backend.agents.file_discovery import FileDiscoveryAgent, FileDiscoveryInput |
| from backend.agents.document_parsing import DocumentParsingAgent, DocumentParsingInput |
| from backend.agents.table_extraction import TableExtractionAgent, TableExtractionInput |
| from backend.agents.media_extraction import MediaExtractionAgent, MediaExtractionInput |
| from backend.agents.indexing import IndexingAgent, IndexingInput |
| from backend.agents.schema_mapping_simple import SchemaMappingAgent |
| from backend.models.schemas import SchemaMappingInput |
| from backend.utils.storage_manager import StorageManager |
| |
| try: |
| # Update status |
| jobs[job_id]["current_phase"] = "file_discovery" |
| jobs[job_id]["progress"] = 10.0 |
| |
| # Step 1: File Discovery |
| storage_manager = StorageManager(storage_base=str(PROFILES_DIR)) |
| discovery_agent = FileDiscoveryAgent(storage_manager=storage_manager) |
| discovery_output = discovery_agent.discover( |
| FileDiscoveryInput(zip_file_path=file_path, job_id=job_id) |
| ) |
| |
| # Step 2: Document Parsing (30%) |
| jobs[job_id]["current_phase"] = "document_parsing" |
| jobs[job_id]["progress"] = 30.0 |
| parsing_agent = DocumentParsingAgent(enable_ocr=False) |
| parsing_output = parsing_agent.parse( |
| DocumentParsingInput(documents=discovery_output.documents, job_id=job_id) |
| ) |
| |
| # Step 3: Table Extraction (50%) |
| jobs[job_id]["current_phase"] = "table_extraction" |
| jobs[job_id]["progress"] = 50.0 |
| table_agent = TableExtractionAgent() |
| tables_output = table_agent.extract( |
| TableExtractionInput(parsed_documents=parsing_output.parsed_documents, job_id=job_id) |
| ) |
| |
| # Step 4: Media Extraction (70%) |
| jobs[job_id]["current_phase"] = "media_extraction" |
| jobs[job_id]["progress"] = 70.0 |
| media_agent = MediaExtractionAgent(enable_deduplication=False) |
| media_output = media_agent.extract_all( |
| MediaExtractionInput( |
| parsed_documents=parsing_output.parsed_documents, |
| standalone_files=[img.file_path for img in discovery_output.images], |
| job_id=job_id |
| ) |
| ) |
| |
| # Step 5: Indexing (85%) |
| jobs[job_id]["current_phase"] = "indexing" |
| jobs[job_id]["progress"] = 85.0 |
| indexing_agent = IndexingAgent() |
| page_index = indexing_agent.build_index( |
| IndexingInput( |
| parsed_documents=parsing_output.parsed_documents, |
| tables=tables_output.tables, |
| images=media_output.media.images if media_output.success else [], |
| job_id=job_id |
| ) |
| ) |
| |
| # Step 6: Schema Mapping (95%) |
| jobs[job_id]["current_phase"] = "schema_mapping" |
| jobs[job_id]["progress"] = 95.0 |
| schema_agent = SchemaMappingAgent() |
| mapping_output = schema_agent.map_to_schema( |
| SchemaMappingInput(page_index=page_index, job_id=job_id) |
| ) |
| |
| if not mapping_output.success: |
| raise Exception(f"Schema mapping failed: {mapping_output.errors}") |
| |
| # Add metadata |
| profile = mapping_output.profile.model_dump(mode='json') |
| profile["job_id"] = job_id |
| profile["created_at"] = datetime.now().isoformat() |
| |
| # Save profile |
| profile_path = PROFILES_DIR / f"profile_{job_id}.json" |
| with open(profile_path, "w") as f: |
| json.dump(profile, f, indent=2) |
| |
| jobs[job_id]["profile_path"] = str(profile_path) |
| jobs[job_id]["status"] = "completed" |
| jobs[job_id]["progress"] = 100.0 |
| jobs[job_id]["current_phase"] = "done" |
| |
| print(f"β
Job {job_id} completed successfully") |
| |
| except Exception as e: |
| jobs[job_id]["status"] = "failed" |
| jobs[job_id]["error"] = str(e) |
| print(f"β Job {job_id} failed: {e}") |
| ``` |
|
|
| --- |
|
|
| ## π¨ **FRONTEND IMPLEMENTATION** |
|
|
| ### **Page 1: Landing Page (Upload)** |
|
|
| **File:** `frontend/src/app/page.tsx` |
|
|
| **Features:** |
| - Hero section with Digi-Biz branding |
| - Drag-drop upload zone |
| - Recent profiles list |
| - Clean, minimal design |
|
|
| --- |
|
|
| ### **Page 2: Processing Page** |
|
|
| **File:** `frontend/src/app/processing/[job_id]/page.tsx` |
|
|
| **Features:** |
| - Progress bar (0-100%) |
| - Current phase display: |
| - π File Discovery (10%) |
| - π Document Parsing (30%) |
| - π Table Extraction (50%) |
| - πΌοΈ Media Extraction (70%) |
| - π Indexing (85%) |
| - π€ Schema Mapping (95%) |
| - β
Complete (100%) |
| - Auto-redirect to profile on completion |
| - Cannot navigate away (modal-like) |
|
|
| --- |
|
|
| ### **Page 3: Profile Dashboard** |
|
|
| **File:** `frontend/src/app/profiles/page.tsx` |
|
|
| **Features:** |
| - Grid of all profiles |
| - Each card shows: |
| - Business name |
| - Service count |
| - Created date |
| - Preview image |
| - "Create New" button |
| - Search/filter |
|
|
| --- |
|
|
| ### **Page 4: Profile View (Landing Page)** |
|
|
| **File:** `frontend/src/app/profiles/[job_id]/page.tsx` |
|
|
| **Features:** |
| - **Hero Section:** |
| - Business name |
| - Category badge |
| - Description |
| - Contact info (phone, email, website) |
| - Location |
| - Hero image (if available) |
|
|
| - **Services Grid:** |
| - Service cards with image, name, price, duration |
| - Click to view details |
|
|
| - **Service Details Modal/Page:** |
| - **Tabs:** |
| - Overview (description, category) |
| - Itinerary (day-by-day) |
| - Info (inclusions, exclusions, what to carry) |
| - FAQ (questions & answers) |
| - Policy (cancellation, payment) |
|
|
| - **Image Gallery:** |
| - Grid of all images |
| - Lightbox view |
|
|
| - **Actions:** |
| - Edit Profile button |
| - Export JSON button |
| - Delete Profile button |
|
|
| --- |
|
|
| ### **Page 5: Edit Page** |
|
|
| **File:** `frontend/src/app/profiles/[job_id]/edit/page.tsx` |
|
|
| **Features:** |
| - **Business Info Form:** |
| - Name, description, category |
| - Contact (phone, email, website) |
| - Location |
| - Hero image upload |
|
|
| - **Services Editor:** |
| - List of all services |
| - Add/Remove services |
| - Edit each service: |
| - Name, description, category |
| - Pricing (base price, currency, price type) |
| - Details (duration, difficulty, best time) |
| - Itinerary (add/remove days) |
| - Inclusions/Exclusions (tag input) |
| - FAQs (Q&A pairs) |
| - Images upload |
|
|
| - **Actions:** |
| - Save button |
| - Cancel button (back to profile) |
| - Auto-save draft (optional) |
|
|
| --- |
|
|
| ## π― **COMPONENTS NEEDED** |
|
|
| ### **shadcn/ui Components:** |
| ```bash |
| npx shadcn-ui@latest add button |
| npx shadcn-ui@latest add card |
| npx shadcn-ui@latest add progress |
| npx shadcn-ui@latest add tabs |
| npx shadcn-ui@latest add dialog |
| npx shadcn-ui@latest add form |
| npx shadcn-ui@latest add input |
| npx shadcn-ui@latest add textarea |
| npx shadcn-ui@latest add label |
| npx shadcn-ui@latest add badge |
| npx shadcn-ui@latest add avatar |
| npx shadcn-ui@latest add dropdown-menu |
| npx shadcn-ui@latest add toast |
| ``` |
|
|
| ### **Custom Components:** |
| 1. `UploadZone.tsx` - Drag-drop upload |
| 2. `ProcessingProgress.tsx` - Progress bar with phases |
| 3. `ProfileDashboard.tsx` - Profile grid |
| 4. `BusinessProfile.tsx` - Profile display |
| 5. `ServiceCard.tsx` - Service card |
| 6. `ServiceDetails.tsx` - Service details with tabs |
| 7. `EditForms.tsx` - Edit forms |
| 8. `ImageGallery.tsx` - Image gallery |
| 9. `ItineraryBuilder.tsx` - Itinerary editor |
| 10. `TagInput.tsx` - For inclusions/exclusions |
|
|
| --- |
|
|
| ## π **IMPLEMENTATION CHECKLIST** |
|
|
| ### **Phase 1: Backend API (8-10 hours)** |
| - [ ] Update api.py with all endpoints |
| - [ ] Add profile storage (JSON files) |
| - [ ] Add background processing |
| - [ ] Add progress tracking |
| - [ ] Test all endpoints with Postman |
| - [ ] Add error handling |
| - [ ] Add CORS for localhost:3000 |
|
|
| ### **Phase 2: Frontend Setup (4-6 hours)** |
| - [ ] Install shadcn/ui components |
| - [ ] Setup Tailwind config |
| - [ ] Create API client (lib/api.ts) |
| - [ ] Create types (lib/types.ts) |
| - [ ] Setup routing |
|
|
| ### **Phase 3: Core Pages (10-12 hours)** |
| - [ ] Landing page (upload) |
| - [ ] Processing page |
| - [ ] Profile dashboard |
| - [ ] Profile view page |
| - [ ] Edit page |
| - [ ] All components |
|
|
| ### **Phase 4: Integration (6-8 hours)** |
| - [ ] Connect upload to API |
| - [ ] Connect processing status polling |
| - [ ] Connect profile loading |
| - [ ] Connect edit forms |
| - [ ] Connect export |
| - [ ] Connect delete |
| - [ ] Error handling |
| - [ ] Loading states |
|
|
| ### **Phase 5: Polish (4-6 hours)** |
| - [ ] Responsive design |
| - [ ] Animations |
| - [ ] Toast notifications |
| - [ ] Better error messages |
| - [ ] Performance optimization |
| - [ ] Test with real data |
|
|
| **Total: 32-42 hours** |
|
|
| --- |
|
|
| ## π **NEXT STEPS** |
|
|
| 1. **Confirm this plan** matches your vision |
| 2. **I'll start implementing** Phase 1 (Backend API) |
| 3. **Test backend** with Postman |
| 4. **Build frontend** incrementally |
| 5. **Test together** |
|
|
| --- |
|
|
| ## β **FINAL QUESTIONS BEFORE I START:** |
|
|
| 1. **Should I proceed with this exact plan?** |
| 2. **Any specific design preferences?** (colors, layout, etc.) |
| 3. **Should I keep the existing mockData.json** as fallback? |
| 4. **Any specific trek companies** to reference for design? |
|
|
| --- |
|
|
| **Ready to start building! Just say "GO" and I'll begin with Phase 1!** π |
|
|