File size: 2,126 Bytes
529090e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { Pool } from 'pg';

export interface DashboardMetrics {
  [key: string]: unknown;
}

export interface VotingAnomaly {
  first_name: string;
  last_name: string;
  party: string;
  rebellion_rate: number;
}

/**
 * THE CIVIC SERVICE (Strand 1 Connector)
 * Formål: Henter politisk intelligens uden at bruge legacy Java-kode.
 */
class CivicService {
  private static instance: CivicService;
  private pool: Pool;

  private constructor() {
    this.pool = new Pool({
      user: process.env.CIVIC_USER || 'civic_reader',
      host: process.env.CIVIC_HOST || 'localhost', // Brug service-navn 'civic-vault' internt i Docker
      database: 'civic_vault',
      password: process.env.CIVIC_PWD || 'secure_civic_access',
      port: 5433, // Porten vi mappede i Docker
    });
    console.log('🏛️ [CivicService] Neural Link established to Civic Node (Strand 1).');
  }

  public static getInstance(): CivicService {
    if (!CivicService.instance) {
      CivicService.instance = new CivicService();
    }
    return CivicService.instance;
  }

  /**
   * Henter "The Big Picture" dashboard data.
   * Baseret på 'view_riksdagen_intelligence_dashboard' fra valideringsrapporten.
   */
  public async getDashboardMetrics(): Promise<DashboardMetrics | null> {
    try {
      const query = `SELECT * FROM view_riksdagen_intelligence_dashboard LIMIT 1;`;
      const result = await this.pool.query(query);
      return result.rows[0] || null;
    } catch {
      console.error('⚠️ [CivicService] Could not fetch dashboard. Is the Vault active?');
      return null;
    }
  }

  /**
   * Finder politiske rebeller (Anomalies).
   * Baseret på 'view_riksdagen_voting_anomaly_detection'.
   */
  public async getAnomalies(limit: number = 5): Promise<VotingAnomaly[]> {
    const query = `
      SELECT first_name, last_name, party, rebellion_rate 
      FROM view_riksdagen_voting_anomaly_detection 
      WHERE rebellion_rate > 0.05 
      ORDER BY rebellion_rate DESC 
      LIMIT $1;
    `;
    return (await this.pool.query(query, [limit])).rows;
  }
}

export const civicService = CivicService.getInstance();