AI Acceleration Impact
Project Duration (with AI)
Without AI
13d
With AI
9d
Saved
4d
Engineering Effort
Without AI
365h
With AI
264h
Saved
101h
Shared Plan · Read-only view. Sign in to move this plan to your workspace.
ResumeWeb is a web application that allows users to convert their resume PDFs into live portfolio pages without requiring sign-up. The core problem it addresses is the need for a quick and easy way to create an online portfolio while ensuring privacy by not displaying personal contact information. The application faces technical challenges in parsing PDF files accurately and managing asynchronous processing to provide real-time feedback to users. It will utilize Next.js, TypeScript, and a cloud database for storage and processing.
Project Duration (with AI)
Without AI
13d
With AI
9d
Saved
4d
Engineering Effort
Without AI
365h
With AI
264h
Saved
101h
4
days (longest dependency chain)
Project duration: 9d · 1 sprint estimated
68
tasks
38 stories · 4 phases
Stories broken into tasks for execution
Foundation Setup
Establish the development environment, CI/CD pipeline, and initial repository setup.
Core Development
Develop core functionalities such as PDF upload, parsing, and portfolio generation.
Advanced Features
Implement advanced features like SEO controls and private edit links.
Non-Functional Requirements
Ensure usability, security, performance, and reliability of the application.
Establish the development environment, CI/CD pipeline, and initial repository setup.
Develop core functionalities such as PDF upload, parsing, and portfolio generation.
Implement advanced features like SEO controls and private edit links.
Ensure usability, security, performance, and reliability of the application.
ResumeWeb addresses the friction and privacy risks associated with turning a traditional resume PDF into a modern, shareable online portfolio. Many job seekers, students, and professionals lack the technical skills or time to build personal websites, and existing solutions often require account creation, expose personal contact information, or are slow and cumbersome. The problem is significant for anyone needing a quick, professional online presence for networking, job applications, or sharing credentials, especially in a market where digital portfolios are increasingly expected. Current workarounds include using generic website builders (which require setup and maintenance), LinkedIn (which exposes contact info and lacks customization), or manual conversion to web pages (time-consuming and technical).
ResumeWeb offers a frictionless, no-signup web app that instantly converts a resume PDF into a polished, mobile-friendly portfolio page. The process is asynchronous for speed and reliability, and privacy is prioritized by stripping contact details from public pages. Unique edit and public URLs allow users to manage their portfolio without accounts. The approach is unique in its combination of instant onboarding, privacy-by-default, and AI-driven parsing, with a focus on mass accessibility and minimal user friction. Compared to existing solutions, ResumeWeb eliminates account barriers, manual data entry, and privacy concerns.
ResumeWeb provides instant, private, and professional online portfolios from any resume PDF, with zero signup or technical barriers. Key benefits include speed (live in under a minute), privacy (no public PII), ease of use (no accounts, no coding), and control (edit, hide, or delete at any time). The unique selling proposition is the combination of instant onboarding, privacy-by-design, and AI-powered resume parsing for structured, visually appealing portfolio pages.
Primary users are job seekers, students, freelancers, and professionals globally who need a quick, private way to showcase their credentials online. Demographics include recent graduates, career switchers, and those without personal websites. The market size is large, as nearly every professional maintains a resume and may benefit from a digital portfolio. Segments include university students, early-career professionals, gig workers, and those in regions where personal branding online is growing rapidly.
The current iteration is free with no monetization. Future revenue models could include premium features (custom domains, analytics, multiple portfolios), B2B partnerships (university/career services), or a freemium SaaS model. Cost structure is low due to serverless architecture and minimal support requirements. No explicit pricing or willingness-to-pay data is present in the provided materials.
low
mature
Research confidence: high
Research confidence: high
Threat Level: medium
DockPage uses AI to convert resumes or LinkedIn profiles into professional personal websites, extracting structured data and generating a polished site instantly.
Strengths:
Weaknesses:
Sources:
RESFOL.IO converts resumes into interactive websites, focusing on showcasing real projects and case studies, with AI-powered content suggestions and a custom AI Champion.
Strengths:
Weaknesses:
Sources:
ResumeFolio uses AI to extract projects, skills, and links from resumes, offering multiple themes and instant portfolio URLs, with a free-to-use model.
Strengths:
Weaknesses:
Sources:
PortlifyAi provides AI-powered portfolio building, smart resume parsing, career trajectory analysis, and portfolio analytics, with both free and premium plans.
Strengths:
Weaknesses:
Sources:
LivCV offers AI-powered writing assistance and interactive web profiles, enabling users to create live, multimedia-rich resumes and web-based profiles.
Strengths:
Weaknesses:
Sources:
Portfoliogy uses AI to rapidly transform resume PDFs into visually appealing, deployed portfolio websites.
Strengths:
Weaknesses:
Sources:
Artfolio enables users to turn resumes into portfolio websites, featuring AI-powered resume building and ATS-friendly designs.
Strengths:
Weaknesses:
Sources:
ResumeWeb should emphasize its frictionless, privacy-first approach—offering a truly free, no-signup, instant portfolio creation experience with robust privacy controls. Highlighting user control (private edit link, visibility/SEO settings) and a demo-ready product within 10 days can further differentiate from slower, more complex, or less privacy-conscious competitors.
feature-1Requirements:
Technical requirements:
feature-2Requirements:
Technical requirements:
feature-3Requirements:
Technical requirements:
feature-4Requirements:
Technical requirements:
feature-5Requirements:
Technical requirements:
infra-1Requirements:
nfr-1Requirements:
nfr-2Requirements:
nfr-3Requirements:
nfr-4Requirements:
nfr-5Requirements:
Date: Wednesday, July 15, 2026 Research as of: Wednesday, July 15, 2026 (2026-07-15) Version: 1.0.0 Technology research confidence: medium
Technology research sources:
ResumeWeb is a privacy-centric, no-signup SaaS web application that enables users to upload a resume PDF and receive a live, mobile-friendly portfolio page at a unique URL, with a private edit link for future modifications. The system is built for rapid demo delivery and minimal operational overhead, optimized for a solo developer deployment, and leverages modern serverless paradigms for both scalability and maintainability.
Key architectural decisions:
flowchart TD
A["User Browser"]
B["Next.js App Router (UI & SSR)"]
C["API Route Handlers (Next.js 16.2.7)"]
D["Async PDF Parser (Serverless Function)"]
E["Supabase Postgres 18.4"]
F["Vercel Blob Storage"]
A -- Upload Resume PDF --> B
B -- POST /api/upload --> C
C -- Store PDF --> F
C -- Create Parse Job & Status --> E
C -- Trigger Async Parse --> D
D -- Fetch PDF from F --> D
D -- Parse & Extract Data --> D
D -- Store Structured Data, Update Status, Generate Slug/Token --> E
A -- Poll /api/status/:jobId --> C
C -- Query Status --> E
A -- Receives Edit Link & Public URL --> B
A -- Access /p/:slug (public) or /edit/:token (private) --> B
B -- Fetch Portfolio Data --> C
C -- Query Portfolio --> E
A -- Optional Photo Upload --> C
C -- Store Photo --> F| Category | Technology (version) | Rationale |
|---|---|---|
| Frontend | Next.js 16.2.7 (docs), TypeScript | Official requirement; supports UI, SSR, API, and serverless on Vercel. Maintains a single codebase and maximizes productivity. |
| Styling/UI | Tailwind CSS (latest stable 2026) | Rapid, responsive, mobile-first UI; integrates seamlessly with Next.js and shadcn/ui if needed. |
| Backend | Next.js 16.2.7 API Route Handlers | Monolithic serverless logic for all APIs; avoids microservices per requirements. |
| Database | Supabase Postgres 18.4 (docs) | Managed Postgres, low ops, supports serverless, matches feature and privacy needs. |
| File Storage | Vercel Blob Storage | First-party, low-latency, zero-maintenance storage for PDFs and photos. |
| PDF Parsing | pdf-parse (Node.js), custom LLM wrapper | Node.js-native parsing; LLM integration for resume structure extraction. |
| Auth/Security | JWT (HS256, signed with server secret) | Magic edit link as a signed, time-unlimited token; no user accounts. |
| Deployment | Vercel | Official requirement; enables monorepo, instant deploys, serverless, and global CDN for static assets and SSR. |
| CI/CD | GitHub Actions | Seamless with Vercel; triggers deploys on push, runs type checks and tests. |
| Monitoring | Vercel Analytics, Sentry (optional) | Basic error and performance monitoring; Sentry for error tracking if needed. |
Alternatives: Supabase Storage (if Vercel Blob unavailable/insufficient).
Modular Monolith (Serverless): Single Next.js App Router codebase with all UI and APIs. No microservices, no split repos. Rationale:
Solo developer, minimal ops.
Serverless deployment on Vercel.
API Route Handlers support async jobs and status polling.
Event-Driven Async Processing: PDF parsing and LLM extraction handled via async job (simulated queue or Vercel background function), with job status in DB.
Token-Based Auth: Magic edit link using JWT, no user accounts, tokens scoped to portfolio.
| Feature | Table(s) |
|---|---|
| Resume Upload & Processing | portfolios, parse_jobs |
| Public Portfolio Page Generation | portfolios |
| Private Edit Link | portfolios |
| SEO & Visibility Controls | portfolios |
| Async Processing Status | parse_jobs |
| Rate Limiting | upload_limits |
| Column | Type | Constraints |
|---|---|---|
| id | UUID | PK, DEFAULT gen_random_uuid() |
| slug | VARCHAR(32) | UNIQUE, NOT NULL |
| edit_token_jwt | TEXT | NOT NULL, unique magic edit JWT |
| pdf_blob_url | TEXT | NOT NULL |
| photo_blob_url | TEXT | NULLABLE |
| parse_status | ENUM: 'pending','processing','success','error' | DEFAULT 'pending', NOT NULL |
| parse_error_message | TEXT | NULLABLE |
| summary | TEXT | NULLABLE |
| experience_json | JSONB | NULLABLE, array of experiences |
| skills_json | JSONB | NULLABLE, array of skills |
| education_json | JSONB | NULLABLE, array of education entries |
| projects_json | JSONB | NULLABLE, array of projects |
| is_published | BOOLEAN | NOT NULL, DEFAULT FALSE |
| allow_search_indexing | BOOLEAN | NOT NULL, DEFAULT FALSE |
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
| updated_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
| deleted_at | TIMESTAMP | NULLABLE, for soft deletes |
| uploader_ip_hash | CHAR(64) | NOT NULL, SHA-256 hash of uploader IP for rate limit |
| INDEX idx_slug | slug | UNIQUE |
| INDEX idx_edit_token | edit_token_jwt | UNIQUE |
| INDEX idx_published | is_published | For quick lookup of published portfolios |
| INDEX idx_ip_hash | uploader_ip_hash | For rate limiting |
| Column | Type | Constraints |
|---|---|---|
| id | UUID | PK, DEFAULT gen_random_uuid() |
| portfolio_id | UUID | FK portfolios(id), NOT NULL |
| status | ENUM: 'pending','processing','success','error' | DEFAULT 'pending', NOT NULL |
| error_message | TEXT | NULLABLE |
| started_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
| finished_at | TIMESTAMP | NULLABLE |
| INDEX idx_portfolio_id | portfolio_id | For status polling |
| Column | Type | Constraints |
|---|---|---|
| ip_hash | CHAR(64) | PK, SHA-256 of IP |
| uploads_last_hour | INTEGER | NOT NULL, DEFAULT 0 |
| last_upload_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
erDiagram
portfolios {
UUID id PK
VARCHAR(32) slug
TEXT edit_token_jwt
TEXT pdf_blob_url
TEXT photo_blob_url
ENUM parse_status
TEXT parse_error_message
TEXT summary
JSONB experience_json
JSONB skills_json
JSONB education_json
JSONB projects_json
BOOLEAN is_published
BOOLEAN allow_search_indexing
TIMESTAMP created_at
TIMESTAMP updated_at
TIMESTAMP deleted_at
CHAR(64) uploader_ip_hash
}
parse_jobs {
UUID id PK
UUID portfolio_id FK
ENUM status
TEXT error_message
TIMESTAMP started_at
TIMESTAMP finished_at
}
upload_limits {
CHAR(64) ip_hash PK
INTEGER uploads_last_hour
TIMESTAMP last_upload_at
}
portfolios ||--o| parse_jobs: "has"/api/, not /api/v1/.| Feature | API Endpoints |
|---|---|
| Resume Upload | POST /api/upload |
| Async Processing + Status | GET /api/status/:jobId |
| Public Portfolio Page | GET /api/portfolio/:slug |
| Private Edit Link | GET /api/edit/:token, PATCH /api/edit/:token, POST /api/edit/:token/photo, DELETE /api/edit/:token |
| SEO/Visibility Controls | PATCH /api/edit/:token/visibility, PATCH /api/edit/:token/seo |
| Rate Limiting | Applied on POST /api/upload (via IP) |
multipart/form-data202 Accepted
{ jobId: string }400 Bad Request (invalid file type/size)429 Too Many Requests (rate limit)500 Internal Server Error200 OK
{ status: 'pending'|'processing'|'success'|'error', errorMessage?: string, publicUrl?: string, editUrl?: string }404 Not Found (unknown jobId)200 OK
{ slug: string, summary: string, experience: [...], skills: [...], education: [...], projects: [...], photoUrl?: string, allowSearchIndexing: boolean }404 Not Found (unpublished or deleted)X-Robots-Tag and meta tags based on allow_search_indexing.200 OK
{ slug: string, summary: string, experience: [...], skills: [...], education: [...], projects: [...], photoUrl?: string, isPublished: boolean, allowSearchIndexing: boolean }401 Unauthorized (invalid/expired token)404 Not Found (deleted){ summary?: string, experience?: [...], skills?: [...], education?: [...], projects?: [...] }200 OK { success: true }401 Unauthorized400 Bad Request (validation error)multipart/form-data200 OK { photoUrl: string }401 Unauthorized400 Bad Request (invalid file){ isPublished: boolean }200 OK { isPublished: boolean }{ allowSearchIndexing: boolean }200 OK { allowSearchIndexing: boolean }204 No Content/api/ namespace per requirements; no /api/v1/ sprawl./api/edit/:token).400, 401, 404, 429, 500).flowchart TD
A["User Browser"]
B["POST /api/upload"]
C["GET /api/status/:jobId"]
D["GET /api/portfolio/:slug"]
E["GET /api/edit/:token"]
F["PATCH /api/edit/:token"]
G["POST /api/edit/:token/photo"]
H["PATCH /api/edit/:token/visibility"]
I["PATCH /api/edit/:token/seo"]
J["DELETE /api/edit/:token"]
A --> B
A --> C
A --> D
A --> E
A --> F
A --> G
A --> H
A --> I
A --> J/api/upload), validates file, stores PDF, creates portfolio record, triggers parse job./api/status/:jobId), polls parse_jobs./p/:slug, fetches sanitized portfolio data./api/portfolio/:slug), applies privacy logic, SEO headers/meta./api/edit/:token), validates JWT, fetches full portfolio.PATCH /api/edit/:token), applies changes.POST /api/edit/:token/photo), validates and stores photo.PATCH /api/edit/:token/visibility)PATCH /api/edit/:token/seo)DELETE /api/edit/:token), soft-deletes.allow_search_indexing.sequenceDiagram
participant User
participant UploadPage
participant UploadHandler
participant BlobStorage
participant DB
participant ParseJobOrchestrator
participant AsyncPDFParser
User->>UploadPage: Select PDF, Click Upload
UploadPage->>UploadHandler: POST /api/upload (PDF)
UploadHandler->>RateLimiter: Check IP quota
alt Under limit
UploadHandler->>BlobStorage: Store PDF
UploadHandler->>DB: Create portfolios row (pending)
UploadHandler->>ParseJobOrchestrator: Create parse_jobs row, trigger parser
UploadHandler->>User: jobId
AsyncPDFParser->>BlobStorage: Fetch PDF
AsyncPDFParser->>AsyncPDFParser: Parse, extract, strip PII
AsyncPDFParser->>DB: Update portfolio (fields, is_published), parse_jobs (status)
else Over limit
UploadHandler->>User: 429 Too Many Requests
endsequenceDiagram
participant User
participant EditPage
participant EditHandler
participant DB
User->>EditPage: Visit /edit/:token
EditPage->>EditHandler: GET /api/edit/:token
EditHandler->>DB: Fetch portfolio by token
DB-->>EditHandler: Portfolio data
EditHandler-->>EditPage: Portfolio data
User->>EditPage: Update fields, photo, toggles
loop For each update
EditPage->>EditUpdateHandler: PATCH /api/edit/:token (fields)
EditUpdateHandler->>DB: Update portfolio
DB-->>EditUpdateHandler: OK
EditUpdateHandler-->>EditPage: Success
endflowchart TD
A["UploadPage (UI)"]
B["UploadHandler (/api/upload)"]
C["RateLimiter"]
D["ParseJobOrchestrator"]
E["AsyncPDFParser (Serverless)"]
F["BlobStorage (Vercel Blob)"]
G["DB (Supabase Postgres)"]
H["StatusHandler (/api/status/:jobId)"]
I["PortfolioPage (/p/:slug)"]
J["PortfolioHandler (/api/portfolio/:slug)"]
K["EditPage (UI)"]
L["EditHandler (/api/edit/:token)"]
M["EditUpdateHandler, PhotoUploadHandler, VisibilityHandler, SEOHandler, DeleteHandler"]
A --> B
B --> C
B --> F
B --> G
B --> D
D --> E
E --> F
E --> G
H --> G
I --> J
J --> G
K --> L
L --> G
K --> M
M --> GProtocols:
Error Handling:
noindex unless owner toggles.Deployment Platform: Vercel (mono-repo, serverless, zero manual ops)
Steps:
SUPABASE_URL, SUPABASE_SERVICE_KEYVERCEL_BLOB_TOKEN (if needed)JWT_SECRETDockerfile for local Next.js dev/testing.Deferred to Phase 2+:
Estimated Phase 1 Infra Setup Time: 4–8 hours
Deployment Topology Diagram
flowchart TD
A["Vercel (Next.js 16.2.7 Monolith)"]
B["Supabase Postgres 18.4 (Managed)"]
C["Vercel Blob Storage"]
D["GitHub Actions (CI/CD)"]
E["Developer Laptop (local Docker, optional)"]
D --> A
E --> A
A --> B
A --> CAlternatives may be reconsidered if:
This architecture provides a complete, production-ready blueprint for ResumeWeb, optimized for rapid delivery, privacy, and solo developer maintainability.
ResumeWeb is a privacy-centric, no-signup SaaS web application that enables users—job seekers, students, freelancers, and professionals—to instantly convert a resume PDF into a polished, mobile-friendly portfolio page. The product addresses the widespread friction and privacy risks of traditional resume sharing by providing a one-click, asynchronous upload-to-portfolio flow, stripping all personal contact information from public pages, and offering unique edit and public URLs for user control without requiring accounts. ResumeWeb’s key objectives are to deliver a live portfolio in under a minute, guarantee user privacy by default, and maximize accessibility for non-technical users globally. The initial demo targets a credible, production-quality MVP within 10 days, optimized for solo developer delivery and mass-market reach.
Traditional methods of sharing resumes online are fraught with friction and privacy risks. Many job seekers, students, and professionals lack the technical skills or time to build personal websites, while existing solutions often require account creation, expose personal contact information, or are slow and cumbersome. This is a significant barrier for anyone needing a quick, professional online presence for networking, job applications, or sharing credentials—especially in a market where digital portfolios are increasingly expected. Current workarounds, such as generic website builders, LinkedIn, or manual conversion, are either too technical, expose sensitive information, or are time-consuming. There is a clear market gap for a tool that enables instant, private, and professional online portfolios from any resume PDF, with zero signup or technical barriers.
ResumeWeb provides a frictionless, no-signup web app that instantly converts a resume PDF into a structured, visually appealing, and mobile-friendly portfolio page. The process is asynchronous for speed and reliability, and privacy is prioritized by stripping contact details (email, phone, address) from public pages at parse time. Users receive both a unique public URL and a private edit link (magic token) to manage their portfolio—edit content, upload a photo, or control visibility and SEO—without ever creating an account. The platform leverages AI-powered parsing to extract and structure resume content, ensuring a professional presentation. By eliminating account barriers, manual data entry, and privacy concerns, ResumeWeb uniquely combines instant onboarding, privacy-by-design, and mass accessibility.
| Stakeholder | Role/Responsibility | Influence/Interest |
|---|---|---|
| End Users | Upload resumes, manage portfolios | High |
| Solo Developer | Product owner, developer, QA, DevOps | Critical |
| University Career Services (future) | Potential B2B partners for bulk onboarding | Medium (future) |
| Executive Sponsor | (If applicable) Approves scope, tracks KPIs | Medium |
| Platform Providers | Vercel, Supabase—infra, support, SLAs | Medium |
| Security Auditor | (Pre-launch) Validate privacy and security | High (at launch) |
Architecture Alignment: All technical requirements strictly follow the approved Architecture v1.0.0.
allow_search_indexingapplication/pdf, max 4MB, magic bytes check| Category | Requirement |
|---|---|
| Performance | Median upload-to-live URL time < 2 minutes; async parse pipeline must not block UI |
| Scalability | Serverless functions auto-scale; DB and storage scale vertically; no sharding required v1 |
| Reliability | 99.9% uptime target (Vercel/Supabase SLAs); automated daily DB backups |
| Availability | Global CDN for static/SSR assets; zero-downtime deploys via Vercel |
| Security | JWT edit tokens, HTTPS everywhere, PII scrubbed, input validation, XSS/injection defense |
| Privacy | No public PII, no user accounts, uploader IP hashed only for rate limiting |
| Compliance | GDPR-aligned practices (no PII exposure, right to delete, data minimization) |
| Usability | Mobile-first, accessible, no technical skills required |
| Maintainability | Monorepo, automated CI/CD, clear code structure |
| Metric | Target/Goal | Measurement Method |
|---|---|---|
| Median time: upload → live URL | < 2 minutes | Instrumented in Vercel Analytics |
| Portfolio creation success rate | > 95% (parse succeeds, not error) | Parse job logs, error tracking |
| % portfolios with no public PII | 100% | Automated test + manual review |
| Upload-to-edit-link delivery | > 99% | API logs, error monitoring |
| User-reported privacy issues | 0 | Support tickets, feedback |
| Uptime | 99.9% | Vercel/Supabase monitoring |
| Mobile device usage | > 60% sessions | Vercel Analytics |
| Upload error rate | < 5% | API logs |
| Rate limit abuse incidents | < 1 per 1,000 uploads | Rate limiter logs |
| Risk | Mitigation Strategy | Contingency Plan |
|---|---|---|
| AI parsing fails on diverse resume formats | Use robust LLM wrapper, fallback to manual error UX | Log failures, prompt user to retry |
| Abuse via spam/malicious uploads (no accounts) | Strict file validation, rate limiting (5/hour/IP), input sanitation | Monitor logs, block abusive IPs |
| Privacy breach (PII not stripped) | Automated PII detection, test coverage, manual QA | Hotfix deploy, notify affected users |
| Token leakage (edit link compromise) | Long, unguessable JWTs, never shown publicly | Invalidate token, allow delete |
| Scaling async processing for mass usage | Serverless async jobs, monitor queue times | Scale up DB/storage, optimize pipeline |
| Competitive risk from established platforms | Emphasize privacy, no-signup, instant onboarding in messaging | Accelerate feature roadmap |
| Limited feature set restricts retention | Plan for premium features in Phase 2 | Gather user feedback, prioritize next |
noindex unless owner toggles.| Column | Type | Constraints |
|---|---|---|
| id | UUID | PK, DEFAULT gen_random_uuid() |
| slug | VARCHAR(32) | UNIQUE, NOT NULL |
| edit_token_jwt | TEXT | NOT NULL, unique magic edit JWT |
| pdf_blob_url | TEXT | NOT NULL |
| photo_blob_url | TEXT | NULLABLE |
| parse_status | ENUM | 'pending','processing','success','error' (DEFAULT 'pending', NOT NULL) |
| parse_error_message | TEXT | NULLABLE |
| summary | TEXT | NULLABLE |
| experience_json | JSONB | NULLABLE, array of experiences |
| skills_json | JSONB | NULLABLE, array of skills |
| education_json | JSONB | NULLABLE, array of education |
| projects_json | JSONB | NULLABLE, array of projects |
| is_published | BOOLEAN | NOT NULL, DEFAULT FALSE |
| allow_search_indexing | BOOLEAN | NOT NULL, DEFAULT FALSE |
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
| updated_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
| deleted_at | TIMESTAMP | NULLABLE, for soft deletes |
| uploader_ip_hash | CHAR(64) | NOT NULL, SHA-256 hash of IP |
| Column | Type | Constraints |
|---|---|---|
| id | UUID | PK, DEFAULT gen_random_uuid() |
| portfolio_id | UUID | FK portfolios(id), NOT NULL |
| status | ENUM | 'pending','processing','success','error' (DEFAULT 'pending', NOT NULL) |
| error_message | TEXT | NULLABLE |
| started_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
| finished_at | TIMESTAMP | NULLABLE |
| Column | Type | Constraints |
|---|---|---|
| ip_hash | CHAR(64) | PK, SHA-256 of IP |
| uploads_last_hour | INTEGER | NOT NULL, DEFAULT 0 |
| last_upload_at | TIMESTAMP | NOT NULL, DEFAULT NOW() |
Relationships:
ER Diagram:
erDiagram
portfolios {
UUID id PK
VARCHAR(32) slug
TEXT edit_token_jwt
TEXT pdf_blob_url
TEXT photo_blob_url
ENUM parse_status
TEXT parse_error_message
TEXT summary
JSONB experience_json
JSONB skills_json
JSONB education_json
JSONB projects_json
BOOLEAN is_published
BOOLEAN allow_search_indexing
TIMESTAMP created_at
TIMESTAMP updated_at
TIMESTAMP deleted_at
CHAR(64) uploader_ip_hash
}
parse_jobs {
UUID id PK
UUID portfolio_id FK
ENUM status
TEXT error_message
TIMESTAMP started_at
TIMESTAMP finished_at
}
upload_limits {
CHAR(64) ip_hash PK
INTEGER uploads_last_hour
TIMESTAMP last_upload_at
}
portfolios ||--o| parse_jobs: "has"Storage Strategies:
Data Processing:
Data Flow:
All endpoints are Next.js Route Handlers under /api/, not /api/v1/.
Minimum 8 endpoints, all mapped to features as per Architecture.
| Feature | API Endpoints |
|---|---|
| Resume Upload | POST /api/upload |
| Async Processing + Status | GET /api/status/:jobId |
| Public Portfolio Page | GET /api/portfolio/:slug |
| Private Edit Link | GET /api/edit/:token, PATCH /api/edit/:token, POST /api/edit/:token/photo, DELETE /api/edit/:token |
| SEO/Visibility Controls | PATCH /api/edit/:token/visibility, PATCH /api/edit/:token/seo |
| Rate Limiting | Applied on POST /api/upload (via IP) |
multipart/form-data
202 Accepted
{ "jobId": "string" }400 Bad Request (invalid file type/size)429 Too Many Requests (rate limit)500 Internal Server Error200 OK
{
"status": "pending" | "processing" | "success" | "error",
"errorMessage": "string (optional)",
"publicUrl": "string (if success)",
"editUrl": "string (if success)"
}404 Not Found (unknown jobId)200 OK
{
"slug": "string",
"summary": "string",
"experience": [ ... ],
"skills": [ ... ],
"education": [ ... ],
"projects": [ ... ],
"photoUrl": "string (optional)",
"allowSearchIndexing": true | false
}404 Not Found (unpublished or deleted)X-Robots-Tag and meta tags based on allow_search_indexing.200 OK
{
"slug": "string",
"summary": "string",
"experience": [ ... ],
"skills": [ ... ],
"education": [ ... ],
"projects": [ ... ],
"photoUrl": "string (optional)",
"isPublished": true | false,
"allowSearchIndexing": true | false
}401 Unauthorized (invalid/expired token)404 Not Found (deleted){
"summary": "string (optional)",
"experience": [ ... ],
"skills": [ ... ],
"education": [ ... ],
"projects": [ ... ]
}200 OK { "success": true }401 Unauthorized400 Bad Request (validation error)multipart/form-data
200 OK { "photoUrl": "string" }401 Unauthorized400 Bad Request (invalid file){ "isPublished": true | false }200 OK { "isPublished": true | false }{ "allowSearchIndexing": true | false }200 OK { "allowSearchIndexing": true | false }204 No ContentAuthentication/Authorization:
API Versioning:
/api/ namespace per requirements; no /api/v1/ sprawl.Rate Limiting:
Error Handling:
400, 401, 404, 429, 500).Solo Developer Roadmap (Sequential, 10-day Demo Target)
| Phase | Deliverable(s) | Est. Duration | Dependencies |
|---|---|---|---|
| 1 | Infra setup (Vercel, Supabase, Blob, CI/CD) | 1 day | None |
| 2 | UploadPage + UploadHandler + RateLimiter | 1 day | Phase 1 |
| 3 | AsyncPDFParser + ParseJobOrchestrator + StatusPage | 2 days | Phase 2 |
| 4 | PortfolioPage + PortfolioHandler (public) | 1 day | Phase 3 |
| 5 | EditPage + EditHandler + EditUpdateHandler | 1 day | Phase 4 |
| 6 | PhotoUploadHandler + Visibility/SEO Controls | 1 day | Phase 5 |
| 7 | DeleteHandler + Soft Delete Flow | 0.5 day | Phase 6 |
| 8 | End-to-end Testing + Accessibility Audit | 1 day | All previous phases |
| 9 | Monitoring, Analytics, Sentry (optional) | 0.5 day | All previous phases |
| 10 | Polish, bugfix, deploy demo | 1 day | All previous phases |
Total Estimated Time: 10 days (±2)
End of PRD
This epic covers usability, accessibility, user experience, and error handling to ensure the application is easy and pleasant to use for all users.
As an end user, I want clear and helpful error messages during upload, parsing, and editing, so that I understand issues and can take corrective actions.
Priority: high
Dependencies: Validate Resume PDF File Type and Size on Upload (ce87d27a-c832-4996-899a-71b70e6b9469), Handle Parse Failures with Clear User Feedback (63ce28e8-ff27-4dcd-9a3c-3c2af195e385), Implement Edit Page UI for Portfolio Content Updates (fe6c18e4-f9af-45f3-be37-9d88c7c29eb2)
Acceptance Criteria:
Story Points: 3
As an end user, I want the application UI to be mobile-friendly and accessible (WCAG 2.1 AA), so that I can use it easily on any device.
Priority: high
Dependencies: Landing Page for Resume PDF Upload (e48d6f2a-2901-4aa1-93db-8fe75e8637a3), Serve Public Portfolio Page at /p/{slug} (efe27222-56ba-4992-b7ad-38d872319942), Implement Edit Page UI for Portfolio Content Updates (fe6c18e4-f9af-45f3-be37-9d88c7c29eb2)
Acceptance Criteria:
Story Points: 5
This epic covers monitoring, logging, alerting, uptime, disaster recovery, and fault tolerance to ensure a reliable and maintainable service.
As the platform, I want to maintain 99.9% uptime and support zero-downtime deployments, so that users experience high availability.
Priority: high
Dependencies: Provision Supabase Postgres Database and Setup Schema (ffe8e4b8-643d-4d06-bec5-1f11c45d2ca1), Setup Vercel Blob Storage for PDFs and Photos (a051b18f-3d2e-4623-8056-fe42e33a6069)
Acceptance Criteria:
Story Points: 3
As the platform, I want automated daily backups of the database and a disaster recovery plan, so that data loss risks are minimized.
Priority: medium
Dependencies: Provision Supabase Postgres Database and Setup Schema (ffe8e4b8-643d-4d06-bec5-1f11c45d2ca1)
Acceptance Criteria:
Story Points: 3
As the developer, I want to monitor application performance and errors using Vercel Analytics and optionally Sentry, so that issues can be detected and resolved quickly.
Priority: medium
Dependencies: Implement Async PDF Parsing Pipeline (06cf3e7c-9415-4253-8296-180d9b5c77e0), Implement Status Polling API for Parse Jobs (e1cf62fd-4fa4-4561-94c5-1bfe82c90ee5)
Acceptance Criteria:
Story Points: 3
This epic covers security and privacy requirements including authentication, authorization, encryption, PII handling, and compliance.
As the system, I want to strip email, phone, and address from public portfolios and default to noindex, so that user privacy is protected by design.
Priority: high
Dependencies: Strip PII from Parsed Data at Parse Time (4f7a6947-fea6-4976-a5f4-7e8729b0e402), Set Default Noindex for Public Portfolio Pages (970155bc-244b-40f4-a54d-4d394ca8c27b)
Acceptance Criteria:
Story Points: 5
As the platform, I want all data in transit to be encrypted with HTTPS and all data at rest to be encrypted, so that user data is protected.
Priority: high
Dependencies: Provision Supabase Postgres Database and Setup Schema (ffe8e4b8-643d-4d06-bec5-1f11c45d2ca1), Setup Vercel Blob Storage for PDFs and Photos (a051b18f-3d2e-4623-8056-fe42e33a6069)
Acceptance Criteria:
Story Points: 3
As the system, I want to authenticate edit requests using signed JWT tokens, so that no user accounts are needed and access is secure.
Priority: high
Dependencies: Generate and Return Private Edit Link with Signed JWT Token (6d1dd22e-3401-4e5c-bf95-ba55e6495793)
Acceptance Criteria:
Story Points: 5
This epic covers performance and scalability requirements to ensure fast processing, low latency, and ability to handle concurrent users and data volume.
As the platform, I want serverless functions and database to auto-scale to handle concurrent users and data volume, so that the service remains reliable under load.
Priority: high
Dependencies: Provision Supabase Postgres Database and Setup Schema (ffe8e4b8-643d-4d06-bec5-1f11c45d2ca1)
Acceptance Criteria:
Story Points: 5
As the system, I want the median time from resume upload to live portfolio URL to be under 2 minutes, so that users receive fast results.
Priority: high
Dependencies: Implement Async PDF Parsing Pipeline (06cf3e7c-9415-4253-8296-180d9b5c77e0)
Acceptance Criteria:
Story Points: 8
This epic covers infrastructure setup and deployment for the ResumeWeb SaaS application, including database, storage, CI/CD, and environment configuration.
As a developer, I want to setup a local development environment with Docker and Next.js, so that I can develop and test the application locally.
Priority: medium
Acceptance Criteria:
Story Points: 5
As the developer, I want to setup automated CI/CD pipelines with GitHub Actions and Vercel, so that code is linted, tested, and deployed automatically.
Priority: high
Dependencies: Provision Supabase Postgres Database and Setup Schema (ffe8e4b8-643d-4d06-bec5-1f11c45d2ca1), Setup Vercel Blob Storage for PDFs and Photos (a051b18f-3d2e-4623-8056-fe42e33a6069)
Acceptance Criteria:
Story Points: 5
As the platform administrator, I want to configure Vercel Blob Storage for storing uploaded PDFs and photos, so that files are managed securely and efficiently.
Priority: high
Acceptance Criteria:
Story Points: 3
As the platform administrator, I want to provision a Supabase Postgres instance and apply the database schema, so that the application has a reliable data store.
Priority: high
Acceptance Criteria:
Story Points: 3
This epic covers user controls for search engine indexing and portfolio visibility, including default noindex settings and toggles for SEO opt-in.
As the system, I want to return HTTP 404 Not Found for public portfolio pages when is_published is false, so that unpublished portfolios are not accessible.
Priority: high
Dependencies: Serve Public Portfolio Page at /p/{slug} (efe27222-56ba-4992-b7ad-38d872319942)
Acceptance Criteria:
Story Points: 3
As an end user, I want to toggle search engine indexing of my portfolio via the edit page, so that I control my portfolio's discoverability.
Priority: high
Dependencies: Implement Edit Page UI for Portfolio Content Updates (fe6c18e4-f9af-45f3-be37-9d88c7c29eb2)
Acceptance Criteria:
Story Points: 3
As the system, I want to set public portfolio pages to noindex by default via robots meta tag and HTTP header, so that portfolios are not indexed unless opted-in.
Priority: high
Dependencies: Serve Public Portfolio Page at /p/{slug} (efe27222-56ba-4992-b7ad-38d872319942)
Acceptance Criteria:
Story Points: 3
This epic covers the secure edit functionality via magic edit links (JWT tokens) allowing users to update portfolio content, upload photos, and manage visibility without login.
As an end user, I want to unpublish or soft-delete my portfolio via the private edit link, so that I can control my portfolio's visibility or remove it.
Priority: high
Dependencies: Generate and Return Private Edit Link with Signed JWT Token (6d1dd22e-3401-4e5c-bf95-ba55e6495793)
Acceptance Criteria:
Story Points: 5
As an end user, I want to upload an optional photo to my portfolio via the edit page, so that I can personalize my portfolio.
Priority: high
Dependencies: Implement Edit Page UI for Portfolio Content Updates (fe6c18e4-f9af-45f3-be37-9d88c7c29eb2)
Acceptance Criteria:
Story Points: 5
As an end user, I want to update text fields extracted from my resume via a private edit page, so that I can refine my portfolio content.
Priority: high
Dependencies: Generate and Return Private Edit Link with Signed JWT Token (6d1dd22e-3401-4e5c-bf95-ba55e6495793)
Acceptance Criteria:
Story Points: 5
As the system, I want to generate a secure, signed JWT edit token and return a private edit URL after successful upload and parse, so that users can manage their portfolio without accounts.
Priority: high
Dependencies: Create Portfolio and Parse Job Records on Upload (6d7cb2c4-2849-47cf-b45c-61118c196a2a), Implement Async PDF Parsing Pipeline (06cf3e7c-9415-4253-8296-180d9b5c77e0)
Acceptance Criteria:
Story Points: 3
This epic covers generation and serving of polished, mobile-friendly public portfolio pages at unique URLs, enforcing privacy and SEO controls.
As the system, I want to ensure no email, phone, or address data appears on public portfolio pages, so that user privacy is protected.
Priority: high
Dependencies: Strip PII from Parsed Data at Parse Time (4f7a6947-fea6-4976-a5f4-7e8729b0e402)
Acceptance Criteria:
Story Points: 3
As an end user, I want to access a mobile-friendly, visually polished portfolio page at a unique URL, so that I can share my credentials professionally.
Priority: high
Dependencies: Generate Unique Slugs for Public Portfolio URLs (609da41c-d895-4142-9b9f-d72761116756), Strip PII from Parsed Data at Parse Time (4f7a6947-fea6-4976-a5f4-7e8729b0e402)
Acceptance Criteria:
Story Points: 5
As the system, I want to generate unique, human-readable slugs for each portfolio, so that users have shareable public URLs.
Priority: high
Dependencies: Create Portfolio and Parse Job Records on Upload (6d7cb2c4-2849-47cf-b45c-61118c196a2a)
Acceptance Criteria:
Story Points: 3
This epic covers the asynchronous processing of uploaded resume PDFs to extract structured portfolio data, status tracking, error handling, and user feedback.
As an end user, I want clear error messages if my resume parsing fails, so that I understand the problem and can retry or correct it.
Priority: high
Dependencies: Implement Async PDF Parsing Pipeline (06cf3e7c-9415-4253-8296-180d9b5c77e0), Implement Status Polling API for Parse Jobs (e1cf62fd-4fa4-4561-94c5-1bfe82c90ee5)
Acceptance Criteria:
Story Points: 3
As an end user, I want to poll the status of my resume parsing job asynchronously, so that I receive real-time feedback without blocking requests.
Priority: high
Dependencies: Create Portfolio and Parse Job Records on Upload (6d7cb2c4-2849-47cf-b45c-61118c196a2a)
Acceptance Criteria:
Story Points: 3
As the system, I want to remove email, phone, and address from parsed portfolio data before storing, so that user privacy is protected.
Priority: high
Dependencies: Implement Async PDF Parsing Pipeline (06cf3e7c-9415-4253-8296-180d9b5c77e0)
Acceptance Criteria:
Story Points: 5
As the system, I want to asynchronously parse uploaded PDFs using pdf-parse and LLM extraction, so that structured portfolio data can be extracted without blocking user requests.
Priority: high
Dependencies: Create Portfolio and Parse Job Records on Upload (6d7cb2c4-2849-47cf-b45c-61118c196a2a)
Acceptance Criteria:
Story Points: 8
This epic covers all features related to the uploading of resume PDFs by users without requiring signup. It includes file validation, rate limiting, asynchronous handling, and user feedback during upload.
As the system, I want to create portfolio and parse job database records upon successful upload, so that the resume can be processed asynchronously.
Priority: high
Dependencies: Store Uploaded Resume PDF in Vercel Blob Storage (164a1190-8581-44e1-83be-08f6f8e7811c)
Acceptance Criteria:
Story Points: 5
As the system, I want to store validated uploaded PDFs in Vercel Blob Storage, so that files are securely stored and accessible for parsing.
Priority: high
Dependencies: Validate Resume PDF File Type and Size on Upload (ce87d27a-c832-4996-899a-71b70e6b9469), Implement Upload Rate Limiting per IP Address (bf7b6ffc-1754-43b5-b2b0-170d211701de)
Acceptance Criteria:
Story Points: 5
As the system, I want to enforce a maximum of 5 uploads per hour per IP address, so that abuse and spam are prevented.
Priority: high
Dependencies: Landing Page for Resume PDF Upload (e48d6f2a-2901-4aa1-93db-8fe75e8637a3)
Acceptance Criteria:
Story Points: 5
As the system, I want to validate that uploaded files are PDFs with MIME type application/pdf and size <= 4MB, so that only valid resumes are processed.
Priority: high
Dependencies: Landing Page for Resume PDF Upload (e48d6f2a-2901-4aa1-93db-8fe75e8637a3)
Acceptance Criteria:
Story Points: 3
As an end user, I want a single landing page to upload my resume PDF, so that I can start creating my portfolio without signup.
Priority: high
Acceptance Criteria:
Story Points: 3
Spike
As the developer, I need to setup documentation tools and initial docs, so that project knowledge is captured and shared.
Priority: medium
Timebox: 0.5 day
Expected Outcomes:
Acceptance Criteria:
Story Points: 2
Spike
As the developer, I need to setup database migration tooling and apply initial schema, so that database changes are manageable and versioned.
Priority: high
Timebox: 0.5 day
Expected Outcomes:
Acceptance Criteria:
Story Points: 3
Spike
As the developer, I need to setup CI/CD pipelines for linting, testing, and deployment, so that code quality and delivery are automated.
Priority: high
Timebox: 1 day
Expected Outcomes:
Acceptance Criteria:
Story Points: 5
Spike
As the developer, I need to setup a local development environment with Docker and testing frameworks, so that I can develop and test reliably.
Priority: high
Timebox: 1 day
Expected Outcomes:
Acceptance Criteria:
Story Points: 5
Spike
As the developer, I need to initialize the repository and scaffold the Next.js project with TypeScript and Tailwind CSS, so that development can start with a solid foundation.
Priority: high
Timebox: 1 day
Expected Outcomes:
Acceptance Criteria:
Story Points: 3
Execution order should follow dependencies; complete "Depends on" tasks before each task.
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
33e87663-96eb-4b00-b630-ba227c2362c3Acceptance Criteria:
Definition of Done:
dfe95477-2e31-4812-8cd7-33390f5caf68, 8a740e79-bcbf-41e4-8bfd-12cecdaf6d82Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
dbb7eb4a-5fa3-4c3b-8570-4f186abb3152Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
5a4474d1-1b51-46a9-baaa-8e8989c54215Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
23a45cd9-5624-41a8-b62d-7dbb0e925d82, 01dee65e-bc3c-4595-adeb-4f154c2464c8Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
d291a122-fe84-468e-8e4e-ac82efb2ef74Acceptance Criteria:
Definition of Done:
043cd481-2ca7-4dba-9668-3b19b1310912Acceptance Criteria:
Definition of Done:
900c135c-13c0-488f-98b4-345978ba39beAcceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
5a4474d1-1b51-46a9-baaa-8e8989c54215Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
e5a8d7b7-fb9c-4ec6-93e4-6f268ff4c186Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
5d060f8a-1332-4d02-81ac-aa1a7843f6a3Acceptance Criteria:
Definition of Done:
e5a8d7b7-fb9c-4ec6-93e4-6f268ff4c186, 5ac7ea26-a221-4470-8d55-b2c5a71cc899Acceptance Criteria:
Definition of Done:
5d060f8a-1332-4d02-81ac-aa1a7843f6a3Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
e80be497-3f83-4d22-add2-a99a70b2a349Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
23a45cd9-5624-41a8-b62d-7dbb0e925d82Acceptance Criteria:
Definition of Done:
01dee65e-bc3c-4595-adeb-4f154c2464c8Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
27df936b-5390-42c1-8e9e-44a5bbe5f3f6Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done:
Acceptance Criteria:
Definition of Done: