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.
- Architecture
- Tech Stack
- Quick Start
- Environment Variables
- Project Structure
- Scripts
- Features
- Public API
- Embed Widget
- Deployment
- Documentation
- Testing
- Contributing
- License
┌─────────────────────────────────────────────────────────────────┐
│ 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.
| 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 |
| 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 |
# 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 devOpen 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.
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 |
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)
| 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) |
PiazzaViva includes 70+ features built across 5 development iterations:
- 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
- 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
- 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
- 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
- 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)
- 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
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.
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.
- Connect your GitHub repository to Vercel
- Set environment variables in the Vercel dashboard
- Build command:
npx prisma generate && next build - The
vercel.jsonis 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
# 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...- Create a Stripe account at stripe.com
- Enable Connect in the Stripe Dashboard
- Create a Connect Application (Express type)
- Set
STRIPE_SECRET_KEY,STRIPE_CONNECT_CLIENT_ID,STRIPE_WEBHOOK_SECRET - Configure webhook endpoint:
https://piazzaviva.it/api/webhooks/stripe
| 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 |
# 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:e2eThe test suite includes 150+ unit tests covering validation, business logic, security, and data transformations.
See CONTRIBUTING.md for development guidelines.
Source code is publicly available. No open-source license has been selected yet.