Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Jesus-Puertos/h-ayuntamiento/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Zongolica application uses Supabase (PostgreSQL) for data storage. The database includes tables for user profiles, preferences, routes, badges, favorites, and visitor registration.
All tables use UUID as primary keys and include Row Level Security (RLS) policies for data protection.

Authentication Tables

Supabase provides the auth.users table automatically. User authentication is handled by Supabase Auth with Google OAuth support.

User Tables

user_profiles

Stores user profile information synchronized with Supabase Auth.
CREATE TABLE user_profiles (
  id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  email TEXT NOT NULL,
  full_name TEXT NOT NULL,
  avatar_url TEXT,
  provider TEXT NOT NULL,
  onboarding_completed BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_user_profiles_email ON user_profiles(email);
ColumnTypeDescription
idUUIDPrimary key, references auth.users(id)
emailTEXTUser’s email address
full_nameTEXTUser’s full name
avatar_urlTEXTProfile picture URL (from OAuth)
providerTEXTAuth provider (“google”, “email”)
onboarding_completedBOOLEANWhether user completed onboarding
created_atTIMESTAMPTZProfile creation timestamp
updated_atTIMESTAMPTZLast update timestamp

user_preferences

Stores user preferences collected during onboarding for personalized recommendations.
CREATE TABLE user_preferences (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  experiencia TEXT[] NOT NULL,
  duracion TEXT NOT NULL,
  dificultad TEXT NOT NULL,
  grupo TEXT NOT NULL,
  intereses TEXT[] NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_user_preferences_user_id ON user_preferences(user_id);
ColumnTypeDescription
idUUIDPrimary key (auto-generated)
user_idUUIDReferences auth.users(id)
experienciaTEXT[]Experience types (e.g., [“aventura”, “naturaleza”])
duracionTEXTPreferred duration (“medio-dia”, “dia-completo”, “fin-de-semana”)
dificultadTEXTDifficulty level (“facil”, “moderado”, “dificil”)
grupoTEXTTravel group (“solo”, “pareja”, “familia”, “amigos”)
interesesTEXT[]Specific interests (e.g., [“cascadas”, “miradores”])
created_atTIMESTAMPTZCreation timestamp
Possible Values:
  • experiencia: aventura, naturaleza, cultura, gastronomia, relax
  • duracion: medio-dia, dia-completo, fin-de-semana
  • dificultad: facil, moderado, dificil
  • grupo: solo, pareja, familia, amigos
  • intereses: cascadas, miradores, cuevas, senderismo, rappel, kayak, historia, fotografia

user_routes

Stores user-generated tourism routes with shareable links.
CREATE TABLE user_routes (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  route_name TEXT NOT NULL,
  atractivos TEXT[] NOT NULL,
  ticket_url TEXT NOT NULL,
  share_code TEXT UNIQUE NOT NULL,
  badges TEXT[] DEFAULT '{}',
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_user_routes_user_id ON user_routes(user_id);
CREATE INDEX idx_user_routes_share_code ON user_routes(share_code);
ColumnTypeDescription
idUUIDPrimary key (auto-generated)
user_idUUIDReferences auth.users(id)
route_nameTEXTName given to the route
atractivosTEXT[]Array of attraction slugs
ticket_urlTEXTURL to generated ticket/itinerary
share_codeTEXTUnique shareable code (e.g., “abc123”)
badgesTEXT[]Array of earned badge types
created_atTIMESTAMPTZRoute creation timestamp

user_badges

Stores unlocked achievements/badges for gamification.
CREATE TABLE user_badges (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  badge_type TEXT NOT NULL,
  unlocked_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(user_id, badge_type)
);

CREATE INDEX idx_user_badges_user_id ON user_badges(user_id);
ColumnTypeDescription
idUUIDPrimary key (auto-generated)
user_idUUIDReferences auth.users(id)
badge_typeTEXTBadge identifier (e.g., “aventurero”)
unlocked_atTIMESTAMPTZWhen badge was unlocked
Constraint: UNIQUE(user_id, badge_type) - Each user can only unlock each badge once.

user_favorites

Stores user’s favorite tourist attractions.
CREATE TABLE user_favorites (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  atractivo_slug TEXT NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(user_id, atractivo_slug)
);

CREATE INDEX idx_user_favorites_user_id ON user_favorites(user_id);
ColumnTypeDescription
idUUIDPrimary key (auto-generated)
user_idUUIDReferences auth.users(id)
atractivo_slugTEXTSlug of favorited attraction
created_atTIMESTAMPTZWhen favorite was added
Constraint: UNIQUE(user_id, atractivo_slug) - Each attraction can only be favorited once per user.

Visitor Registration (MySQL)

visitantes

Stores visitor registration data (pre-registration and on-site check-ins).
This table uses MySQL (not Supabase), typically hosted with shared hosting or phpMyAdmin.
CREATE TABLE visitantes (
  id INT AUTO_INCREMENT PRIMARY KEY,
  token CHAR(64) NOT NULL UNIQUE,
  nombre VARCHAR(80) NOT NULL,
  apellidos VARCHAR(120) NULL,
  email VARCHAR(190) NULL,
  telefono VARCHAR(24) NULL,
  lugar VARCHAR(120) NULL,
  pais VARCHAR(120) NULL,
  estado VARCHAR(120) NULL,
  municipio VARCHAR(120) NULL,
  edad TINYINT NULL,
  genero ENUM('M','F','X','NA') NOT NULL DEFAULT 'NA',
  foto_url TEXT NULL,
  source ENUM('pre','sitio') NOT NULL DEFAULT 'pre',
  check_in_at DATETIME NULL,
  check_in_by INT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  email_status ENUM('pending','sent','failed') NULL,
  email_sent_at DATETIME NULL,
  email_error VARCHAR(255) NULL,
  INDEX idx_created_at (created_at),
  INDEX idx_check_in_at (check_in_at),
  CONSTRAINT fk_checkin_admin FOREIGN KEY (check_in_by) REFERENCES admins(id)
    ON UPDATE CASCADE ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ColumnTypeDescription
idINTPrimary key (auto-increment)
tokenCHAR(64)Unique visitor token
nombreVARCHAR(80)First name
apellidosVARCHAR(120)Last name
emailVARCHAR(190)Email address
telefonoVARCHAR(24)Phone number
lugarVARCHAR(120)Origin location
paisVARCHAR(120)Country
estadoVARCHAR(120)State/province
municipioVARCHAR(120)Municipality
edadTINYINTAge
generoENUMGender (M/F/X/NA)
foto_urlTEXTPhoto URL
sourceENUMRegistration source (pre/sitio)
check_in_atDATETIMECheck-in timestamp
check_in_byINTAdmin who performed check-in
created_atDATETIMERegistration timestamp
email_statusENUMEmail delivery status
email_sent_atDATETIMEWhen email was sent
email_errorVARCHAR(255)Email error message

Storage Buckets

tickets

Supabase Storage bucket for ticket/itinerary images and PDFs.
INSERT INTO storage.buckets (id, name, public)
VALUES ('tickets', 'tickets', true)
ON CONFLICT (id) DO NOTHING;
Configuration:
  • Public: Yes (all tickets are publicly accessible)
  • Max file size: 5MB
  • Allowed types: image/*, application/pdf

Database Functions

get_user_stats()

Utility function to retrieve user statistics.
CREATE OR REPLACE FUNCTION get_user_stats(user_uuid UUID)
RETURNS JSON AS $$
DECLARE
  result JSON;
BEGIN
  SELECT json_build_object(
    'total_routes', (SELECT COUNT(*) FROM user_routes WHERE user_id = user_uuid),
    'total_badges', (SELECT COUNT(*) FROM user_badges WHERE user_id = user_uuid),
    'latest_route', (SELECT route_name FROM user_routes WHERE user_id = user_uuid ORDER BY created_at DESC LIMIT 1),
    'created_at', (SELECT created_at FROM user_routes WHERE user_id = user_uuid ORDER BY created_at ASC LIMIT 1)
  ) INTO result;
  
  RETURN result;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Usage:
SELECT get_user_stats('a1b2c3d4-e5f6-7890-abcd-ef1234567890');

Verification Queries

Check Tables

SELECT table_name 
FROM information_schema.tables 
WHERE table_schema = 'public' 
AND table_name IN ('user_preferences', 'user_routes', 'user_badges', 'user_favorites');

Check Indexes

SELECT tablename, indexname 
FROM pg_indexes 
WHERE schemaname = 'public';

Check RLS Policies

SELECT schemaname, tablename, policyname 
FROM pg_policies 
WHERE tablename IN ('user_preferences', 'user_routes', 'user_badges', 'user_favorites');

Build docs developers (and LLMs) love