nordabiz/database/migrations/002_digital_maturity_foundation.sql
2026-01-01 14:01:49 +01:00

270 lines
10 KiB
SQL

-- ============================================================
-- Digital Maturity Assessment Platform - Foundation
-- Migration 002: ETAP 1 - Core Tables
-- ============================================================
-- Created: 2025-11-26
-- Description:
-- - Extends companies table with digital maturity fields
-- - Creates company_digital_maturity (dashboard/composite scores)
-- - Creates company_website_analysis (website & online presence)
-- - Creates maturity_assessments (historical tracking)
--
-- Usage:
-- PostgreSQL: psql -h localhost -U nordabiz_app -d nordabiz -f 002_digital_maturity_foundation.sql
-- SQLite: sqlite3 nordabiz_local.db < 002_digital_maturity_foundation.sql
-- ============================================================
-- ============================================================
-- 1. EXTEND companies TABLE
-- ============================================================
ALTER TABLE companies ADD COLUMN IF NOT EXISTS digital_maturity_last_assessed TIMESTAMP;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS digital_maturity_score INTEGER;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS digital_maturity_rank_category INTEGER;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS digital_maturity_rank_overall INTEGER;
-- AI Readiness (basic fields)
ALTER TABLE companies ADD COLUMN IF NOT EXISTS ai_enabled BOOLEAN DEFAULT FALSE;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS ai_tools_used TEXT[]; -- PostgreSQL array, TEXT for SQLite
ALTER TABLE companies ADD COLUMN IF NOT EXISTS data_structured BOOLEAN DEFAULT FALSE;
-- IT Management
ALTER TABLE companies ADD COLUMN IF NOT EXISTS it_manager_exists BOOLEAN DEFAULT FALSE;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS it_outsourced BOOLEAN DEFAULT FALSE;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS it_provider_company_id INTEGER REFERENCES companies(id);
-- Website tracking
ALTER TABLE companies ADD COLUMN IF NOT EXISTS website_last_analyzed TIMESTAMP;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS website_status VARCHAR(20);
ALTER TABLE companies ADD COLUMN IF NOT EXISTS website_quality_score INTEGER;
COMMENT ON COLUMN companies.digital_maturity_score IS 'Composite score 0-100 across all digital maturity areas';
COMMENT ON COLUMN companies.website_quality_score IS 'Website quality score 0-100';
-- ============================================================
-- 2. CREATE company_digital_maturity TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS company_digital_maturity (
id SERIAL PRIMARY KEY,
company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- === COMPOSITE SCORES (0-100 each) ===
overall_score INTEGER,
online_presence_score INTEGER,
social_media_score INTEGER,
it_infrastructure_score INTEGER,
business_applications_score INTEGER,
backup_disaster_recovery_score INTEGER,
cybersecurity_score INTEGER,
ai_readiness_score INTEGER,
digital_marketing_score INTEGER,
-- === GAPS & OPPORTUNITIES ===
critical_gaps TEXT[], -- Array of strings
improvement_priority VARCHAR(20), -- 'critical', 'high', 'medium', 'low'
estimated_investment_needed NUMERIC(10, 2),
-- === BENCHMARKING ===
rank_in_category INTEGER,
rank_overall INTEGER,
percentile INTEGER, -- top X% of companies
-- === SALES INTELLIGENCE ===
total_opportunity_value NUMERIC(10, 2),
sales_readiness VARCHAR(20), -- 'hot', 'warm', 'cold', 'not_ready'
-- Constraints
UNIQUE(company_id)
);
CREATE INDEX IF NOT EXISTS idx_digital_maturity_company ON company_digital_maturity(company_id);
CREATE INDEX IF NOT EXISTS idx_digital_maturity_updated ON company_digital_maturity(last_updated);
CREATE INDEX IF NOT EXISTS idx_digital_maturity_overall_score ON company_digital_maturity(overall_score);
COMMENT ON TABLE company_digital_maturity IS 'Central dashboard for company digital maturity - composite scores and benchmarking';
-- ============================================================
-- 3. CREATE company_website_analysis TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS company_website_analysis (
id SERIAL PRIMARY KEY,
company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
analyzed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- === BASIC INFO ===
website_url VARCHAR(500),
final_url VARCHAR(500), -- After redirects
http_status_code INTEGER,
load_time_ms INTEGER,
-- === TECHNICAL ===
has_ssl BOOLEAN DEFAULT FALSE,
ssl_expires_at DATE,
is_responsive BOOLEAN DEFAULT FALSE, -- mobile-friendly
cms_detected VARCHAR(100),
frameworks_detected TEXT[], -- ['WordPress', 'Bootstrap', etc.]
-- === CONTENT RICHNESS ===
content_richness_score INTEGER, -- 1-10
page_count_estimate INTEGER,
word_count_homepage INTEGER,
has_blog BOOLEAN DEFAULT FALSE,
has_portfolio BOOLEAN DEFAULT FALSE,
has_contact_form BOOLEAN DEFAULT FALSE,
has_live_chat BOOLEAN DEFAULT FALSE,
-- === EXTRACTED CONTENT ===
content_summary TEXT, -- AI-generated summary from website
services_extracted TEXT[], -- Services mentioned on website
main_keywords TEXT[], -- Top keywords
-- === SEO ===
seo_title VARCHAR(500),
seo_description TEXT,
has_sitemap BOOLEAN DEFAULT FALSE,
has_robots_txt BOOLEAN DEFAULT FALSE,
google_indexed_pages INTEGER,
-- === DOMAIN ===
domain_registered_at DATE,
domain_expires_at DATE,
domain_age_years INTEGER,
-- === ANALYTICS ===
has_google_analytics BOOLEAN DEFAULT FALSE,
has_google_tag_manager BOOLEAN DEFAULT FALSE,
has_facebook_pixel BOOLEAN DEFAULT FALSE,
-- === OPPORTUNITY SCORING ===
needs_redesign BOOLEAN DEFAULT FALSE,
missing_features TEXT[], -- ['blog', 'portfolio', 'ssl', etc.]
opportunity_score INTEGER, -- 0-100
estimated_project_value NUMERIC(10, 2), -- PLN
opportunity_notes TEXT
);
CREATE INDEX IF NOT EXISTS idx_website_analysis_company ON company_website_analysis(company_id);
CREATE INDEX IF NOT EXISTS idx_website_analysis_date ON company_website_analysis(analyzed_at);
CREATE INDEX IF NOT EXISTS idx_website_analysis_opportunity ON company_website_analysis(opportunity_score);
COMMENT ON TABLE company_website_analysis IS 'Detailed website and online presence analysis';
COMMENT ON COLUMN company_website_analysis.content_summary IS 'AI-extracted summary of what the company does based on website';
COMMENT ON COLUMN company_website_analysis.opportunity_score IS 'Sales opportunity score 0-100 for website redesign/improvement';
-- ============================================================
-- 4. CREATE maturity_assessments TABLE (Historical Tracking)
-- ============================================================
CREATE TABLE IF NOT EXISTS maturity_assessments (
id SERIAL PRIMARY KEY,
company_id INTEGER NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
assessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
assessed_by_user_id INTEGER REFERENCES users(id),
assessment_type VARCHAR(50), -- 'full', 'quick', 'self_reported', 'audit'
-- === SNAPSHOT OF SCORES ===
overall_score INTEGER,
online_presence_score INTEGER,
social_media_score INTEGER,
it_infrastructure_score INTEGER,
business_applications_score INTEGER,
backup_dr_score INTEGER,
cybersecurity_score INTEGER,
ai_readiness_score INTEGER,
-- === CHANGES SINCE LAST ASSESSMENT ===
score_change INTEGER, -- +5, -3, etc.
areas_improved TEXT[], -- ['cybersecurity', 'backup']
areas_declined TEXT[], -- ['social_media']
notes TEXT
);
CREATE INDEX IF NOT EXISTS idx_maturity_assessments_company ON maturity_assessments(company_id);
CREATE INDEX IF NOT EXISTS idx_maturity_assessments_date ON maturity_assessments(assessed_at);
COMMENT ON TABLE maturity_assessments IS 'Historical tracking of digital maturity scores over time';
-- ============================================================
-- 5. CREATE HELPER VIEWS
-- ============================================================
-- View: Companies with low digital maturity (potential clients)
CREATE OR REPLACE VIEW v_low_maturity_companies AS
SELECT
c.id,
c.name,
c.slug,
c.category_id,
cat.name as category_name,
c.website,
dm.overall_score,
dm.critical_gaps,
dm.total_opportunity_value,
dm.sales_readiness
FROM companies c
LEFT JOIN company_digital_maturity dm ON c.id = dm.company_id
LEFT JOIN categories cat ON c.category_id = cat.id
WHERE dm.overall_score < 50
ORDER BY dm.overall_score ASC;
COMMENT ON VIEW v_low_maturity_companies IS 'Companies with digital maturity score below 50 - sales opportunities';
-- View: Digital maturity leaderboard
CREATE OR REPLACE VIEW v_maturity_leaderboard AS
SELECT
c.id,
c.name,
c.slug,
cat.name as category_name,
dm.overall_score,
dm.rank_in_category,
dm.rank_overall,
dm.percentile,
dm.last_updated
FROM companies c
LEFT JOIN company_digital_maturity dm ON c.id = dm.company_id
LEFT JOIN categories cat ON c.category_id = cat.id
WHERE dm.overall_score IS NOT NULL
ORDER BY dm.overall_score DESC;
COMMENT ON VIEW v_maturity_leaderboard IS 'Digital maturity rankings - leaderboard for gamification';
-- ============================================================
-- 6. SAMPLE DATA / DEFAULTS
-- ============================================================
-- Initialize digital_maturity records for all existing companies
INSERT INTO company_digital_maturity (company_id, overall_score)
SELECT id, 0 FROM companies
ON CONFLICT (company_id) DO NOTHING;
COMMENT ON TABLE company_digital_maturity IS 'All companies should have a record here, even if scores are 0 initially';
-- ============================================================
-- MIGRATION COMPLETE
-- ============================================================
-- Verify tables created
DO $$
BEGIN
RAISE NOTICE 'Migration 002 completed successfully!';
RAISE NOTICE 'Tables created:';
RAISE NOTICE ' - company_digital_maturity';
RAISE NOTICE ' - company_website_analysis';
RAISE NOTICE ' - maturity_assessments';
RAISE NOTICE 'Views created:';
RAISE NOTICE ' - v_low_maturity_companies';
RAISE NOTICE ' - v_maturity_leaderboard';
END $$;