{"id":34756100,"url":"https://github.com/e-roy/find-a-flight-school","last_synced_at":"2026-05-25T15:34:55.966Z","repository":{"id":323567886,"uuid":"1092435458","full_name":"e-roy/find-a-flight-school","owner":"e-roy","description":null,"archived":false,"fork":false,"pushed_at":"2025-12-11T03:51:40.000Z","size":16028,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-11T10:32:26.581Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://find-a-flight-school-gamma.vercel.app","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/e-roy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"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":null,"dco":null,"cla":null}},"created_at":"2025-11-08T16:15:39.000Z","updated_at":"2025-12-11T03:51:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/e-roy/find-a-flight-school","commit_stats":null,"previous_names":["e-roy/find-a-flight-school"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/e-roy/find-a-flight-school","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-roy%2Ffind-a-flight-school","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-roy%2Ffind-a-flight-school/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-roy%2Ffind-a-flight-school/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-roy%2Ffind-a-flight-school/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/e-roy","download_url":"https://codeload.github.com/e-roy/find-a-flight-school/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-roy%2Ffind-a-flight-school/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33482305,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T14:31:05.219Z","status":"ssl_error","status_checked_at":"2026-05-25T14:31:02.878Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":"2025-12-25T05:40:38.644Z","updated_at":"2026-05-25T15:34:55.961Z","avatar_url":"https://github.com/e-roy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Flight School Marketplace\n\nA marketplace platform where students can search, compare, and contact flight schools. Schools can claim and manage their profiles, while admins operate the crawl/normalize pipeline and moderate data.\n\n## Tech Stack\n\n- **Framework:** Next.js 16 (App Router) + TypeScript (strict mode)\n- **API:** tRPC v11 for interactive calls; REST route handlers for workers/cron\n- **Database:** PostgreSQL (Neon/Supabase) + Drizzle ORM + pgvector\n- **Crawl/Extract:** Firecrawl API\n- **Validation:** Zod\n- **Authentication:** NextAuth.js (Auth.js) v5 + Postgres adapter\n- **UI:** Tailwind CSS + shadcn/ui\n- **LLM:** Vercel AI SDK (OpenAI-compatible)\n- **Email:** Resend\n- **Package Manager:** pnpm\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js 18+\n- pnpm installed globally (`npm install -g pnpm`)\n- PostgreSQL database (Neon, Supabase, or self-hosted)\n\n### Installation\n\n1. Clone the repository:\n\n```bash\ngit clone \u003crepository-url\u003e\ncd find-a-flight-school\n```\n\n2. Install dependencies:\n\n```bash\npnpm install\n```\n\n3. Set up environment variables:\n   Create a `.env.local` file in the root directory with the following variables:\n\n```env\nDATABASE_URL=postgresql://user:password@host:port/database\nFIRECRAWL_API_KEY=your_firecrawl_api_key\nOPENAI_API_KEY=your_openai_api_key\nRESEND_API_KEY=your_resend_api_key\nNEXTAUTH_SECRET=your_nextauth_secret\nNEXTAUTH_URL=http://localhost:3000\nWEBHOOK_BASE_URL=local_only_for_firecrawl\n```\n\n4. Set up the database:\n\n```bash\n# Generate migrations\npnpm db:generate\n\n# Push schema to database\npnpm db:push\n\n# Or run migrations\npnpm db:migrate\n```\n\n5. Run the development server:\n\n```bash\npnpm dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) in your browser.\n\n## Project Structure\n\n```\n.\n├── app/                          # Next.js App Router\n│   ├── (public)/                # Public routes (landing, search, saved, compare)\n│   ├── (marketplace)/           # Marketplace routes (school profiles)\n│   ├── (auth)/                  # Authentication routes\n│   ├── admin/                   # Admin dashboard (RBAC: admin role)\n│   ├── portal/                  # School portal (RBAC: school role)\n│   ├── claim/                   # School claim flow\n│   └── api/                     # API routes (REST + tRPC)\n├── components/                  # React components\n│   ├── ui/                      # shadcn/ui components\n│   ├── marketplace/              # Marketplace components\n│   ├── schools/                 # School profile components\n│   ├── portal/                  # Portal components\n│   └── admin/                   # Admin components\n├── lib/                         # Utility libraries\n│   ├── trpc/                    # tRPC setup\n│   ├── db.ts                    # Database client\n│   ├── auth.ts                  # NextAuth configuration\n│   ├── rbac.ts                  # Role-based access control\n│   └── ...                      # Other utilities\n├── server/                      # tRPC routers\n│   └── routers/                 # Domain-specific routers\n├── db/                          # Database schema\n│   └── schema/                  # Drizzle schema definitions\n└── types/                       # TypeScript type definitions\n```\n\n## Key Features\n\n### Public Marketplace\n\n- **Search \u0026 Filter:** Search flight schools with URL-synced filters\n- **School Profiles:** Detailed school information with evidence panels and tier badges\n- **Compare:** Compare up to 4 schools side-by-side\n- **Saved Schools:** Save favorite schools for quick access\n- **Contact Forms:** Submit inquiries directly to schools\n\n### School Portal\n\n- **Profile Management:** Claim and edit school profiles\n- **Lead Management:** View and manage inbound inquiries\n- **Analytics:** Track views, CTR, and match appearances\n\n### Admin Dashboard\n\n- **Data Operations:** Manage crawl queue, normalization, and deduplication\n- **Moderation:** Review and approve fact submissions\n- **Seed Management:** Upload and resolve seed candidates\n- **Snapshots:** View historical data snapshots\n- **Match Testing:** Test and refine matching algorithms\n\n## Available Scripts\n\n- `pnpm dev` - Start development server\n- `pnpm build` - Build for production\n- `pnpm start` - Start production server\n- `pnpm lint` - Run ESLint\n- `pnpm db:generate` - Generate Drizzle migrations\n- `pnpm db:push` - Push schema changes to database\n- `pnpm db:migrate` - Run database migrations\n- `pnpm db:studio` - Open Drizzle Studio\n\n## Authentication \u0026 Authorization\n\nThe application uses NextAuth.js with role-based access control (RBAC):\n\n- **Roles:** `user`, `school`, `admin`\n- **Protected Routes:**\n  - `/admin/**` - Requires `admin` role\n  - `/portal/**` - Requires `school` role\n- **Middleware:** Automatically redirects unauthorized users to `/sign-in` or `/403`\n\n## Database Schema\n\nKey tables:\n\n- `schools` - Canonical school records\n- `facts` - Append-only fact records with provenance\n- `sources` - Source tracking (FAA, Places, Crawl, Claim, Manual)\n- `snapshots` - Historical website snapshots\n- `crawl_queue` - Crawl job queue\n- `leads` - Marketplace contact leads\n- `saved_schools` - User favorites\n- `comparisons` - Compare sets\n- `user_profiles` - User roles and preferences\n- `claims` - School claim requests\n\n## API Architecture\n\n- **tRPC:** Used for interactive UI calls (search, mutations, queries)\n- **REST Routes:** Used for workers, cron jobs, and background tasks\n- **Validation:** All inputs validated with Zod schemas\n- **Type Safety:** End-to-end type safety with tRPC\n\n### Testing Firecrawl\n\nUse ngrok to set up a url to point to localhost. This url will need to be used in the env `WEBHOOK_BASE_URL` to locally receive webhooks\n\n[https://www.sitepoint.com/use-ngrok-test-local-site/](https://www.sitepoint.com/use-ngrok-test-local-site/)\n\nRun this command to setup the connection\n\n```\nngrok http http://localhost:3000\n```\n\n## Learn More\n\n- [Next.js Documentation](https://nextjs.org/docs)\n- [tRPC Documentation](https://trpc.io)\n- [Drizzle ORM Documentation](https://orm.drizzle.team)\n- [NextAuth.js Documentation](https://next-auth.js.org)\n\n## License\n\n[Add your license here]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fe-roy%2Ffind-a-flight-school","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fe-roy%2Ffind-a-flight-school","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fe-roy%2Ffind-a-flight-school/lists"}