# Easy Reserveren - Restaurant Reserveringssysteem > Modern, betaalbaar reserveringssysteem voor restaurants met embeddable widget > €69 per jaar | Onbeperkte reserveringen | Real-time beschikbaarheid ## Project Overzicht Easy Reserveren is een volledig functioneel restaurant reserveringssysteem dat bestaat uit: - **Admin Panel**: Beheer van tafels, tijdslots, reserveringen, evenementen en klanten - **Reserveringswidget**: Embeddable widget voor websites waarmee gasten direct kunnen reserveren - **Analytics Dashboard**: Inzicht in bezettingsgraden, piekuren en gastvoorkeuren - **Multi-tenant**: Meerdere restaurants beheren vanuit één account ## Technologie Stack ### Frontend - React 18.3.1 met TypeScript - Vite 5.4.2 als build tool - Tailwind CSS voor styling - Lucide React voor iconografie ### Backend & Database - Supabase (PostgreSQL) met Row Level Security - @supabase/supabase-js 2.57.4 - Real-time synchronisatie voor beschikbaarheid ### Extra Functionaliteiten - jsPDF + jsPDF-AutoTable voor PDF export van reserveringen - Google Maps API integratie (@googlemaps/js-api-loader) - Stripe integratie voor betalingen (Edge Functions) ## Project Structuur ``` /tmp/cc-agent/59988886/project/ ├── src/ │ ├── components/ # React componenten │ │ ├── AdminPanel.tsx # Hoofdbeheer interface │ │ ├── AnalyticsPanel.tsx # Analytics en statistieken │ │ ├── EmbedCodeGenerator.tsx # Widget embed code │ │ ├── LandingPage.tsx # Marketing homepage │ │ ├── LoginPage.tsx # Authenticatie login │ │ ├── ReservationWidget.tsx # Embeddable widget │ │ ├── RestaurantOnboarding.tsx # Setup wizard │ │ ├── SignupPage.tsx # Registratie │ │ └── TimelineView.tsx # Tijdlijn reserveringen │ ├── contexts/ │ │ └── AuthContext.tsx # Auth state management │ ├── lib/ │ │ └── supabase.ts # Supabase client setup │ ├── App.tsx # Main app component │ └── main.tsx # Entry point ├── public/ │ ├── widget.js # Standalone widget script │ ├── test.html # Widget test page │ ├── robots.txt # SEO crawler rules │ ├── sitemap.xml # SEO sitemap │ └── llms.txt # AI indexering (dit bestand) ├── supabase/ │ ├── migrations/ # Database schema migrations │ └── functions/ # Edge Functions │ ├── stripe-checkout/ # Stripe checkout sessie │ └── stripe-webhook/ # Stripe webhook handler └── package.json # Dependencies ``` ## Database Schema ### Core Tables **restaurants** - Restaurant informatie - id (uuid, primary key) - name (text) - address (text) - phone (text) - email (text) - company_name, kvk_number, btw_number (bedrijfsinfo) - subscription_status, subscription_end_date, trial_end_date - stripe_customer_id, stripe_subscription_id - created_at, updated_at **tables** - Tafels - id (uuid, primary key) - restaurant_id (uuid, foreign key) - table_number (text) - capacity (integer) - is_active (boolean) **time_slots** - Openingstijden - id (uuid, primary key) - restaurant_id (uuid, foreign key) - day_of_week (integer, 0-6) - start_time (time) - end_time (time) - slot_duration (integer, minuten) - is_active (boolean) **reservations** - Reserveringen - id (uuid, primary key) - restaurant_id (uuid, foreign key) - table_id (uuid, foreign key) - event_id (uuid, nullable) - customer_name (text) - customer_email (text) - customer_phone (text) - party_size (integer) - reservation_date (date) - reservation_time (time) - status (text: 'pending', 'confirmed', 'seated', 'completed', 'cancelled') - notes (text) - created_at (timestamptz) **events** - Speciale evenementen - id (uuid, primary key) - restaurant_id (uuid, foreign key) - name (text) - description (text) - event_start_date, event_end_date (date) - daily_start_time, daily_end_time (time) - reservation_start_date, reservation_end_date (date) - max_reservation_days_ahead (integer) - color (text, hex) **blocked_dates** - Gesloten datums - id (uuid, primary key) - restaurant_id (uuid, foreign key) - blocked_date (date) - reason (text) **widget_settings** - Widget aanpassing - id (uuid, primary key) - restaurant_id (uuid, foreign key) - primary_color (text, hex) - secondary_color (text, hex) - text_color (text, hex) **user_restaurants** - Multi-tenant relaties - id (uuid, primary key) - user_id (uuid, foreign key naar auth.users) - restaurant_id (uuid, foreign key) - role (text: 'owner', 'admin', 'staff') ### Beveiliging (RLS Policies) Alle tabellen hebben Row Level Security enabled met policies voor: - Authenticated users: volledige CRUD voor eigen restaurants - Anonymous users: alleen SELECT voor widget (restaurants, tables, time_slots, events, blocked_dates) - Multi-tenant isolation via user_restaurants tabel ## API Endpoints ### Supabase Client Queries **Reserveringen ophalen** ```typescript const { data, error } = await supabase .from('reservations') .select('*, tables(*)') .eq('restaurant_id', restaurantId) .order('reservation_date', { ascending: true }); ``` **Beschikbare tijden checken** ```typescript const { data, error } = await supabase .from('time_slots') .select('*') .eq('restaurant_id', restaurantId) .eq('day_of_week', dayOfWeek) .eq('is_active', true); ``` **Nieuwe reservering maken** ```typescript const { data, error } = await supabase .from('reservations') .insert({ restaurant_id, table_id, customer_name, customer_email, customer_phone, party_size, reservation_date, reservation_time, status: 'pending' }); ``` ### Edge Functions **stripe-checkout** - URL: `/functions/v1/stripe-checkout` - Method: POST - Body: `{ priceId: string, restaurantId: string }` - Returns: Stripe checkout session URL **stripe-webhook** - URL: `/functions/v1/stripe-webhook` - Method: POST - Handles: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted - Updates: subscription_status in restaurants table ## Belangrijke Features ### 1. Admin Panel Functionaliteiten - **Tafelbeheer**: CRUD operaties voor tafels met capaciteit - **Tijdslot Planning**: Flexibele openingstijden per weekdag - **Reserveringsbeheer**: Lijst en tijdlijn views, status tracking - **Evenementenbeheer**: Speciale openingstijden voor events - **Geblokkeerde Datums**: Sluitingsdagen beheren - **Klantenbeheer**: Historie en contactinfo - **Widget Instellingen**: Kleurcustomization - **Analytics**: Bezettingsgraden, piekuren, omzet tracking - **PDF Export**: Reserveringsrapporten downloaden ### 2. Reserveringswidget - Stapsgewijze flow: personen → datum → tijd → gegevens → bevestiging - Real-time beschikbaarheid checking - Automatische tafel-toewijzing op basis van party_size - Respect voor events en blocked_dates - Responsive design (mobiel/desktop) - Aanpasbare kleuren via widget_settings - Embeddable via script tag ### 3. Multi-tenant Systeem - Supabase auth.users voor authenticatie - user_restaurants junction tabel voor toegang - Rol-gebaseerde toegang (owner, admin, staff) - Meerdere restaurants per gebruiker - Isolatie via RLS policies ### 4. Subscription Management - 28 dagen gratis trial - Stripe integratie voor betalingen - Automatische status updates via webhooks - Trial tracking met trial_end_date ## SEO & Discoverability ### Meta Tags (index.html) ```html Easy Reserveren - Restaurant Reserveringssysteem €69/jaar ``` ### Structured Data - robots.txt: toegankelijk voor alle crawlers - sitemap.xml: hoofdpagina's en belangrijke routes - llms.txt: dit bestand voor AI-indexering ### Analytics Tracking Elke belangrijke button heeft unieke tracking: - Homepage CTA buttons - Signup/Login buttons - Widget interaction points - Admin panel acties ## Development ### Lokaal Starten ```bash npm install npm run dev ``` ### Environment Variables (.env) ``` VITE_SUPABASE_URL=your_supabase_project_url VITE_SUPABASE_ANON_KEY=your_supabase_anon_key VITE_GOOGLE_MAPS_API_KEY=optional_for_maps ``` ### Build Commands ```bash npm run build # Production build npm run typecheck # TypeScript validatie npm run lint # ESLint check ``` ### Database Migrations Migrations bevinden zich in `supabase/migrations/` en worden automatisch toegepast via Supabase CLI of dashboard. ## Widget Integratie ### Embed Code ```html ``` ### Widget Customization Kleuren worden ingesteld via Admin Panel → Instellingen: - Primary Color: Hoofdkleur voor widget container - Secondary Color: Buttons en accenten - Text Color: Tekstkleur Widget haalt automatisch: - Beschikbare tijdslots - Actieve evenementen - Geblokkeerde datums - Restaurant informatie ## Conventies ### Code Style - TypeScript strict mode - Tailwind CSS utility classes - Lucide React voor alle icons - Componenten in PascalCase - Hooks gebruik voor state management ### Database Conventies - UUID primary keys (gen_random_uuid()) - timestamptz voor timestamps met DEFAULT now() - snake_case voor database velden - RLS enabled op alle tabellen - Foreign keys met ON DELETE CASCADE waar relevant ### Naming Conventions - Componenten: PascalCase (AdminPanel.tsx) - Functions: camelCase (handleSubmit) - Database: snake_case (restaurant_id) - CSS classes: kebab-case (via Tailwind) ## Deployment ### Production Build ```bash npm run build ``` Output: `dist/` folder ### Netlify Configuration - Build command: `npm run build` - Publish directory: `dist` - Redirects: SPA routing via `_redirects` file ### Environment Setup Alle VITE_ prefixed variables moeten ingesteld worden in production environment. ## Support & Contact Voor vragen over dit project: - Check README.md voor uitgebreide documentatie - Database schema in migrations folder - Component documentatie in source files ## Keywords voor AI Discovery restaurant reservation system, reserveringssysteem, tafelbeheer, online reserveren, booking widget, supabase, react, typescript, multi-tenant, stripe payments, restaurant management, table management, event management, analytics dashboard, embeddable widget, affordable reservation system, €69 per year, betaalbaar, Nederlands ## Licentie Privé project - Alle rechten voorbehouden --- Laatst bijgewerkt: 2025-11-19 Versie: 1.0.0