A GoCanvas-like field forms platform for professionals. Create form templates, fill them offline on mobile, sync data, and generate professional PDFs.
- Backend: Node.js 20 + TypeScript + Express
- Database/Auth/Storage: Supabase (Postgres + RLS + Storage)
- Web Admin: React + Vite + TypeScript + Tailwind CSS
- Mobile App: Flutter (Android + iOS)
- PDF Generation: PDFKit (server-side)
- Authentication: Google OAuth via Supabase
- ✅ Google OAuth authentication
- ✅ Multi-tenant architecture (single workspace per user in v1)
- ✅ Drag-and-drop form template builder
- ✅ Field types: Text, Number, Checkbox, Toggle, Dropdown, Date/Time, Notes, Signature, Photo
- ✅ Offline-first mobile submissions
- ✅ Draft auto-save
- ✅ Background sync
- ✅ Professional PDF generation
- ✅ Supabase Storage integration
- ✅ Row-level security (RLS)
onsite-forms/
├── server/ # Node.js API
│ ├── src/
│ │ ├── config/
│ │ ├── middleware/
│ │ ├── routes/
│ │ └── services/
│ └── package.json
├── client/ # React web admin
│ ├── src/
│ │ ├── components/
│ │ ├── pages/
│ │ ├── services/
│ │ └── store/
│ └── package.json
├── mobile/ # Flutter app
│ ├── lib/
│ │ ├── models/
│ │ ├── providers/
│ │ ├── screens/
│ │ ├── services/
│ │ └── widgets/
│ └── pubspec.yaml
└── supabase/
└── migrations/
- Node.js 20+
- Flutter 3.0+
- Supabase account
- Create a new Supabase project
- Run migrations from
supabase/migrations/ - Enable Google OAuth in Supabase Auth settings
- Create storage buckets:
submission-photos,submission-pdfs,company-logos
cd server
npm install
# Create .env file
cat > .env << EOF
PORT=3000
NODE_ENV=development
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
CORS_ORIGIN=http://localhost:5173
EOF
# Run in development
npm run dev
# Build for production
npm run build
npm startcd client
npm install
# Create .env file
cat > .env << EOF
VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
VITE_API_URL=http://localhost:3000/api
EOF
# Run in development
npm run dev
# Build for production
npm run buildcd mobile
flutter pub get
# Run on device/emulator
flutter run \
--dart-define=SUPABASE_URL=your_url \
--dart-define=SUPABASE_ANON_KEY=your_key \
--dart-define=API_URL=http://your-api-url/api
# Build for Android
flutter build apk --release
# Build for iOS
flutter build ios --release- Handled by Supabase OAuth
GET /api/user/me- Get current user profilePATCH /api/user/me- Update user profile
GET /api/templates- List templatesGET /api/templates/:id- Get templatePOST /api/templates- Create templatePUT /api/templates/:id- Update templateDELETE /api/templates/:id- Delete templatePOST /api/templates/:id/duplicate- Duplicate template
GET /api/submissions- List submissionsGET /api/submissions/:id- Get submissionPOST /api/submissions- Create submissionPUT /api/submissions/:id- Update submissionDELETE /api/submissions/:id- Delete submissionPOST /api/submissions/:id/pdf- Generate PDF
POST /api/uploads/signed-url- Get signed upload URLPOST /api/uploads/submission-photo- Upload submission photo
user_profiles- User informationworkspaces- User workspacesform_templates- Form templates with fieldssubmissions- Form submissionssubmission_photos- Attached photos
submission-photos- Photo uploadssubmission-pdfs- Generated PDFscompany-logos- Company logos
- Row-level security (RLS) on all tables
- JWT verification on API routes
- Signed URLs for storage uploads
- User can only access their own data
FROM node:20-alpine
WORKDIR /app
COPY server/package*.json ./
RUN npm ci --production
COPY server/ .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]cd client
npm run build
# Deploy dist/ folder to any static host- Android: Upload APK to Google Play Store
- iOS: Upload to App Store Connect
- Create form templates in web admin
- Fill forms on mobile (works offline)
- Sync when online
- Generate PDFs from submissions
- View/download PDFs in web admin
PORT- API port (default: 3000)NODE_ENV- Environment (development/production)SUPABASE_URL- Supabase project URLSUPABASE_ANON_KEY- Supabase anon keySUPABASE_SERVICE_ROLE_KEY- Supabase service role keyCORS_ORIGIN- CORS origin URL
VITE_SUPABASE_URL- Supabase project URLVITE_SUPABASE_ANON_KEY- Supabase anon keyVITE_API_URL- Backend API URL
SUPABASE_URL- Supabase project URLSUPABASE_ANON_KEY- Supabase anon keyAPI_URL- Backend API URL
MIT
For issues and questions, please open a GitHub issue.