A freelance contract management platform with digital signatures, email delivery, and subscription billing.
Flowio enables freelancers to create, send, and manage contracts with clients. The platform includes digital signature collection, PDF generation, and payment tracking with a tiered subscription model.
- Create contracts with customizable content
- Send contracts via email to clients
- Collect digital signatures through secure signing links
- Download contracts as PDF documents
- Search and filter contracts by status
- Visual analytics with status breakdown charts
- Revenue tracking for signed and completed contracts
- Contract status tracking (Draft, Pending, Signed, Completed)
- Secure authentication with Supabase Auth
- Password reset functionality
- Row Level Security for data isolation
- Dodo Payments integration for subscription management
- Free plan: 3 contracts per month
- Pro plan: Unlimited contracts at $2/month
| Category | Technology |
|---|---|
| Framework | Next.js 14 (App Router) |
| Language | TypeScript |
| Database | Supabase (PostgreSQL) |
| Authentication | Supabase Auth |
| Styling | Tailwind CSS |
| Resend | |
| PDF Generation | jsPDF |
| Charts | Recharts |
| Payments | Dodo Payments |
- Node.js 18 or higher
- npm or yarn
- Supabase account
- Resend account for email functionality
- Dodo Payments account for billing (optional)
-
Clone the repository
git clone https://github.com/yourusername/flowio.git cd flowio -
Install dependencies
npm install
-
Configure environment variables
Create a
.env.localfile in the root directory:NEXT_PUBLIC_SUPABASE_URL=your_supabase_url NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key SUPABASE_SERVICE_ROLE_KEY=your_service_role_key NEXT_PUBLIC_APP_URL=http://localhost:3000 RESEND_API_KEY=your_resend_api_key DODO_API_KEY=your_dodo_api_key DODO_PRO_PRODUCT_ID=your_product_id DODO_WEBHOOK_SECRET=your_webhook_secret -
Set up the database
Run the following SQL in your Supabase SQL Editor:
-- Users table CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT UNIQUE NOT NULL, name TEXT, plan TEXT DEFAULT 'free', dodo_customer_id TEXT, dodo_subscription_id TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Contracts table CREATE TABLE contracts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, title TEXT NOT NULL, client_name TEXT NOT NULL, client_email TEXT NOT NULL, content TEXT NOT NULL, template_id TEXT, amount DECIMAL(10,2), currency TEXT DEFAULT 'USD', status TEXT DEFAULT 'draft', signing_token TEXT UNIQUE, signed_at TIMESTAMP WITH TIME ZONE, due_date TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Enable Row Level Security ALTER TABLE users ENABLE ROW LEVEL SECURITY; ALTER TABLE contracts ENABLE ROW LEVEL SECURITY; -- User policies CREATE POLICY "Users can read own data" ON users FOR SELECT USING (auth.uid() = id); CREATE POLICY "Users can update own data" ON users FOR UPDATE USING (auth.uid() = id); -- Contract policies CREATE POLICY "Users can manage own contracts" ON contracts FOR ALL USING (auth.uid() = user_id); CREATE POLICY "Public can view contracts by signing token" ON contracts FOR SELECT USING (signing_token IS NOT NULL); CREATE POLICY "Public can update contracts by signing token" ON contracts FOR UPDATE USING (signing_token IS NOT NULL);
-
Start the development server
npm run dev
-
Open http://localhost:3000 in your browser
flowio/
├── app/
│ ├── api/
│ │ ├── auth/ Authentication endpoints
│ │ ├── contracts/ Contract CRUD operations
│ │ └── dodo/ Payment webhooks and checkout
│ ├── dashboard/ Main application dashboard
│ ├── login/ User login page
│ ├── signup/ User registration page
│ ├── settings/ Account settings
│ ├── sign/[token]/ Public contract signing page
│ └── page.tsx Landing page
├── components/
│ ├── ContractModal.tsx Contract creation and editing
│ ├── Navbar.tsx Navigation component
│ ├── Footer.tsx Footer component
│ ├── PricingCard.tsx Pricing display component
│ └── LoadingSpinner.tsx Loading indicator
├── lib/
│ ├── api.ts Supabase API functions
│ ├── auth-context.tsx Authentication context provider
│ ├── supabase.ts Supabase client configuration
│ ├── email.ts Email sending utilities
│ ├── pdf.ts PDF generation
│ ├── dodo.ts Payment configuration
│ └── templates.ts Contract templates
├── types/
│ └── index.ts TypeScript type definitions
└── public/ Static assets
| Endpoint | Method | Description |
|---|---|---|
| /api/auth/signup | POST | Create new user account |
| /api/auth/login | POST | Authenticate user |
| /api/auth/logout | POST | End user session |
| /api/contracts | GET | List user contracts |
| /api/contracts | POST | Create new contract |
| /api/contracts/[id] | PUT | Update contract |
| /api/contracts/[id] | DELETE | Delete contract |
| /api/contracts/send | POST | Send contract via email |
| /api/contracts/sign/[token] | GET | Retrieve contract for signing |
| /api/contracts/sign/[token] | POST | Submit signature |
| /api/dodo/checkout | POST | Create payment session |
| /api/dodo/webhook | POST | Process payment events |
| Variable | Required | Description |
|---|---|---|
| NEXT_PUBLIC_SUPABASE_URL | Yes | Supabase project URL |
| NEXT_PUBLIC_SUPABASE_ANON_KEY | Yes | Supabase anonymous key |
| SUPABASE_SERVICE_ROLE_KEY | Yes | Supabase service role key |
| NEXT_PUBLIC_APP_URL | Yes | Application base URL |
| RESEND_API_KEY | Yes | Resend API key for emails |
| DODO_API_KEY | No | Dodo Payments API key |
| DODO_PRO_PRODUCT_ID | No | Dodo product ID for Pro subscription |
| DODO_WEBHOOK_SECRET | No | Webhook signature verification key |
MIT License. See LICENSE file for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
For bug reports or feature requests, please open an issue on GitHub.