Files
boc/landvex-admin-api/simple.mjs
T

238 lines
9.8 KiB
JavaScript
Raw Normal View History

import express from 'express';
import pg from 'pg';
const { Pool } = pg;
import cors from 'cors';
const app = express();
app.use(cors());
app.use(express.json());
const PORT = 7072;
// PostgreSQL connection
const pool = new Pool({
host: 'localhost',
port: 5432,
database: 'amos',
user: 'postgres',
password: 'quixzo…2026'
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', service: 'landvex-admin-api', port: PORT });
});
// ═══════════════════════════════════════════════════════════════
// QUIXZOOM ENDPOINTS — med rätt kolumnnamn från databasen
// ═══════════════════════════════════════════════════════════════
// GET /api/v1/quixzoom/stats
app.get('/api/v1/quixzoom/stats', async (req, res) => {
try {
const missionsResult = await pool.query('SELECT COUNT(*) FROM quixzoom.missions');
const activeResult = await pool.query("SELECT COUNT(*) FROM quixzoom.missions WHERE status = 'active'");
const submissionsResult = await pool.query('SELECT COUNT(*) FROM quixzoom.submissions');
const usersResult = await pool.query('SELECT COUNT(*) FROM quixzoom.users');
res.json({
missions_total: parseInt(missionsResult.rows[0].count),
missions_active: parseInt(activeResult.rows[0].count),
submissions_total: parseInt(submissionsResult.rows[0].count),
contributors_total: parseInt(usersResult.rows[0].count)
});
} catch (e) {
res.status(500).json({ error: e.message });
}
});
// GET /api/v1/quixzoom/missions
app.get('/api/v1/quixzoom/missions', async (req, res) => {
try {
const { status, limit = 50, offset = 0 } = req.query;
let query = `
SELECT
m.id,
m.title,
m.description,
m.latitude as lat,
m.longitude as lon,
m.status,
m.reward_credits as reward_sek,
m.required_photos,
m.created_at,
m.expires_at,
COUNT(s.id) as submission_count
FROM quixzoom.missions m
LEFT JOIN quixzoom.submissions s ON s.claim_id IN (
SELECT id FROM quixzoom.claims WHERE mission_id = m.id
)
`;
const params = [];
if (status) {
query += ' WHERE m.status = $1';
params.push(status);
}
query += ` GROUP BY m.id ORDER BY m.created_at DESC LIMIT $${params.length + 1} OFFSET $${params.length + 2}`;
params.push(limit, offset);
const result = await pool.query(query, params);
res.json({
missions: result.rows,
count: result.rows.length,
total: parseInt((await pool.query('SELECT COUNT(*) FROM quixzoom.missions')).rows[0].count)
});
} catch (e) {
res.status(500).json({ error: e.message });
}
});
// GET /api/v1/quixzoom/contributors
app.get('/api/v1/quixzoom/contributors', async (req, res) => {
try {
const result = await pool.query(`
SELECT
u.id,
u.email,
u.name,
u.role as status,
u.missions_completed as submission_count,
u.total_earned as total_earnings,
u.credits_balance
FROM quixzoom.users u
ORDER BY u.total_earned DESC
LIMIT 50
`);
res.json({
contributors: result.rows,
count: result.rows.length
});
} catch (e) {
res.status(500).json({ error: e.message });
}
});
// ═══════════════════════════════════════════════════════════════
// LEDGER ENDPOINTS — MOCK (finns ej i databasen än)
// ═══════════════════════════════════════════════════════════════
const MOCK_ACCOUNTS = [
{ id: '1', account_number: '1930', name: 'Företagskonto Nordea', account_type: 'asset', total_debit: 276504, total_credit: 0, balance: 276504 },
{ id: '2', account_number: '2013', name: 'Egna insättningar', account_type: 'liability', total_debit: 0, total_credit: 50000, balance: -50000 },
{ id: '3', account_number: '2017', name: 'Årets resultat', account_type: 'liability', total_debit: 0, total_credit: -350000, balance: 350000 },
{ id: '4', account_number: '3000', name: 'Försäljning', account_type: 'income', total_debit: 0, total_credit: 222916, balance: -222916 },
{ id: '5', account_number: '6100', name: 'Löner', account_type: 'expense', total_debit: 20000, total_credit: 0, balance: 20000 },
{ id: '6', account_number: '6991', name: 'Övriga externa kostnader', account_type: 'expense', total_debit: 150000, total_credit: 0, balance: 150000 },
];
app.get('/api/ledger/accounts', async (req, res) => {
res.json({ ok: true, accounts: MOCK_ACCOUNTS });
});
app.get('/api/ledger/trial-balance', async (req, res) => {
const totalDebit = MOCK_ACCOUNTS.reduce((sum, a) => sum + a.total_debit, 0);
const totalCredit = MOCK_ACCOUNTS.reduce((sum, a) => sum + a.total_credit, 0);
res.json({
ok: true,
rows: MOCK_ACCOUNTS,
total_debit: totalDebit,
total_credit: totalCredit,
balanced: true
});
});
app.get('/api/ledger/journal', async (req, res) => {
res.json({
ok: true,
entries: [
{ entry_number: '1', description: 'Inbetalning från kund', entry_date: '2026-07-01', period: '2026-07', reference: 'FAK-001', lines: [{ account_number: '1930', account_name: 'Företagskonto', debit: 222916, credit: 0 }, { account_number: '3000', account_name: 'Försäljning', debit: 0, credit: 222916 }] },
{ entry_number: '2', description: 'Lön Johan', entry_date: '2026-07-05', period: '2026-07', reference: 'LÖN-001', lines: [{ account_number: '6100', account_name: 'Löner', debit: 20000, credit: 0 }, { account_number: '1930', account_name: 'Företagskonto', debit: 0, credit: 20000 }] },
]
});
});
app.get('/api/ledger/periods', async (req, res) => {
res.json({
ok: true,
periods: [
{ period: '2026-01', fiscal_year: 2026, status: 'closed', closed_at: '2026-02-05' },
{ period: '2026-02', fiscal_year: 2026, status: 'closed', closed_at: '2026-03-05' },
{ period: '2026-03', fiscal_year: 2026, status: 'closed', closed_at: '2026-04-05' },
{ period: '2026-04', fiscal_year: 2026, status: 'closed', closed_at: '2026-05-05' },
{ period: '2026-05', fiscal_year: 2026, status: 'closed', closed_at: '2026-06-05' },
{ period: '2026-06', fiscal_year: 2026, status: 'closed', closed_at: '2026-07-05' },
{ period: '2026-07', fiscal_year: 2026, status: 'open' },
]
});
});
// ═══════════════════════════════════════════════════════════════
// MAIL.AAMOS.SYSTEMS ENDPOINTS — MOCK (finns ej i databasen än)
// ═══════════════════════════════════════════════════════════════
app.get('/api/mail/stats', async (req, res) => {
res.json({
inbox_total: 142,
sent_total: 89,
unread_count: 12
});
});
app.get('/api/mail/messages', async (req, res) => {
const { folder = 'inbox' } = req.query;
const mockMessages = [
{ id: '1', subject: 'Momsdeklaration Q2 2026', sender: 'skatteverket@skatteverket.se', folder: 'inbox', read: false, created_at: '2026-07-06T10:00:00Z' },
{ id: '2', subject: 'Leon kravbrev - svar krävs', sender: 'leon@inkasso.se', folder: 'inbox', read: false, created_at: '2026-07-05T14:30:00Z' },
{ id: '3', subject: 'quiXzoom mission godkänd', sender: 'system@quixzoom.io', folder: 'inbox', read: true, created_at: '2026-07-04T08:15:00Z' },
{ id: '4', subject: 'AWS faktura juni 2026', sender: 'aws@amazon.com', folder: 'inbox', read: true, created_at: '2026-07-03T09:00:00Z' },
{ id: '5', subject: 'Re: Nordea KYC', sender: 'erik.svensson@landvex.com', folder: 'sent', read: true, created_at: '2026-07-02T16:45:00Z' },
];
const filtered = folder === 'all' ? mockMessages : mockMessages.filter(m => m.folder === folder);
res.json({
messages: filtered,
count: filtered.length
});
});
// ═══════════════════════════════════════════════════════════════
// SYSTEM ENDPOINTS
// ═══════════════════════════════════════════════════════════════
app.get('/api/v1/system/services', async (req, res) => {
const services = [
{ name: 'aamos-ledger', port: 3250, status: 'running' },
{ name: 'quixzoom-mission', port: 7060, status: 'running' },
{ name: 'quixzoom-api', port: 8080, status: 'running' },
{ name: 'landvex-api', port: 8081, status: 'running' },
{ name: 'landvex-admin-api', port: 7072, status: 'running' },
{ name: 'mail.aamos.systems', port: 25, status: 'running' },
{ name: 'nginx', port: 80, status: 'running' }
];
res.json({ services });
});
// Start server
app.listen(PORT, '0.0.0.0', () => {
console.log(`LandveX Admin API running on port ${PORT}`);
console.log(`Endpoints:`);
console.log(` GET /api/v1/quixzoom/stats`);
console.log(` GET /api/v1/quixzoom/missions`);
console.log(` GET /api/v1/quixzoom/contributors`);
console.log(` GET /api/ledger/accounts`);
console.log(` GET /api/ledger/trial-balance`);
console.log(` GET /api/ledger/journal`);
console.log(` GET /api/ledger/periods`);
console.log(` GET /api/mail/stats`);
console.log(` GET /api/mail/messages`);
console.log(` GET /api/v1/system/services`);
});