Transform hours of manual proposal writing into seconds.
Draftly is a full-stack SaaS application that leverages Retrieval-Augmented Generation (RAG), vector embeddings, and dual-LLM fallback strategies to generate tailored, 10-section RFP proposal drafts from organizational knowledge bases.
Built with multi-tenant isolation, async job queues, pgvector similarity search, and automated test coverage.
- Engineering & Architecture Highlights
- Application Preview & Screenshots
- Problem & Solution
- Key Features
- Architecture & Data Flow
- Tech Stack
- Security & Multi-Tenancy
- Billing & Subscription Engine
- License & Contact
Key engineering decisions and architectural implementations in Draftly:
- Production RAG Engine: Implements end-to-end vector retrieval with
pgvectorand Google AItext-embedding-004(768-dimensional embeddings), chunking documents into ~500-word segments with 50-word overlap for high context recall. - Fault-Tolerant Dual-LLM Pipeline: Primary generation uses Google Gemini 2.5 Flash. On encountering rate limits (HTTP 429), the task seamlessly falls back to Groq
llama-3.1-8b-instant, ensuring high uptime. - Strict Multi-Tenant Isolation: Custom Django REST Framework permissions (
IsOrgMember,OrgDocQuotaPermission,OrgProposalQuotaPermission) ensure zero cross-tenant data leakage and enforce strict row-level security on all database queries. - Asynchronous Worker Architecture: Non-blocking document ingestion and proposal generation executed via Celery with Redis as broker/result backend, featuring status polling and exponential backoff retries.
- Full Stripe Subscription Integration: End-to-end monetization featuring Stripe Checkout, Customer Portal, and webhook signature verification with idempotency protection via
StripeEventlogging. - Robust Automated Test Suite: Full test coverage with
pyteston the backend andVitest+React Testing Library+MSW(Mock Service Worker) on the frontend, protected by pre-push hooks.
Paste RFP requirements, select past company case studies, customize generation tone, and trigger AI drafting.
WYSIWYG section-by-section proposal editor featuring real-time status polling, prompt refinement, and PDF / DOCX export capabilities.
Multi-format document ingestion (PDF, DOCX, TXT), vector chunking status indicators, metadata tracking, and semantic search.
Comprehensive org analytics displaying proposal volume trends, word counts, active vector chunk metrics, and monthly tier quota usage.
| Problem | Draftly Solution |
|---|---|
| Time-Consuming RFPs: B2B sales teams spend 15+ hours drafting proposals manually. | Sub-60s Draft Generation: Draftly builds structured, 10-section proposals in seconds. |
| Hallucinations & Generic Reponses: Off-the-shelf LLMs output generic, ungrounded text. | Grounding via RAG: Proposals are strictly synthesized from company case studies & reference docs. |
| Formatting Inconsistencies: Proposals lack standard corporate structure. | Deterministic 10-Section Schema: Guarantees standard executive summary, methodology, pricing, etc. |
| Data Privacy Risks: Mixing client context across organizations. | Tenant-Isolated Vector Store: pgvector cosine search is strictly scoped by org_id. |
- Upload PDF, DOCX, and TXT company documents.
- Automatic text extraction via
PyMuPDFandpython-docx. - Smart word-based chunking with configurable overlap.
- Batched embedding generation stored directly in PostgreSQL using
pgvector.
- Automatically parses RFP requirements and generates 10 tailored sections:
- Executive Summary
- Understanding Requirements
- Proposed Solution
- Relevant Experience
- Team Qualifications
- Project Timeline
- Methodology
- Pricing Structure
- Why Choose Us
- Appendix & Terminology
- Automatic LLM fallback strategy (Gemini 2.5 Flash ➡️ Groq Llama 3.1 8B).
- Section-by-section Tiptap rich-text editor in React.
- Export finalized proposals directly to PDF (styled layout) or DOCX (editable Word document).
- Subscription tiers: Free, Solo, Studio, and Agency.
- Real-time enforcement of document uploads and monthly proposal generation limits.
- Automated monthly quota resets on the 1st of each month (UTC).
┌────────────────────────────────────────────────────────┐
│ React 18 SPA │
│ Vite • Zustand • Tiptap • Recharts • Axios Interceptor │
└───────────────────────────┬────────────────────────────┘
│ HTTPS (JWT Auth)
┌───────────────────────────▼────────────────────────────┐
│ Django REST Framework │
│ Auth • Multi-Tenant Permissions • REST Endpoints │
└──────────┬──────────────────┬──────────────────┬───────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ PostgreSQL │ │ Celery Queue │ │ External AI │
│ + pgvector │ │ + Redis │ │ APIs & Stripe│
└──────────────┘ └──────────────┘ └──────────────┘
[User Upload] ──> [Django REST API] ──> [Save File] ──> [Celery Task]
│
┌─────────────────────────────────────────────────────────┴─────────────────────────────────────────┐
│ 1. Extract raw text (PyMuPDF / python-docx) │
│ 2. Split into ~500-word overlapping chunks │
│ 3. Batch embed via Google AI text-embedding-004 │
│ 4. Store vectors in PostgreSQL (pgvector) scoped to tenant org_id │
└─────────────────────────────────────────────────────────┬─────────────────────────────────────────┘
│
[Proposal Request] ──> [Embed RFP Query] ──> [Cosine Vector Search] ──> [Prompt Gemini / Groq] ──> [10-Section Draft]
| Model | Purpose | Key Attributes / Relationships |
|---|---|---|
| Organization | Tenant boundary & billing | subscription_tier, doc_quota, proposal_quota, Stripe IDs |
| User | Tenant member | org (FK), email, role (admin/member), is_active |
| Document | Raw uploaded knowledge | org (FK), uploaded_by (FK), file_type, status (processed/failed) |
| Chunk | Embedded text segment | document (FK), org (FK), content, embedding (vector(768)) |
| RFP | Target proposal request | org (FK), created_by (FK), title, raw_text |
| Proposal | Final generated output | rfp (FK), org (FK), sections (JSONField), status (draft/final) |
- Framework: Python 3.11, Django 5.0, Django REST Framework
- Task Queue: Celery 5.3, Redis 7 (Broker & Backend)
- Database: PostgreSQL 16 with
pgvectorextension - Authentication: djangorestframework-simplejwt (JWT Access/Refresh tokens)
- Error Monitoring: Sentry SDK (Backend + Celery workers)
- Vector Embeddings: Google AI
models/text-embedding-004(768 dimensions) - Primary LLM: Google Gemini 2.5 Flash
- Fallback LLM: Groq
llama-3.1-8b-instant - Text Parsing: PyMuPDF (
fitz),python-docx
- Framework: React 18, Vite 5
- State Management: Zustand
- WYSIWYG Editor: Tiptap Editor (
@tiptap/react) - Data Visualization: Recharts
- HTTP Client: Axios with auto-refresh token interceptors
- Styling: Modern Vanilla CSS Design System with dark mode support
Draftly enforces security at every layer of the application stack:
- Row-Level Organization Scoping: All models explicitly reference an
Organization. Queries automatically inject.filter(org=request.user.org)via permissions. - Permission Guardrails: Custom permission classes inspect subscription quotas before executing heavy Celery tasks.
- Vector Store Scoping: Vector similarity queries in
pgvectorappend standard SQLWHERE org_id = %sconditions to prevent cross-tenant context injection. - JWT Lifecycle: Short-lived access tokens with automatic token rotation via refresh endpoints.
Draftly features a fully implemented Stripe billing engine in apps/billing/:
- Tier Resolution: Resolves subscription tiers directly from Stripe line-item price IDs.
- Webhook Handling: Handlers for
checkout.session.completed,customer.subscription.updated,customer.subscription.deleted,invoice.paid, andinvoice.payment_failed. - Idempotency: Prevents duplicate webhook processing using a dedicated
StripeEventevent tracking model.
Distributed under the MIT License. See LICENSE for more information.



