{"id":50695768,"url":"https://github.com/hngprojects/flowbrand-ui","last_synced_at":"2026-06-09T06:08:41.733Z","repository":{"id":357722262,"uuid":"1238167455","full_name":"hngprojects/flowbrand-ui","owner":"hngprojects","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-04T15:45:47.000Z","size":19703,"stargazers_count":0,"open_issues_count":8,"forks_count":5,"subscribers_count":0,"default_branch":"dev","last_synced_at":"2026-06-04T16:07:48.495Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hngprojects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-13T21:58:50.000Z","updated_at":"2026-06-03T23:57:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hngprojects/flowbrand-ui","commit_stats":null,"previous_names":["hngprojects/flowbrand-ui"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hngprojects/flowbrand-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fflowbrand-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fflowbrand-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fflowbrand-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fflowbrand-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hngprojects","download_url":"https://codeload.github.com/hngprojects/flowbrand-ui/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hngprojects%2Fflowbrand-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34093841,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-09T06:08:40.931Z","updated_at":"2026-06-09T06:08:41.719Z","avatar_url":"https://github.com/hngprojects.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SEIL — Guided Marketing Strategy for African SMBs\n\n\u003e **Turn your business story into a step-by-step marketing funnel in under 3 minutes.**\n\nSEIL is a web-based marketing operations tool built for small and medium-sized business owners in Sub-Saharan Africa who have no prior marketing experience. It walks users through three phases — collect, generate, and guide — producing a personalised marketing funnel and a weekly execution plan they can act on immediately.\n\n![Seil](public/images/seil.png)\n\n---\n\n## Table of Contents\n\n- [Product Overview](#product-overview)\n- [The Problem](#the-problem)\n- [Core Features](#core-features)\n- [Tech Stack](#tech-stack)\n- [Architecture](#architecture)\n- [Project Structure](#project-structure)\n- [API Reference](#api-reference)\n- [Getting Started](#getting-started)\n- [Environment Variables](#environment-variables)\n- [Authentication Flow](#authentication-flow)\n- [Known Issues \u0026 Status](#known-issues--status)\n- [Contributing](#contributing)\n- [Team](#team)\n\n---\n\n## Product Overview\n\nSEIL removes the barrier between \"I don't know marketing\" and \"I have a complete funnel and action plan.\" It does this through three sequential phases:\n\n| Phase        | Description                                                                        | Target Time     |\n| ------------ | ---------------------------------------------------------------------------------- | --------------- |\n| **Collect**  | 3 plain-English intake questions about the business, or upload a business document | 30 seconds      |\n| **Generate** | AI analyses intake answers and creates a personalised marketing funnel             | Under 3 seconds |\n| **Guide**    | Walk the owner through each funnel stage week by week with checklists              | Ongoing         |\n\n**Target users:** SMB owners aged 25–45 in Nigeria and Sub-Saharan Africa, solo entrepreneurs, and non-marketing business owners who need a done-for-you framework.\n\n---\n\n## The Problem\n\n96% of SMBs in Sub-Saharan Africa lack structured marketing systems. Existing tools like HubSpot and Mailchimp are expensive (₦15,000+/month), built for dedicated marketing teams, and assume prior marketing knowledge. SEIL is built specifically for a sole trader running their entire business from an Android phone.\n\n---\n\n## Core Features\n\n### MVP v2.0 (In Scope)\n\n- **Email + password authentication** — sign up, log in, session management, email verification, password reset\n- **Google OAuth 2.0** — one-click sign in with Google\n- **Intake wizard** — 3 guided questions with auto-save after every interaction, or business document upload (PDF, DOCX, PPT — max 5MB, up to 3 files)\n- **AI-powered funnel generation** — personalised marketing strategy from awareness to conversion\n- **Stage execution dashboard** — Stages 1 through 4 with per-stage checklists\n- **CTA lock system** — next stage unlocks only when all checklist items for the current stage are completed\n- **One funnel per user account**\n- **Mobile-first layout** — 375px minimum viewport, 44×44px minimum tap targets\n\n### Out of Scope (MVP)\n\n- CRM or campaign management\n- Multi-channel marketing automation\n- Paid subscription billing\n- Multiple funnels per user\n- WhatsApp/Instagram API integrations\n- Multi-language support (English only)\n- Team/multi-user accounts\n\n---\n\n## Tech Stack\n\n| Layer            | Technology                                                 |\n| ---------------- | ---------------------------------------------------------- |\n| Frontend         | Next.js 15 (App Router), TypeScript, Tailwind CSS v4       |\n| Backend          | NestJS, TypeScript                                         |\n| Database         | PostgreSQL (primary), Redis (session cache, rate limiting) |\n| Authentication   | Custom JWT, bcrypt (cost factor 12), NextAuth.js           |\n| State Management | Zustand, TanStack Query v5                                 |\n| HTTP Client      | Axios (server actions), native fetch (API routes)          |\n| Email            | Resend SMTP                                                |\n| File Upload      | Multipart form — max 5MB per file, 3 files per upload      |\n| Hosting          | Vercel (frontend), Railway/Render (backend + DB)           |\n\n---\n\n## Architecture\n\nSEIL's frontend follows a strict 4-layer request pattern. No component ever calls the backend directly.\n\n```\nLayer 1 — UI Component\n    React components render UI and call hooks only.\n    No HTTP logic lives here.\n          ↓\nLayer 2 — TanStack Query Hook\n    useQuery (reads) and useMutation (writes) manage\n    caching, loading state, error state, and polling.\n          ↓\nLayer 3 — Server Action  (src/actions/)\n    \"use server\" functions run on the Next.js server.\n    They attach the Bearer token and make HTTP calls via axios.\n    Always return { ok: true, data } or { ok: false, error }.\n          ↓\nLayer 4 — Backend REST API  (NestJS)\n    Receives authenticated requests, queries PostgreSQL,\n    returns JSON. Documented in Swagger.\n```\n\nThe frontend also exposes a small set of **Next.js API Route files** (`src/app/api/`) for cases that require a real HTTP endpoint — Google OAuth callback, waitlist proxy, and health check. These sit outside the 4-layer pattern and are called by the browser directly via `fetch`.\n\n---\n\n## Project Structure\n\n```\nflowbrand-ui/\n├── public/                         # Static assets served at root\n├── scripts/                        # Dev/build utility scripts\n└── src/\n    ├── app/                        # Next.js App Router — pages and API routes\n    │   ├── (main)/                 # Route group for authenticated app shell\n    │   ├── api/                    # API route handlers (BFF layer)\n    │   │   ├── oauth/google/callback/  # Google OAuth callback handler\n    │   │   ├── onboarding/         # Onboarding proxy route\n    │   │   ├── waitlist/           # Waitlist proxy route\n    │   │   └── health/             # Health check endpoint\n    │   ├── onboarding/             # Onboarding page routes\n    │   ├── error.tsx               # Global error boundary\n    │   ├── layout.tsx              # Root layout\n    │   ├── loading.tsx             # Root loading state\n    │   ├── not-found.tsx           # 404 page\n    │   ├── forbidden.tsx           # 403 page\n    │   ├── unauthorized.tsx        # 401 page\n    │   ├── robots.ts               # Robots.txt generation\n    │   └── sitemap.ts              # Sitemap generation\n    │\n    ├── actions/                    # Next.js server actions\n    │   ├── auth.ts                 # Authentication endpoints\n    │   ├── funnels.ts              # Funnel generation and stages\n    │   ├── onboarding.ts           # Onboarding session management\n    │   └── contact.ts              # Contact form submission\n    │\n    ├── components/                 # Reusable UI components organised by domain\n    │   ├── auth/                   # Login, signup, and auth flow components\n    │   ├── dashboard/              # Dashboard layout and widgets\n    │   ├── features/               # Feature-specific composite components\n    │   ├── icons/                  # Icon components\n    │   ├── landing/                # Marketing/landing page components\n    │   ├── modals/                 # Modal dialogs\n    │   ├── navigation/             # Nav bars, sidebars, breadcrumbs\n    │   ├── providers/              # React context and query providers\n    │   ├── settings/               # Settings page components\n    │   ├── ui/                     # Base UI primitives (shadcn/ui)\n    │   └── waitlist/               # Waitlist signup components\n    │\n    ├── config/                     # App-wide configuration\n    │   ├── env.config.ts           # Centralised environment variable access\n    │   └── auth.config.ts          # NextAuth configuration\n    │\n    ├── constants/                  # App-wide constant values\n    │\n    ├── features/                   # Self-contained feature modules\n    │\n    ├── hooks/                      # Custom React hooks\n    │   ├── queries/                # Data-fetching hooks (useQuery)\n    │   │   ├── use-strategy-funnel.ts      # Strategy polling and display\n    │   │   ├── use-onboarding-queries.ts   # Onboarding data queries\n    │   │   └── use-upload-queries.ts       # File upload queries\n    │   └── mutations/              # Data-mutation hooks (useMutation)\n    │       └── use-funnel-mutations.ts     # Funnel mutation actions\n    │\n    ├── lib/                        # Shared utilities and helpers\n    │   ├── auth-api.ts             # Auth response parsers\n    │   ├── funnel-api-types.ts     # Funnel response type parsers\n    │   ├── funnel-query-fns.ts     # Query function bridge\n    │   ├── onboarding-query-fns.ts # Onboarding query functions\n    │   ├── funnel-generation-storage.ts    # sessionStorage management\n    │   └── stage-progress-storage.ts       # localStorage stage progress\n    │\n    ├── schema/                     # Zod validation schemas\n    │   ├── auth.schema.ts          # Auth form schemas\n    │   ├── onboarding.ts           # Onboarding form schemas\n    │   └── contact.schema.ts       # Contact form schema\n    │\n    ├── services/                   # External service integrations\n    │\n    ├── store/                      # Global client state (Zustand)\n    │   └── useOnboardingStore.ts   # Onboarding flow state\n    │\n    ├── types/                      # Shared TypeScript type definitions\n    │\n    └── utils/                      # Pure utility functions\n        ├── auth.ts                 # Auth helper utilities\n        ├── proxy.ts                # Proxy helper utilities\n        └── routes.ts               # Route constants and helpers\n```\n\n---\n\n## API Reference\n\nAll backend endpoints are documented in the live Swagger UI:\n**`https://api.staging.flowbrand.hng14.com/docs#`**\n\n### Auth\n\n| Method | Endpoint                     | Auth | Description                              |\n| ------ | ---------------------------- | ---- | ---------------------------------------- |\n| POST   | `/api/auth/register`         | ❌   | Create a new account                     |\n| POST   | `/api/auth/login`            | ❌   | Email + password login                   |\n| POST   | `/api/auth/send-otp`         | ❌   | Send email verification OTP              |\n| POST   | `/api/auth/verify-otp`       | ❌   | Verify OTP, activate account             |\n| POST   | `/api/auth/resend-otp`       | ❌   | Resend verification OTP                  |\n| POST   | `/api/auth/forgot-password`  | ❌   | Request password reset OTP               |\n| POST   | `/api/auth/verify-reset-otp` | ❌   | Verify reset OTP → returns `reset_token` |\n| POST   | `/api/auth/reset-password`   | ❌   | Set new password using `reset_token`     |\n| POST   | `/api/auth/refresh-token`    | ❌   | Rotate access token                      |\n| POST   | `/api/auth/logout`           | ✅   | Revoke session                           |\n| GET    | `/api/auth/me`               | ✅   | Get current user profile                 |\n| GET    | `/auth/google`               | ❌   | Start Google OAuth flow                  |\n| GET    | `/auth/google/callback`      | ❌   | Google OAuth callback                    |\n| POST   | `/api/auth/google/exchange`  | ❌   | Exchange OAuth code for tokens           |\n\n### Onboarding\n\n| Method | Endpoint                   | Auth | Description                     |\n| ------ | -------------------------- | ---- | ------------------------------- |\n| POST   | `/api/onboarding/start`    | ✅   | Create a new onboarding session |\n| POST   | `/api/onboarding/step`     | ✅   | Save a single step answer       |\n| POST   | `/api/onboarding/complete` | ✅   | Mark onboarding as complete     |\n\n### Funnels\n\n| Method | Endpoint                                  | Auth | Description                           |\n| ------ | ----------------------------------------- | ---- | ------------------------------------- |\n| GET    | `/api/funnels`                            | ✅   | List all funnels (paginated)          |\n| POST   | `/api/funnels/generate`                   | ✅   | Start funnel generation               |\n| GET    | `/api/funnels/generate/stats/{funnelId}`  | ✅   | Poll generation status                |\n| GET    | `/api/funnels/{id}`                       | ✅   | Get full funnel detail                |\n| GET    | `/api/funnels/{id}/stages`                | ✅   | Get all stages summary                |\n| GET    | `/api/funnels/{id}/stages/{stageId}`      | ✅   | Get single stage with tasks           |\n| POST   | `/api/funnels/upload`                     | ✅   | Upload business documents (multipart) |\n| GET    | `/api/funnels/upload/progress/{uploadId}` | ✅   | Poll upload processing status         |\n\n---\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js 18.17+\n- pnpm\n- Access to the staging backend\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/hngprojects/flowbrand-ui.git\ncd flowbrand-ui\n\n# Install dependencies\npnpm install\n\n# Copy the environment template\ncp .env.example .env.local\n```\n\n### Running locally\n\n```bash\npnpm dev\n# App runs on http://localhost:3000\n```\n\n---\n\n## Scripts\n\n| Command          | What it does                     |\n| ---------------- | -------------------------------- |\n| `pnpm dev`       | Dev server                       |\n| `pnpm build`     | Production build (validates env) |\n| `pnpm start`     | Run the production build         |\n| `pnpm lint`      | ESLint                           |\n| `pnpm typecheck` | `tsc --noEmit`                   |\n\n---\n\n### Enabling debug logging\n\nTo see every API request and response logged to the browser console:\n\n```js\n// Paste in browser DevTools console, then reload the page\nsessionStorage.setItem(\"flowbrand_debug\", \"1\");\n\n// To disable\nsessionStorage.removeItem(\"flowbrand_debug\");\n```\n\n---\n\n## Authentication Flow\n\n### Email + Password\n\n```\nRegister → POST /api/auth/register\n        → POST /api/auth/send-otp  (verification email sent)\n        → User enters OTP\n        → POST /api/auth/verify-otp  (account activated, access token returned)\n        → Redirect to onboarding\n```\n\n### Google OAuth\n\n```\nUser clicks \"Sign in with Google\"\n        → GET /auth/google  (backend redirects to Google)\n        → Google redirects to GET /api/oauth/google/callback  (Next.js route)\n        → Route exchanges code → POST /api/auth/google/exchange\n        → NextAuth session created\n        → Redirect to dashboard or onboarding\n```\n\n### Password Reset\n\n```\nUser clicks \"Forgot password?\"\n        → POST /api/auth/forgot-password  { email }\n        → OTP sent to email\n        → POST /api/auth/verify-reset-otp  { email, otp_code }\n        → Returns { reset_token }  — valid for 15 minutes\n        → POST /api/auth/reset-password  { reset_token, password }\n        → Session created, redirect to dashboard\n```\n\n---\n\n## Contributing\n\nThis project is built during the HNG14 internship sprint. All contributions go through pull requests.\n\n### Branch naming\n\n```\nfeature/your-feature-name\nfix/what-youre-fixing\nchore/what-youre-updating\n```\n\n### Before opening a PR\n\n- Run `pnpm run lint` and fix all errors\n- Test on mobile viewport (375px) — this is the primary user viewport\n- Confirm your `.env.local` is pointing at staging\n- Check the Network tab in DevTools — no request should be returning 404\n\n---\n\n## Team\n\nBuilt by the SEIL frontend team during the HNG14 Internship.\n\n| Role               | Responsibility                                                |\n| ------------------ | ------------------------------------------------------------- |\n| Frontend Engineers | Next.js, TanStack Query, component library                    |\n| Backend Engineers  | NestJS, PostgreSQL, REST API                                  |\n| DevOps             | Vercel deployment, Railway/Render backend, environment config |\n| Design             | Figma components, design tokens, mobile-first wireframes      |\n\n---\n\n## License\n\nThis project was built as part of the HNG Internship programme. All rights reserved by the SEIL product team.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhngprojects%2Fflowbrand-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhngprojects%2Fflowbrand-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhngprojects%2Fflowbrand-ui/lists"}