Skip to content

ForliLabs/piazza-viva

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

130 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PiazzaViva 🏛️

La piattaforma degli eventi di Forlì — scopri, partecipa, organizza.

PiazzaViva is a hyperlocal event discovery and ticketing marketplace for small-to-mid-sized Italian cities, starting with Forlì (pop. 118K). It aggregates manual listings, automated RSS feeds, and AI-enriched content into a unified platform with an interactive map, integrated ticketing, and Stripe Connect payments.

70+ features across 5 development iterations — from a simple event listing to a full marketplace with AI, social signals, demand-driven programming, and venue intelligence.


Table of Contents


Architecture

┌─────────────────────────────────────────────────────────────────┐
│                      Next.js 16 (App Router)                    │
│                                                                 │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌─────────────┐  │
│  │  25 Pages  │  │  67 APIs  │  │ Middleware │  │  SSE/Cron   │  │
│  └─────┬─────┘  └─────┬─────┘  └─────┬─────┘  └──────┬──────┘  │
│        │               │              │                │         │
│  ┌─────┴───────────────┴──────────────┴────────────────┴──────┐  │
│  │                  35 Lib Modules                            │  │
│  │  auth · events · stripe · ai · scrapers · analytics       │  │
│  │  venues · waitlist · verification · monitoring · ...       │  │
│  └───────────────────────┬────────────────────────────────────┘  │
│                          │                                      │
│  ┌───────────────────────┴────────────────────────────────────┐  │
│  │              Prisma ORM (22 Models)                        │  │
│  │    SQLite (dev) ←→ LibSQL Adapter ←→ Turso (prod)          │  │
│  └────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
         │                │               │
    ┌────┴────┐     ┌─────┴────┐    ┌─────┴─────┐
    │  Stripe │     │  OpenAI  │    │  Leaflet  │
    │ Connect │     │  (AI/NLU)│    │  Maps/OSM │
    └─────────┘     └──────────┘    └───────────┘

For a detailed architecture overview with Mermaid diagrams, see docs/ARCHITECTURE.md.

Tech Stack

Layer Technology
Framework Next.js 16, React 19, TypeScript 5
Database Prisma 7.8, SQLite (dev), Turso/LibSQL (prod)
Styling Tailwind CSS 4, CVA, clsx, tailwind-merge
Maps Leaflet + React-Leaflet + OpenStreetMap
Payments Stripe Checkout + Connect (Express)
AI OpenAI API (GPT-4o-mini) with heuristic fallbacks
Email Resend (transactional email)
Testing Vitest (150+ unit tests), Playwright (E2E)
CI/CD GitHub Actions, Vercel (CDG1 region, Paris)
Monitoring Structured JSON logging, metrics pipeline, Sentry-compatible

Quick Start

# 1. Clone and install
git clone https://github.com/forli/piazza-viva.git
cd piazza-viva
npm ci

# 2. Generate Prisma client
npx prisma generate

# 3. Create database and run migrations
npx prisma db push

# 4. Seed with sample data (50+ real Forlì events)
npx tsx prisma/seed.ts

# 5. Start development server
npm run dev

Open http://localhost:3000.

Note: The application runs fully in development mode with SQLite. External services (Stripe, OpenAI, Resend) are optional — the platform gracefully degrades when they are not configured.

Environment Variables

Create a .env file in the project root:

# ── Required ────────────────────────────────────────
DATABASE_URL="file:prisma/dev.db"

# ── Production Database (Turso) ─────────────────────
# TURSO_DATABASE_URL="libsql://your-db.turso.io"
# TURSO_AUTH_TOKEN="your-auth-token"

# ── Stripe (Payments) ──────────────────────────────
# STRIPE_SECRET_KEY="sk_test_..."
# STRIPE_WEBHOOK_SECRET="whsec_..."
# STRIPE_CONNECT_CLIENT_ID="ca_..."

# ── AI (OpenAI) ────────────────────────────────────
# OPENAI_API_KEY="sk-..."
# OPENAI_MODEL="gpt-4o-mini"                  # optional override

# ── Email (Resend) ─────────────────────────────────
# RESEND_API_KEY="re_..."
# EMAIL_FROM="PiazzaViva <noreply@piazzaviva.it>"

# ── Monitoring ─────────────────────────────────────
# SENTRY_DSN="https://..."
# SLACK_ALERT_WEBHOOK="https://hooks.slack.com/..."

# ── Security ──────────────────────────────────────
# CSRF_SECRET="random-32-char-string"
# ADMIN_API_KEY="admin-secret-key"
# API_KEYS="key1,key2,key3"
# CRON_SECRET="cron-secret"

# ── Application ───────────────────────────────────
# NEXT_PUBLIC_BASE_URL="https://piazzaviva.it"
Variable Required Description
DATABASE_URL ✅ Dev Path to local SQLite file
TURSO_DATABASE_URL ✅ Prod Turso LibSQL connection URL
TURSO_AUTH_TOKEN ✅ Prod Turso authentication token
STRIPE_SECRET_KEY Optional Enables paid ticketing
STRIPE_CONNECT_CLIENT_ID Optional Enables organizer payouts
OPENAI_API_KEY Optional Enables AI classification, NLU search, translation
RESEND_API_KEY Optional Enables transactional email
API_KEYS Optional Comma-separated keys for public API access
ADMIN_API_KEY Optional Admin endpoint authentication
CRON_SECRET Optional Cron job authentication

Project Structure

src/
├── app/                       # Next.js App Router
│   ├── api/                   # 67 API route handlers
│   │   ├── admin/             #   Admin: jobs, queue, users
│   │   ├── ai/                #   AI: classify, enhance, search, translate, copilot
│   │   ├── analytics/         #   Funnel tracking, organizer analytics
│   │   ├── connect/           #   Stripe Connect: onboard, payouts, commission
│   │   ├── events/            #   CRUD, search, live status, photos, memory
│   │   ├── public/            #   Public API (API-key auth)
│   │   ├── venues/            #   Venue CRUD, claim, match, availability
│   │   ├── webhooks/stripe/   #   Stripe webhook handler
│   │   └── ...                #   auth, calendar, checkout, cities, comments,
│   │                          #   cron, demand, digest, embed, health, locale,
│   │                          #   notifications, og, onboarding, profile,
│   │                          #   recommendations, reports, scraper, social,
│   │                          #   tickets, upload, verification, waitlist
│   ├── admin/                 # Admin dashboard pages
│   ├── auth/                  # Login / Register
│   ├── dashboard/             # Organizer dashboard
│   ├── events/                # Event listing & detail pages
│   ├── organizers/            # Organizer profiles & onboarding flow
│   ├── venues/                # Venue pages
│   ├── embed/                 # Widget builder page
│   ├── map/                   # Full-screen map view
│   ├── calendar/              # Calendar view
│   ├── demand/                # Event request board
│   ├── feed/                  # Social feed
│   ├── profile/               # User profile
│   ├── tickets/               # User tickets
│   ├── layout.tsx             # Root layout with providers
│   ├── page.tsx               # Landing page
│   ├── error.tsx              # Error boundary
│   ├── not-found.tsx          # 404 page
│   ├── sitemap.ts             # Dynamic sitemap
│   └── robots.ts              # robots.txt
├── components/                # 46 React components
│   ├── event-card.tsx         # Event card with category styling
│   ├── event-map.tsx          # Leaflet map with markers
│   ├── search-bar.tsx         # AI-enhanced search
│   ├── toast.tsx              # Toast notification system
│   ├── error-boundary.tsx     # Client-side error boundary
│   ├── comment-thread.tsx     # Threaded comments
│   ├── ticket-form.tsx        # Ticket purchase form
│   └── ...
├── lib/                       # 35 business logic modules
│   ├── auth.ts                # Session-based auth (PBKDF2)
│   ├── db.ts                  # Prisma client (SQLite/Turso)
│   ├── security.ts            # Rate limiting, CSRF, sanitization
│   ├── validation.ts          # Input validation (zero-dep)
│   ├── events.ts              # Domain event bus (pub/sub)
│   ├── types.ts               # Shared TypeScript types
│   ├── ai.ts                  # OpenAI integration with fallbacks
│   ├── stripe.ts              # Stripe Checkout
│   ├── stripe-connect.ts      # Stripe Connect marketplace
│   ├── tickets.ts             # QR ticketing & check-in
│   ├── venues.ts              # Venue intelligence graph
│   ├── analytics.ts           # Conversion funnel tracking
│   ├── recommendations.ts     # Affinity-based recommendations
│   ├── notifications.ts       # Multi-channel notification orchestrator
│   ├── monitoring.ts          # Metrics, alerting, Sentry
│   ├── observability.ts       # Structured logging, API metrics
│   ├── jobs.ts                # Background job queue
│   ├── calendar.ts            # iCal generation, calendar sync
│   ├── waitlist.ts            # Capacity waitlist & demand signals
│   ├── verification.ts        # Organizer verification tiers
│   ├── scrapers/              # Content scraper pipeline
│   │   ├── index.ts           # Core engine, RSS adapter, dedup
│   │   ├── forlitoday.ts      # ForlìToday RSS adapter
│   │   ├── university.ts      # UniBO campus adapter
│   │   └── municipal.ts       # Comune di Forlì adapter
│   └── ...
├── middleware.ts              # Edge: security headers, CORS, request IDs
└── generated/                 # Prisma generated client
prisma/
├── schema.prisma              # 22 data models
└── seed.ts                    # Database seeder (50+ events)
tests/
├── unit/                      # 150+ unit tests (Vitest)
└── e2e/                       # End-to-end tests (Playwright)

Scripts

Command Description
npm run dev Start development server (hot reload)
npm run build Production build
npm run start Start production server
npm run test Run unit tests (watch mode)
npm run test:run Run unit tests (CI, single run)
npm run test:coverage Run with coverage report
npm run test:e2e Run Playwright E2E tests
npm run lint ESLint
npm run typecheck TypeScript type checking (tsc --noEmit)

Features

PiazzaViva includes 70+ features built across 5 development iterations:

🔍 Discovery & Content

  • Interactive Leaflet map with OpenStreetMap tiles
  • Full-text search with AI-powered natural language understanding
  • Calendar view with date/category filtering
  • RSS scraper pipeline (ForlìToday, UniBO, Comune di Forlì)
  • AI content classification, description enhancement, and IT↔EN translation
  • Venue intelligence graph with claiming and analytics

🎫 Ticketing & Payments

  • QR code tickets with real-time check-in
  • Stripe Checkout for payment processing
  • Stripe Connect (Express) for organizer payouts
  • Tiered commission rates (2%–5%) by verification level
  • Automatic refund handling
  • Italian fattura elettronica data generation

📊 Analytics & Intelligence

  • Full conversion funnel tracking (impression → check-in)
  • Organizer analytics dashboard
  • Channel attribution (WhatsApp, Telegram, organic, etc.)
  • Venue analytics with conversion rates and vibe tags
  • AI-powered event recommendations with category diversity

🤝 Engagement & Social

  • Threaded event comments (1 level deep)
  • Social graph with follow (user, organizer, venue)
  • "Who's going" with opt-in visibility and group RSVPs
  • Social signal ingestion from Telegram/WhatsApp
  • Event memory generation (post-event summaries)
  • Progressive Web App with offline support

🔔 Communications

  • Multi-channel notification orchestrator (email, push, in-app)
  • Per-user notification preferences by category and channel
  • Calendar sync (Google Calendar, Outlook, .ics download)
  • Weekly event digest email
  • Event reminder emails (2 hours before)

🔐 Platform Operations

  • In-memory sliding-window rate limiting with configurable tiers
  • Brute-force login protection with exponential backoff
  • CSRF protection (HMAC-based)
  • Input sanitization (XSS prevention)
  • Content Security Policy, security headers
  • Background job queue with exponential retry
  • Monitoring & alerting pipeline (Slack, Sentry-compatible)
  • Structured JSON logging with request IDs
  • Organizer verification (4 tiers: unverified → featured_partner)
  • Content reporting with auto-escalation (3+ reports → auto-hide)
  • Waitlist with auto-notification and time-limited claims
  • Demand board with pledge-backed event requests
  • Multi-city architecture
  • Embeddable widget with theme support
  • Public REST API (1000 req/hour, API-key authenticated)
  • Dynamic OG image generation
  • SEO sitemap and robots.txt

Public API

PiazzaViva exposes a read-only public API for external integrations. All requests require an API key via the X-API-Key header.

# List events
curl -H "X-API-Key: YOUR_KEY" \
  "https://piazzaviva.it/api/public/events?city=Forlì&category=musica&limit=10"

# List venues
curl -H "X-API-Key: YOUR_KEY" \
  "https://piazzaviva.it/api/public/venues?city=Forlì"

Rate limit: 1000 requests/hour per API key.

For full API documentation, see docs/API.md.

Embed Widget

Add PiazzaViva events to any website:

<iframe
  src="https://piazzaviva.it/api/embed?city=Forlì&limit=5&theme=light"
  width="100%" height="400"
  style="border:none;border-radius:12px"
  title="Eventi a Forlì"
></iframe>

See the widget builder for configuration options.

Deployment

Vercel (Recommended)

  1. Connect your GitHub repository to Vercel
  2. Set environment variables in the Vercel dashboard
  3. Build command: npx prisma generate && next build
  4. The vercel.json is pre-configured with:
    • CDG1 region (Paris) for optimal Italian latency
    • Hourly cron job (/api/cron) for scraping, digests, and job processing
    • Security headers on all API routes

Turso Database Setup

# Install Turso CLI
curl -sSfL https://get.tur.so/install.sh | bash

# Create database in Paris region (closest to Italy)
turso db create piazzaviva --location cdg

# Get connection details
turso db show piazzaviva --url
turso db tokens create piazzaviva

# Set in Vercel:
# TURSO_DATABASE_URL=libsql://piazzaviva-xxx.turso.io
# TURSO_AUTH_TOKEN=eyJhbG...

Stripe Connect Setup

  1. Create a Stripe account at stripe.com
  2. Enable Connect in the Stripe Dashboard
  3. Create a Connect Application (Express type)
  4. Set STRIPE_SECRET_KEY, STRIPE_CONNECT_CLIENT_ID, STRIPE_WEBHOOK_SECRET
  5. Configure webhook endpoint: https://piazzaviva.it/api/webhooks/stripe

Documentation

Document Description
docs/ARCHITECTURE.md Architecture overview with Mermaid diagrams
docs/API.md Full API reference (67 endpoints)
CONTRIBUTING.md Contribution guidelines
LAUNCH-PLAYBOOK.md Launch checklist and playbook

Testing

# Unit tests (watch mode)
npm run test

# Unit tests (single run, CI-friendly)
npm run test:run

# Coverage report
npm run test:coverage

# End-to-end tests
npm run test:e2e

The test suite includes 150+ unit tests covering validation, business logic, security, and data transformations.

Contributing

See CONTRIBUTING.md for development guidelines.

License

Source code is publicly available. No open-source license has been selected yet.

About

Local events discovery for residents, visitors, venues, and organizers in Romagna.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors