Files
SwiftInvoice/docs/SwiftInvoice_Implementation_Plan.md

32 KiB
Raw Permalink Blame History

SwiftInvoice — MVP Implementation Plan

Database Schema & Feature Specification

Version 1.0 • March 2026 Flutter • Dart • SQLite (Drift ORM) • Riverpod


Table of Contents

  1. Executive Summary
  2. Database Schema
  3. MVP Feature Specifications
  4. Build Timeline
  5. Tech Stack Reference
  6. Recommended Project Structure
  7. Key Risks & Mitigations
  8. Raw SQL Schema Reference

1. Executive Summary

SwiftInvoice is a cross-platform mobile invoicing application built with Flutter, targeting freelancers, tradespeople, and small business owners. The app differentiates itself through offline-first architecture, transparent pricing, and a modern UI that directly addresses the pain points of competitors like Invoice Simple.

This document defines every MVP feature in implementation-ready detail, provides a production-grade SQLite database schema designed for future extensibility, and outlines the screen-by-screen build plan to take the project from zero to App Store submission in nine weeks.

1.1 Strategic Pillars

Pillar Description
Offline-First Every core feature works without internet. SQLite local storage, local PDF generation, local notifications.
Price Transparency Flat $3.99/month. Lifetime option available. No retroactive changes, no feature removals.
Friction-Based Monetization Paywall appears only when the user hits a limit (4th invoice, 3rd client), never on app launch.
Modern UX Material Design 3, single-screen workflows, one-tap estimate-to-invoice conversion.

2. Database Schema

The schema below is designed for the Drift ORM (SQLite) and is intentionally extensible. Every table includes created_at and updated_at timestamps, UUID-based primary keys for future cloud sync compatibility, and nullable fields where v1.1 features will plug in. The schema supports multi-currency, recurring invoices, and cloud sync without requiring migration-breaking changes.

2.1 Design Principles

  • UUID primary keys on all tables to support conflict-free cloud sync in v1.1.
  • ISO 4217 currency_code column included from day one (default to user locale, multi-currency UI deferred to v1.1).
  • Unified documents table: invoices and estimates share the same documents table via a document_type discriminator, eliminating duplication and making estimate-to-invoice conversion trivial.
  • Soft deletes via is_deleted flag on client-facing tables, enabling undo and future sync reconciliation.
  • All monetary values stored as INTEGER cents (not floating point) to avoid rounding errors.
  • Indexes on every foreign key and on commonly filtered columns (status, due_date, is_deleted).

2.2 Entity Relationship Overview

businesses (1) ──< clients (many)
businesses (1) ──< documents (many)
clients    (1) ──< documents (many)
documents  (1) ──< line_items (many)
documents  (1) ──< payments (many)
documents  (1) ──< documents (self-ref: converted_from_id)

2.3 Table: businesses

Stores the user's business profile. Single-row table for MVP (multi-business support is a future consideration).

Column Type Constraints Notes
id TEXT (UUID) PRIMARY KEY UUID v4, generated client-side
name TEXT NOT NULL Business display name
email TEXT NULLABLE Contact email shown on invoices
phone TEXT NULLABLE Contact phone
address_line1 TEXT NULLABLE Street address line 1
address_line2 TEXT NULLABLE Street address line 2
city TEXT NULLABLE City
state TEXT NULLABLE State / province
postal_code TEXT NULLABLE Zip / postal code
country_code TEXT DEFAULT 'US' ISO 3166-1 alpha-2
tax_number TEXT NULLABLE Tax ID / VAT number
logo_path TEXT NULLABLE Local file path to logo image
default_currency TEXT DEFAULT 'USD' ISO 4217 code; drives default for new invoices
default_tax_rate INTEGER DEFAULT 0 Basis points (e.g., 825 = 8.25%)
default_payment_terms_days INTEGER DEFAULT 30 Auto-sets due date on new invoices
invoice_prefix TEXT DEFAULT 'INV' Prefix for auto-numbering (INV-001)
estimate_prefix TEXT DEFAULT 'EST' Prefix for estimate numbering
next_invoice_number INTEGER DEFAULT 1 Counter for auto-numbering
next_estimate_number INTEGER DEFAULT 1 Counter for estimate numbering
created_at TEXT (ISO 8601) NOT NULL Row creation timestamp
updated_at TEXT (ISO 8601) NOT NULL Last modification timestamp

2.4 Table: clients

Stores client/customer records. Free tier enforces a maximum of 2 active clients at the application layer.

Column Type Constraints Notes
id TEXT (UUID) PRIMARY KEY UUID v4
business_id TEXT FK → businesses.id Owner business
name TEXT NOT NULL Client display name
email TEXT NULLABLE Client email
phone TEXT NULLABLE Client phone
address_line1 TEXT NULLABLE Street address
address_line2 TEXT NULLABLE Address line 2
city TEXT NULLABLE City
state TEXT NULLABLE State / province
postal_code TEXT NULLABLE Zip / postal code
country_code TEXT NULLABLE ISO 3166-1 alpha-2
notes TEXT NULLABLE Internal notes (not shown on invoices)
outstanding_balance INTEGER DEFAULT 0 Cached sum of unpaid invoice totals (cents)
is_deleted INTEGER DEFAULT 0 Soft delete flag (0 = active, 1 = deleted)
created_at TEXT (ISO 8601) NOT NULL Row creation timestamp
updated_at TEXT (ISO 8601) NOT NULL Last modification timestamp

2.5 Table: documents

Unified table for both invoices and estimates, distinguished by the document_type column. This avoids schema duplication and makes estimate-to-invoice conversion a simple status change plus a new row copy.

Column Type Constraints Notes
id TEXT (UUID) PRIMARY KEY UUID v4
business_id TEXT FK → businesses.id Owner business
client_id TEXT FK → clients.id Associated client
document_type TEXT NOT NULL 'invoice' or 'estimate'
document_number TEXT NOT NULL, UNIQUE e.g., INV-001 or EST-003
status TEXT NOT NULL See status enum below
issue_date TEXT (ISO 8601) NOT NULL Date document was created/issued
due_date TEXT (ISO 8601) NULLABLE Payment due date (invoices) or expiry (estimates)
currency_code TEXT DEFAULT 'USD' ISO 4217; copied from business default at creation
subtotal INTEGER DEFAULT 0 Sum of line items (cents), auto-calculated
tax_rate INTEGER DEFAULT 0 Basis points (825 = 8.25%)
tax_amount INTEGER DEFAULT 0 Calculated tax in cents
discount_type TEXT NULLABLE 'percentage' or 'fixed'
discount_value INTEGER DEFAULT 0 Percentage (basis points) or fixed (cents)
discount_amount INTEGER DEFAULT 0 Resolved discount in cents
total INTEGER DEFAULT 0 Final total in cents (subtotal + tax - discount)
amount_paid INTEGER DEFAULT 0 Sum of linked payments (cents)
amount_due INTEGER DEFAULT 0 total - amount_paid (cents)
notes TEXT NULLABLE Notes/terms shown on document footer
converted_from_id TEXT NULLABLE FK → documents.id Links invoice back to source estimate
is_deleted INTEGER DEFAULT 0 Soft delete flag
created_at TEXT (ISO 8601) NOT NULL Row creation timestamp
updated_at TEXT (ISO 8601) NOT NULL Last modification timestamp

Document Status Enum Values

document_type Valid Statuses Description
invoice draft Invoice created but not yet sent
invoice sent Invoice shared with client
invoice partial Some payment received, balance remaining
invoice paid Fully paid
invoice overdue Past due_date and not fully paid (set by app logic)
invoice void Cancelled invoice (kept for records)
estimate draft Estimate created but not sent
estimate sent Estimate shared with client
estimate accepted Client approved; ready for invoice conversion
estimate declined Client rejected the estimate
estimate expired Past due_date (expiry) without acceptance
estimate converted Converted to invoice (converted_from_id links back)

2.6 Table: line_items

Shared line items table for both invoices and estimates. Each line item belongs to a document. The sort_order column preserves user-defined ordering.

Column Type Constraints Notes
id TEXT (UUID) PRIMARY KEY UUID v4
document_id TEXT FK → documents.id Parent document
description TEXT NOT NULL Line item description
quantity REAL NOT NULL, DEFAULT 1 Supports fractional (e.g., 2.5 hours)
unit_price INTEGER NOT NULL Price per unit in cents
amount INTEGER NOT NULL quantity × unit_price (cents), app-calculated
sort_order INTEGER DEFAULT 0 Display ordering within document
created_at TEXT (ISO 8601) NOT NULL Row creation timestamp
updated_at TEXT (ISO 8601) NOT NULL Last modification timestamp

2.7 Table: payments

Records individual payments against invoices. Supports partial payments and multiple payment methods. The document's amount_paid and amount_due fields are updated via application logic whenever a payment is added or removed.

Column Type Constraints Notes
id TEXT (UUID) PRIMARY KEY UUID v4
document_id TEXT FK → documents.id Associated invoice
amount INTEGER NOT NULL Payment amount in cents
method TEXT NOT NULL 'cash', 'card', 'bank_transfer', 'check', 'other'
paid_at TEXT (ISO 8601) NOT NULL Date/time payment was received
notes TEXT NULLABLE Payment memo or reference number
created_at TEXT (ISO 8601) NOT NULL Row creation timestamp
updated_at TEXT (ISO 8601) NOT NULL Last modification timestamp

2.8 Table: app_settings

Key-value store for application preferences (subscription status, theme, notification settings). Avoids hardcoding configuration and supports future settings without schema changes.

Column Type Constraints Notes
key TEXT PRIMARY KEY Setting identifier (e.g., 'subscription_tier')
value TEXT NOT NULL Serialized value (JSON string for complex values)
updated_at TEXT (ISO 8601) NOT NULL Last modification timestamp

2.9 Indexes

Index Name Table Columns Purpose
idx_clients_business clients business_id, is_deleted List active clients for a business
idx_documents_client documents client_id, document_type, status Filter docs by client and type
idx_documents_status documents status, due_date Dashboard: overdue detection, status filtering
idx_documents_type documents document_type, is_deleted Separate invoice vs estimate queries
idx_documents_number documents document_number Unique lookup by number (UNIQUE constraint)
idx_line_items_doc line_items document_id, sort_order Ordered retrieval of line items
idx_payments_doc payments document_id Sum payments for a document

2.10 Future-Proofing Notes

The schema has been designed so the following v1.1 features can be added without breaking changes:

Future Feature Schema Extension Required Why It Works Today
Cloud Sync Add sync_status and last_synced_at columns; add remote_id column UUID primary keys avoid ID collisions. Soft deletes support conflict resolution.
Recurring Invoices Add recurrence_rule table (document_id, frequency, next_run_date) Documents table is self-contained; recurrence references an existing document as a template.
Multi-Currency UI work only; currency_code column already exists on documents Currency is stored per-document, so mixed-currency invoices already work at the data layer.
Expense Tracking Add expenses table (id, business_id, category, amount, date, receipt_path) Completely additive; no changes to existing tables.
Revenue Dashboard Query layer only (SUM/GROUP BY on documents and payments) All necessary data (totals, dates, statuses, payments) already exists.
Multiple Businesses Remove single-row assumption in app logic business_id FK already exists on clients and documents.
Custom PDF Templates Add templates table (id, name, html_template, is_default) Additive table; documents reference template_id.

3. MVP Feature Specifications

Each feature is specified with its screen behavior, data flow, business rules, and acceptance criteria. Features are grouped by the build phase in which they should be implemented.

3.1 Business Profile Setup (Onboarding)

3.1.1 Screen Behavior

  • First-launch flow: user sees a single-screen form to enter their business details.
  • Required field: Business Name only. All other fields are optional but encouraged.
  • Logo picker: tap a placeholder to select an image from the device gallery. Crop to square, save to app directory.
  • Currency selector: dropdown defaulting to device locale currency. Sets businesses.default_currency.
  • Tax rate field: numeric input with helper text showing format (e.g., 8.25%).
  • "Save & Start" button creates the businesses row and navigates to the Invoice Dashboard.
  • Accessible later from Settings to edit.

3.1.2 Data Flow

  • INSERT into businesses table.
  • Set app_settings key 'onboarding_complete' = 'true'.
  • Logo image saved to local file system; logo_path column stores the path.

3.1.3 Acceptance Criteria

  • App does not show main UI until onboarding is complete.
  • Business name appears on all generated PDFs immediately after setup.
  • Logo appears on PDFs if provided; placeholder text if not.

3.2 Invoice Dashboard (Home Screen)

3.2.1 Screen Behavior

  • Top summary bar: 4 stat cards showing total Outstanding, Overdue, Paid (this month), and Draft count.
  • Below: scrollable list of all invoices, newest first.
  • Each list item shows: invoice number, client name, total amount, due date, and a colored status pill (Draft = gray, Sent = blue, Paid = green, Overdue = red, Partial = orange).
  • Filter chips at top of list: All, Draft, Sent, Overdue, Paid. Tapping a chip filters the list.
  • Floating Action Button (FAB): "+ New Invoice" opens the Invoice Creator.
  • Tap any invoice to open it in read mode with Edit, Share, and Delete actions.
  • Bottom navigation bar: Invoices (active), Estimates, Clients, Settings.

3.2.2 Data Flow

  • Query: SELECT * FROM documents WHERE document_type = 'invoice' AND is_deleted = 0 ORDER BY created_at DESC.
  • Summary stats: aggregate queries on documents table filtered by status and current month.
  • Overdue detection: on app foreground, run UPDATE documents SET status = 'overdue' WHERE due_date < date('now') AND status IN ('sent', 'partial') AND amount_due > 0.

3.2.3 Acceptance Criteria

  • Dashboard loads in under 200ms with 100 invoices in the database.
  • Status pills update in real-time when an invoice is edited or a payment is recorded.
  • Overdue invoices are flagged within 1 second of the app returning to the foreground.

3.3 Invoice Creator

3.3.1 Screen Behavior

  • Single scrollable screen (no multi-step wizard).
  • Client selector: searchable dropdown of saved clients. "+ New Client" inline option opens a bottom sheet.
  • Invoice number: auto-generated from businesses.invoice_prefix + next_invoice_number. Editable.
  • Date fields: Issue Date (defaults to today) and Due Date (defaults to today + default_payment_terms_days).
  • Line items section: each row has Description, Quantity, Rate fields. Running line total on the right. "+ Add Item" button appends a new row. Swipe-to-delete on each row.
  • Totals section: live-updating Subtotal, Tax (with toggle to override business default rate), Discount (toggle between percentage and fixed amount), and Grand Total.
  • Notes field: multi-line text for payment terms or messages.
  • Action bar: "Save as Draft" and "Save & Share" buttons.

3.3.2 Data Flow

  • On save: INSERT into documents (document_type = 'invoice') and INSERT line_items rows.
  • Increment businesses.next_invoice_number.
  • "Save & Share" sets status = 'sent' and opens the share sheet (see PDF Export feature).
  • All monetary calculations happen in cents at the application layer.

3.3.3 Business Rules

  • Free tier: if active invoice count >= 3 in current calendar month, show paywall before allowing creation.
  • Invoice number must be unique; if user edits the auto-number, validate before save.
  • At least one line item is required to save.
  • Quantity must be > 0. Rate can be 0 (for "no charge" line items).

3.3.4 Acceptance Criteria

  • Creating an invoice with 5 line items takes under 60 seconds for a familiar user.
  • Grand total updates within 100ms of any field change.
  • Saving works entirely offline.

3.4 Client Manager

3.4.1 Screen Behavior

  • Alphabetically sorted list of all active clients.
  • Each list item shows: client name, email, and outstanding balance.
  • Tap a client to view their detail page: contact info, total invoiced, total paid, outstanding balance, and a list of all their documents.
  • FAB: "+ New Client" opens the client creation form.
  • Client form: Name (required), Email, Phone, Address fields, Notes.
  • Edit and delete (soft) available from detail page.

3.4.2 Business Rules

  • Free tier: if active (non-deleted) client count >= 2, show paywall on "+ New Client" tap.
  • Deleting a client soft-deletes (is_deleted = 1). Their invoices remain visible.
  • Outstanding balance is updated whenever an invoice for this client is saved, paid, or voided.

3.4.3 Acceptance Criteria

  • Client auto-fill in invoice creator works by typing 2+ characters of the name.
  • Outstanding balance is always accurate to the cent.

3.5 PDF Export & Sharing

3.5.1 Screen Behavior

  • "Share" button on any invoice or estimate opens a PDF preview, then the system share sheet.
  • Share sheet allows sending via WhatsApp, email, SMS, or any installed app.
  • PDF is generated locally using the Dart pdf package. No server required.

3.5.2 PDF Layout

  • Header: business logo (left), business name and contact info (right).
  • Document title: "INVOICE" or "ESTIMATE" with document number and status.
  • Bill To: client name and address block.
  • Dates: Issue Date and Due Date / Expiry Date.
  • Line items table: Description, Qty, Rate, Amount columns.
  • Totals block: Subtotal, Tax, Discount, Total Due.
  • Footer: notes/terms text.
  • Watermark (free tier only): small "Created with SwiftInvoice" text in footer.

3.5.3 Business Rules

  • Free tier: PDF includes watermark. Pro/Lifetime: no watermark.
  • Sharing an invoice automatically sets its status to 'sent' if currently 'draft'.
  • PDF file is cached locally for re-sharing without regeneration.

3.6 Estimate Maker (Pro Feature)

3.6.1 Screen Behavior

  • Identical form layout to Invoice Creator.
  • Uses estimate_prefix and next_estimate_number for numbering (EST-001).
  • Due Date field labeled as "Valid Until" (expiry date).
  • "Convert to Invoice" button available on accepted estimates: creates a new invoice document copying all fields and line items, sets estimate status to 'converted', and populates converted_from_id.

3.6.2 One-Tap Conversion Logic

  1. Deep-copy the estimate's document row with document_type = 'invoice', status = 'draft', new UUID, new invoice number.
  2. Deep-copy all line_items pointing to the new document_id.
  3. Set the original estimate's status to 'converted'.
  4. Set new invoice's converted_from_id to the estimate's id.
  5. Navigate to the new invoice for final review before saving.

3.6.3 Acceptance Criteria

  • Converting a 10-line-item estimate to an invoice completes in under 500ms.
  • All line item data is preserved; user does not re-enter anything.
  • Converted estimate shows a visual indicator linking to its invoice.

3.7 Payment Tracker (Pro Feature)

3.7.1 Screen Behavior

  • On an invoice detail screen, a "Record Payment" button opens a bottom sheet.
  • Fields: Amount (defaults to amount_due), Payment Method (dropdown), Date (defaults to today), Notes (optional).
  • Payment history list shown below the invoice details with all recorded payments.
  • "Mark as Paid" shortcut: records a payment for the full remaining balance.

3.7.2 Data Flow

  • INSERT into payments table.
  • UPDATE documents: amount_paid = SUM(payments.amount), amount_due = total - amount_paid.
  • If amount_due = 0, set status = 'paid'. If amount_due > 0 and amount_paid > 0, set status = 'partial'.
  • UPDATE client's outstanding_balance cache.

3.7.3 Acceptance Criteria

  • Partial payments correctly track remaining balance.
  • Payment cannot exceed amount_due (validate before save).
  • Deleting a payment reverses the amount_paid and status updates.

3.8 Overdue Reminders (Pro Feature)

3.8.1 Behavior

  • Uses flutter_local_notifications to schedule a local notification on invoice due_date.
  • Notification text: "Invoice [INV-001] for [Client Name] is overdue. Tap to view."
  • Tapping the notification deep-links to the invoice detail screen.
  • If an invoice is marked paid before the due date, cancel the scheduled notification.
  • No backend or push notification service required.

3.8.2 Acceptance Criteria

  • Notification fires at 9:00 AM local time on the day after the due date.
  • Notification is cancelled when the invoice is paid or voided.
  • Works entirely offline.

3.9 In-App Purchase & Paywall

3.9.1 Paywall Trigger Points

  • Trigger 1: User attempts to create their 4th invoice in a calendar month.
  • Trigger 2: User attempts to add a 3rd client.
  • Never shown on app launch, on a timer, or as a pop-up ad.

3.9.2 Paywall Screen

  • Three plan cards displayed side by side (or stacked on small screens):
    • Monthly: $3.99/month
    • Yearly: $29.99/year ("Save 37%" badge)
    • Lifetime: $49.99 one-time ("Best Value" badge)
  • Feature comparison list below the cards.
  • "Restore Purchases" link at the bottom.
  • Dismiss button (X) allows the user to go back without purchasing.

3.9.3 Technical Implementation

  • RevenueCat SDK (purchases_flutter) handles purchase flow, receipt validation, and subscription status.
  • Subscription status cached in app_settings ('subscription_tier': 'free' | 'pro' | 'lifetime').
  • On app launch: check RevenueCat for current entitlement status and sync to local cache.
  • All tier-gating logic reads from the local cache for instant, offline-capable checks.

3.9.4 Acceptance Criteria

  • Purchase completes and unlocks Pro within 3 seconds.
  • Restore Purchases works on a fresh install / new device.
  • Free tier limits are enforced even when offline (cached tier value).

3.10 Offline-First Architecture

3.10.1 Design

  • All data stored in a single SQLite database via Drift ORM.
  • Database file location: app documents directory (platform-managed, backed up by OS).
  • No API calls for any core feature (invoicing, clients, PDF generation, payments).
  • Only network-dependent features: in-app purchase validation, future cloud sync.

3.10.2 Acceptance Criteria

  • With airplane mode on, user can create a client, create an invoice, generate a PDF, and share via email draft — all without error.
  • Database survives app update without data loss.
  • Database size stays under 50MB with 1,000 invoices and 200 clients.

4. Build Timeline

The build is organized into 9 weekly sprints at 510 hours per week. Each sprint has defined deliverables and a clear definition of done.

Week Sprint Focus Key Deliverables Definition of Done
12 Foundation Flutter project scaffold with folder structure; Drift ORM database with all MVP tables; Navigation shell (bottom nav, routing); Business profile onboarding screen Onboarding flow creates a business row. Navigation between all 4 tabs works. Database migrations run clean.
35 Core Invoicing Invoice Creator (single-screen form); Client Manager (CRUD + search); Invoice Dashboard with status filters; Real-time total calculation User can create a client, create an invoice with 3+ line items, and see it on the dashboard with correct status.
6 PDF & Sharing PDF generation with business branding; Watermark logic (free vs Pro); System share sheet integration; WhatsApp deep-link sharing Generated PDF looks professional, includes logo, and can be shared via WhatsApp and email.
7 Pro Features Estimate flow with conversion logic; Payment tracker with partial payments; Overdue push notifications Estimate converts to invoice in one tap. Payments update balances. Notifications fire on overdue date.
8 Monetization RevenueCat integration; Paywall screen with 3 plan options; Free tier limit enforcement; Restore purchases flow Free tier blocks 4th invoice and 3rd client. Purchase unlocks Pro. Restore works on fresh install.
9 Polish & Launch UI polish and animations; App Store screenshots and descriptions; Beta testing (TestFlight + Play internal); Store submission App passes both store review processes. No crashes in 48-hour beta soak test.

5. Tech Stack Reference

Layer Technology Version Purpose
Framework Flutter 3.x (latest stable) Cross-platform UI
Language Dart 3.x Application logic
Local Database SQLite via Drift 2.x Offline-first data persistence
PDF Generation pdf (pub.dev) Latest Client-side PDF rendering
State Management Riverpod 2.x Reactive state, dependency injection
Notifications flutter_local_notifications Latest Overdue reminders
In-App Purchases purchases_flutter (RevenueCat) Latest Subscription management
iOS CI/CD Codemagic N/A Cloud Mac builds (~$20/build)
Analytics Firebase Analytics Free tier Usage tracking, crash reporting

lib/
  main.dart
  app.dart
  core/
    database/
      database.dart          # Drift database class
      tables/                # Table definitions (1 file per table)
      daos/                  # Data Access Objects (1 per entity)
    models/                  # Shared data models / enums
    services/                # Business logic services
    utils/                   # Formatters, validators, helpers
    theme/                   # Material 3 theme, colors, typography
  features/
    onboarding/              # Business profile setup
    invoices/                # Dashboard, creator, detail
    estimates/               # Estimate list, creator, detail
    clients/                 # Client list, form, detail
    payments/                # Payment recording widgets
    pdf/                     # PDF template and generation logic
    paywall/                 # Paywall screen, tier logic
    settings/                # App settings screen
  shared/                    # Shared widgets (status pills, etc.)

7. Key Risks & Mitigations

Risk Likelihood Impact Mitigation
iOS App Store rejection Medium High Strictly follow Apple HIG. Test on simulator before submission. Budget 1 week for review iteration.
Lifetime tier cannibalizes subs Medium Medium Price at 12.5× monthly ($49.99). Run lifetime discounts only during events. Monitor conversion ratios monthly.
Drift ORM schema migration issues Low High Write migration tests. Keep schema clean from day one. Use stepByStep migrations.
RevenueCat integration complexity Medium Medium Use RevenueCat's Flutter sample app as reference. Test sandbox purchases extensively.
PDF rendering inconsistencies Low Medium Test on 10+ device sizes. Use fixed-width PDF layout. Cache and preview before sharing.
Low organic downloads at launch High High Prepare Apple Search Ads + Google UAC campaigns targeting competitor keywords. Budget $200500 for first month.

8. Raw SQL Schema Reference

The following SQL can be used as a reference when defining the Drift ORM table classes. While Drift generates SQL from Dart code, this raw SQL serves as the canonical schema definition.

-- ================================================
-- SwiftInvoice MVP Database Schema
-- SQLite / Drift ORM Compatible
-- ================================================

CREATE TABLE businesses (
  id               TEXT PRIMARY KEY,
  name             TEXT NOT NULL,
  email            TEXT,
  phone            TEXT,
  address_line1    TEXT,
  address_line2    TEXT,
  city             TEXT,
  state            TEXT,
  postal_code      TEXT,
  country_code     TEXT DEFAULT 'US',
  tax_number       TEXT,
  logo_path        TEXT,
  default_currency TEXT DEFAULT 'USD',
  default_tax_rate INTEGER DEFAULT 0,
  default_payment_terms_days INTEGER DEFAULT 30,
  invoice_prefix   TEXT DEFAULT 'INV',
  estimate_prefix  TEXT DEFAULT 'EST',
  next_invoice_number  INTEGER DEFAULT 1,
  next_estimate_number INTEGER DEFAULT 1,
  created_at       TEXT NOT NULL,
  updated_at       TEXT NOT NULL
);

CREATE TABLE clients (
  id                  TEXT PRIMARY KEY,
  business_id         TEXT NOT NULL REFERENCES businesses(id),
  name                TEXT NOT NULL,
  email               TEXT,
  phone               TEXT,
  address_line1       TEXT,
  address_line2       TEXT,
  city                TEXT,
  state               TEXT,
  postal_code         TEXT,
  country_code        TEXT,
  notes               TEXT,
  outstanding_balance INTEGER DEFAULT 0,
  is_deleted          INTEGER DEFAULT 0,
  created_at          TEXT NOT NULL,
  updated_at          TEXT NOT NULL
);

CREATE TABLE documents (
  id                TEXT PRIMARY KEY,
  business_id       TEXT NOT NULL REFERENCES businesses(id),
  client_id         TEXT NOT NULL REFERENCES clients(id),
  document_type     TEXT NOT NULL CHECK(document_type IN ('invoice','estimate')),
  document_number   TEXT NOT NULL UNIQUE,
  status            TEXT NOT NULL,
  issue_date        TEXT NOT NULL,
  due_date          TEXT,
  currency_code     TEXT DEFAULT 'USD',
  subtotal          INTEGER DEFAULT 0,
  tax_rate          INTEGER DEFAULT 0,
  tax_amount        INTEGER DEFAULT 0,
  discount_type     TEXT CHECK(discount_type IN ('percentage','fixed',NULL)),
  discount_value    INTEGER DEFAULT 0,
  discount_amount   INTEGER DEFAULT 0,
  total             INTEGER DEFAULT 0,
  amount_paid       INTEGER DEFAULT 0,
  amount_due        INTEGER DEFAULT 0,
  notes             TEXT,
  converted_from_id TEXT REFERENCES documents(id),
  is_deleted        INTEGER DEFAULT 0,
  created_at        TEXT NOT NULL,
  updated_at        TEXT NOT NULL
);

CREATE TABLE line_items (
  id            TEXT PRIMARY KEY,
  document_id   TEXT NOT NULL REFERENCES documents(id),
  description   TEXT NOT NULL,
  quantity      REAL NOT NULL DEFAULT 1,
  unit_price    INTEGER NOT NULL,
  amount        INTEGER NOT NULL,
  sort_order    INTEGER DEFAULT 0,
  created_at    TEXT NOT NULL,
  updated_at    TEXT NOT NULL
);

CREATE TABLE payments (
  id            TEXT PRIMARY KEY,
  document_id   TEXT NOT NULL REFERENCES documents(id),
  amount        INTEGER NOT NULL,
  method        TEXT NOT NULL,
  paid_at       TEXT NOT NULL,
  notes         TEXT,
  created_at    TEXT NOT NULL,
  updated_at    TEXT NOT NULL
);

CREATE TABLE app_settings (
  key        TEXT PRIMARY KEY,
  value      TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

-- ================================================
-- Indexes
-- ================================================

CREATE INDEX idx_clients_business ON clients(business_id, is_deleted);
CREATE INDEX idx_documents_client ON documents(client_id, document_type, status);
CREATE INDEX idx_documents_status ON documents(status, due_date);
CREATE INDEX idx_documents_type ON documents(document_type, is_deleted);
CREATE INDEX idx_line_items_doc ON line_items(document_id, sort_order);
CREATE INDEX idx_payments_doc ON payments(document_id);

SwiftInvoice MVP Implementation Plan — Version 1.0 — March 2026