eindelijk weer eens een push
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
FROM couchdb
|
||||
COPY serveradmin.ini /opt/couchdb/etc/local.d/
|
||||
COPY allard.txt /opt/couchdb/etc/
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
Step 1
|
||||
======
|
||||
|
||||
kubectl apply -f couchdb.yaml
|
||||
|
||||
step 2
|
||||
======
|
||||
|
||||
kubectl port-forward pod/couchdb-0 5984:5984 -n couchdb
|
||||
|
||||
dan in andere terminal:
|
||||
|
||||
curl -X PUT http://admin:Couchdb01@localhost:5984/_users
|
||||
curl -X PUT http://admin:Couchdb01@localhost:5984/_replicator
|
||||
curl -X PUT http://admin:Couchdb01@localhost:5984/_global_changes
|
||||
{"ok":true}
|
||||
{"ok":true}
|
||||
{"ok":true}
|
||||
|
||||
verify:
|
||||
|
||||
curl http://admin:Couchdb01@localhost:5984/_all_dbs
|
||||
|
||||
check cluster status:
|
||||
|
||||
curl -s -u admin:Couchdb01 https://couchdb-prod.allarddcs.nl/_membership
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install --omit=dev
|
||||
|
||||
COPY server.js ./
|
||||
COPY public/ ./public/
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
# Secret – CouchDB credentials
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: couchdb-credentials
|
||||
namespace: couchdb
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: admin
|
||||
password: Couchdb01
|
||||
url: http://admin:Couchdb01@couchdb.couchdb.svc.cluster.local:5984
|
||||
|
||||
---
|
||||
# Deployment
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: aangifte
|
||||
namespace: couchdb
|
||||
labels:
|
||||
app: aangifte
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: aangifte
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: aangifte
|
||||
spec:
|
||||
containers:
|
||||
- name: aangifte
|
||||
image: allardkrings/aangifte
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: COUCHDB_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: couchdb-credentials
|
||||
key: url
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
|
||||
---
|
||||
# Service
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: aangifte
|
||||
namespace: couchdb
|
||||
spec:
|
||||
selector:
|
||||
app: aangifte
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
|
||||
---
|
||||
# IngressRoute
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: aangifte
|
||||
namespace: couchdb
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`aangifte-prod.allarddcs.nl`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: aangifte
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "aangifte-app",
|
||||
"version": "1.0.0",
|
||||
"description": "Belastingdienst aangifte app with CouchDB backend",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"http-proxy-middleware": "^3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,585 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="nl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Mijn Belastingdienst – Aangifte Inkomstenbelasting 2024</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+3:wght@300;400;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'Source Sans 3', Arial, sans-serif; font-size: 14px; color: #1a1a1a; background: #fff; }
|
||||
|
||||
.top-logo-bar { border-bottom: 1px solid #ccc; padding: 10px 20px; display: flex; justify-content: center; align-items: center; }
|
||||
.logo-placeholder { display: flex; align-items: center; gap: 10px; }
|
||||
.logo-shield { width: 44px; height: 44px; background: #154273; border-radius: 2px; display: flex; align-items: center; justify-content: center; }
|
||||
.logo-shield svg { width: 28px; height: 28px; }
|
||||
.logo-site-name { font-size: 15px; color: #333; font-weight: 400; }
|
||||
|
||||
.main-header { background: #c8daea; padding: 12px 24px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #a8c0d8; }
|
||||
.main-header .app-title { font-size: 20px; font-weight: 700; color: #1a1a1a; }
|
||||
.main-header .user-name { font-size: 18px; font-weight: 700; color: #1a1a1a; }
|
||||
|
||||
.app-body { display: flex; min-height: calc(100vh - 120px); }
|
||||
|
||||
.sidebar { width: 280px; min-width: 280px; border-right: 1px solid #ddd; padding: 20px 0; background: #fff; overflow-y: auto; }
|
||||
.sidebar-title { font-size: 14px; font-weight: 700; color: #1a1a1a; padding: 0 16px 12px 16px; border-bottom: 1px solid #eee; margin-bottom: 8px; }
|
||||
.nav-tree { list-style: none; }
|
||||
.nav-item { display: flex; align-items: center; gap: 6px; padding: 5px 16px; font-size: 13px; color: #1a1a1a; cursor: pointer; line-height: 1.4; }
|
||||
.nav-item:hover { background: #e8f0f8; }
|
||||
.nav-item.active { background: #dce8f5; font-weight: 600; color: #154273; }
|
||||
.nav-item.section-header { font-weight: 600; padding-top: 8px; }
|
||||
.nav-sub { list-style: none; padding-left: 24px; }
|
||||
.nav-sub .nav-item { font-weight: 400; }
|
||||
|
||||
.main-content { flex: 1; padding: 28px 36px; max-width: 820px; }
|
||||
.content-title { font-size: 18px; font-weight: 700; margin-bottom: 4px; }
|
||||
.content-subtitle { font-size: 16px; font-weight: 700; margin-bottom: 20px; color: #1a1a1a; }
|
||||
|
||||
.employer-block { border: 1px solid #ccc; border-radius: 3px; margin-bottom: 24px; background: #fff; }
|
||||
.employer-header { background: #f5f5f5; border-bottom: 1px solid #ccc; padding: 10px 16px; display: flex; align-items: center; justify-content: space-between; cursor: pointer; user-select: none; }
|
||||
.employer-header-left { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 14px; }
|
||||
.collapse-icon { color: #154273; font-size: 12px; font-weight: 700; }
|
||||
.btn-verwijderen { background: none; border: none; color: #154273; font-size: 13px; cursor: pointer; display: flex; align-items: center; gap: 5px; font-family: inherit; text-decoration: underline; }
|
||||
.btn-verwijderen:hover { color: #0f2f52; }
|
||||
.employer-body { padding: 20px; }
|
||||
|
||||
.form-row { display: flex; align-items: flex-start; margin-bottom: 16px; gap: 16px; }
|
||||
.form-label-col { min-width: 200px; font-size: 14px; padding-top: 8px; display: flex; align-items: center; gap: 5px; flex-shrink: 0; }
|
||||
.form-value-col { flex: 1; }
|
||||
|
||||
.help-btn { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border: 1px solid #154273; color: #154273; border-radius: 2px; font-size: 11px; font-weight: 700; cursor: pointer; flex-shrink: 0; background: white; font-family: inherit; }
|
||||
.tooltip { display: none; position: absolute; background: #154273; color: white; padding: 8px 12px; border-radius: 3px; font-size: 12px; max-width: 240px; line-height: 1.5; z-index: 100; box-shadow: 0 2px 8px rgba(0,0,0,0.25); }
|
||||
.tooltip::before { content: ''; position: absolute; top: -6px; left: 12px; border: 6px solid transparent; border-bottom-color: #154273; border-top: none; }
|
||||
.help-container { position: relative; display: inline-block; }
|
||||
.help-container:hover .tooltip { display: block; top: 100%; margin-top: 4px; left: 0; }
|
||||
|
||||
.bd-text-input { width: 100%; max-width: 320px; border: 1px solid #aaa; border-radius: 2px; padding: 6px 10px; font-size: 14px; font-family: inherit; background: #eaf3fb; color: #1a1a1a; }
|
||||
.bd-text-input:focus { outline: none; border-color: #154273; box-shadow: 0 0 0 2px rgba(21,66,115,0.2); }
|
||||
.bd-text-input[readonly] { background: #f0f0f0; color: #555; }
|
||||
|
||||
.money-row { display: flex; gap: 24px; margin-bottom: 16px; align-items: flex-start; }
|
||||
.money-col { display: flex; flex-direction: column; gap: 4px; }
|
||||
.money-label { font-size: 14px; display: flex; align-items: center; gap: 5px; margin-bottom: 4px; }
|
||||
.money-input-wrap { display: flex; align-items: center; border: 1px solid #aaa; border-radius: 2px; background: #eaf3fb; overflow: hidden; width: 130px; }
|
||||
.money-input-wrap .euro-sign { padding: 6px 8px; background: #eaf3fb; font-size: 14px; color: #333; border-right: 1px solid #aaa; flex-shrink: 0; }
|
||||
.money-input-wrap input { border: none; background: #eaf3fb; padding: 6px 8px; font-size: 14px; font-family: inherit; width: 100%; text-align: right; }
|
||||
.money-input-wrap input:focus { outline: none; }
|
||||
|
||||
.sub-section-title { font-size: 14px; font-weight: 700; margin: 20px 0 12px 0; }
|
||||
.radio-row { display: flex; align-items: center; margin-top: 4px; }
|
||||
.radio-option { display: flex; align-items: center; gap: 5px; padding: 5px 12px 5px 0; cursor: pointer; font-size: 14px; }
|
||||
.radio-option input[type="radio"] { accent-color: #154273; width: 15px; height: 15px; }
|
||||
|
||||
.btn-toevoegen { background: none; border: 1px solid #154273; color: #154273; padding: 6px 16px; font-size: 13px; font-family: inherit; border-radius: 2px; cursor: pointer; margin-top: 8px; display: flex; align-items: center; gap: 6px; }
|
||||
.btn-toevoegen:hover { background: #e8f0f8; }
|
||||
|
||||
.bottom-nav { display: flex; gap: 12px; margin-top: 32px; padding-top: 20px; border-top: 1px solid #ddd; align-items: center; }
|
||||
.btn-primary { background: #154273; color: white; border: none; padding: 9px 24px; font-size: 14px; font-weight: 600; font-family: inherit; border-radius: 2px; cursor: pointer; }
|
||||
.btn-primary:hover { background: #1a5296; }
|
||||
.btn-secondary { background: white; color: #154273; border: 1px solid #154273; padding: 8px 20px; font-size: 14px; font-family: inherit; border-radius: 2px; cursor: pointer; }
|
||||
.btn-secondary:hover { background: #e8f0f8; }
|
||||
|
||||
.pension-block { border: 1px solid #ccc; border-radius: 3px; margin-bottom: 16px; background: #fff; }
|
||||
.pension-header { background: #f5f5f5; border-bottom: 1px solid #ccc; padding: 9px 16px; display: flex; align-items: center; justify-content: space-between; cursor: pointer; font-weight: 700; font-size: 13px; }
|
||||
|
||||
.section-tabs { display: none; }
|
||||
.section-tabs.active-section { display: block; }
|
||||
.info-text { font-size: 13px; color: #555; margin-bottom: 16px; line-height: 1.6; }
|
||||
|
||||
.status-bar { font-size: 12px; color: #555; display: flex; align-items: center; gap: 8px; }
|
||||
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: #ccc; flex-shrink: 0; }
|
||||
.status-dot.saved { background: #39870c; }
|
||||
.status-dot.saving { background: #e17000; animation: pulse 1s infinite; }
|
||||
.status-dot.error { background: #d52b1e; }
|
||||
@keyframes pulse { 0%,100% { opacity:1; } 50% { opacity:0.3; } }
|
||||
|
||||
.toast { position: fixed; bottom: 24px; right: 24px; padding: 12px 20px; border-radius: 3px; font-size: 13px; font-weight: 600; box-shadow: 0 4px 16px rgba(0,0,0,0.2); transform: translateY(60px); opacity: 0; transition: all 0.3s ease; z-index: 1000; }
|
||||
.toast.show { transform: translateY(0); opacity: 1; }
|
||||
.toast.success { background: #39870c; color: white; }
|
||||
.toast.error { background: #d52b1e; color: white; }
|
||||
|
||||
@media (max-width: 768px) { .sidebar { display: none; } .main-content { padding: 16px; } .money-row { flex-wrap: wrap; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="top-logo-bar">
|
||||
<div class="logo-placeholder">
|
||||
<div class="logo-shield">
|
||||
<svg viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 2L4 7v7c0 5.5 4.3 10.7 10 12 5.7-1.3 10-6.5 10-12V7L14 2z" fill="white" opacity="0.9"/>
|
||||
<text x="9" y="19" font-size="12" font-weight="bold" fill="#154273" font-family="Arial">BD</text>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="logo-site-name">Belastingdienst</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-header">
|
||||
<span class="app-title">Mijn Belastingdienst</span>
|
||||
<span class="user-name">A C KRINGS</span>
|
||||
</div>
|
||||
|
||||
<div class="app-body">
|
||||
<nav class="sidebar">
|
||||
<div class="sidebar-title">Aangifte Inkomstenbelasting 2024</div>
|
||||
<ul class="nav-tree">
|
||||
<li><span class="nav-item" onclick="showSection('intro')">Introductie</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('persoonlijk')">Persoonlijke gegevens A C KRINGS</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('partner')">Partner</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('vooraf')">Vooraf ingevulde gegevens</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('partner-gegevens')">Persoonlijke gegevens partner</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('kinderen')">Persoonlijke gegevens kinderen</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('onderneming')">Onderneming</span></li>
|
||||
<li>
|
||||
<span class="nav-item section-header" onclick="toggleNav('nav-inkomsten')">
|
||||
<span id="chev-nav-inkomsten">▼</span> Inkomsten
|
||||
</span>
|
||||
<ul class="nav-sub" id="nav-inkomsten">
|
||||
<li><span class="nav-item active" onclick="showSection('loondienst')">Inkomsten uit loondienst</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('pensioen')">Pensioen en andere uitkeringen</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('overige-inkomsten')">Overige inkomsten</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('beschikbaar')">Inkomsten uit beschikbaar gestelde bezittingen</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('partneralimentatie')">Partneralimentatie</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span class="nav-item" onclick="showSection('woningen')">Woningen en andere onroerende zaken</span></li>
|
||||
<li>
|
||||
<span class="nav-item section-header" onclick="toggleNav('nav-bank')">
|
||||
<span id="chev-nav-bank">▲</span> Bankrekeningen en andere bezittingen
|
||||
</span>
|
||||
<ul class="nav-sub" id="nav-bank" style="display:none">
|
||||
<li><span class="nav-item" onclick="showSection('bank')">Bank- en spaarrekeningen</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('aanmerkelijk')">Aanmerkelijk belang</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('beleggingen')">Beleggingen</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('kapitaalverzekeringen')">Kapitaalverzekeringen</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('bouwdepots')">Bouwdepots</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('andere-bezittingen')">Andere bezittingen</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<span class="nav-item section-header" onclick="toggleNav('nav-hypotheken')">
|
||||
<span id="chev-nav-hypotheken">▼</span> Hypotheken en andere schulden
|
||||
</span>
|
||||
<ul class="nav-sub" id="nav-hypotheken">
|
||||
<li><span class="nav-item" onclick="showSection('hypotheken')">Hypotheken en leningen woning</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<span class="nav-item section-header" onclick="toggleNav('nav-uitgaven')">
|
||||
<span id="chev-nav-uitgaven">▲</span> Uitgaven
|
||||
</span>
|
||||
<ul class="nav-sub" id="nav-uitgaven" style="display:none">
|
||||
<li><span class="nav-item" onclick="showSection('lijfrente')">Uitgaven voor lijfrente</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('zorgkosten')">Zorgkosten</span></li>
|
||||
<li><span class="nav-item" onclick="showSection('giften')">Giften</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<main class="main-content">
|
||||
|
||||
<!-- LOONDIENST -->
|
||||
<div id="section-loondienst" class="section-tabs active-section">
|
||||
<div class="content-title">Inkomsten uit loondienst</div>
|
||||
<div class="content-subtitle">A C KRINGS</div>
|
||||
<div class="employer-block" id="employer-0">
|
||||
<div class="employer-header" onclick="toggleEmployer(0)">
|
||||
<div class="employer-header-left">
|
||||
<span class="collapse-icon" id="emp-icon-0">∧</span>
|
||||
Werkgever: MINISTERIE VAN FINANCIEN
|
||||
</div>
|
||||
<button class="btn-verwijderen" onclick="event.stopPropagation()">
|
||||
<span>🗑</span> verwijderen
|
||||
</button>
|
||||
</div>
|
||||
<div class="employer-body" id="emp-body-0">
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Soort inkomsten: <div class="help-container"><button class="help-btn">?</button><div class="tooltip">Het soort inkomsten bepaalt hoe de loonheffing wordt berekend.</div></div></div>
|
||||
<div class="form-value-col"><input class="bd-text-input" type="text" value="Loon binnen Nederland" readonly></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Werkgever: <div class="help-container"><button class="help-btn">?</button><div class="tooltip">De naam van uw werkgever zoals vermeld op uw jaaropgave.</div></div></div>
|
||||
<div class="form-value-col"><input class="bd-text-input" type="text" id="wg0-naam" value="MINISTERIE VAN FINANCIEN"></div>
|
||||
</div>
|
||||
<div class="money-row">
|
||||
<div class="money-col">
|
||||
<div class="money-label">Loon: <div class="help-container"><button class="help-btn">?</button><div class="tooltip">Brutoloon van uw jaaropgave (rubriek 1).</div></div></div>
|
||||
<div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="wg0-loon" value="118231"></div>
|
||||
</div>
|
||||
<div class="money-col">
|
||||
<div class="money-label">Loonheffing: <div class="help-container"><button class="help-btn">?</button><div class="tooltip">Ingehouden loonheffing (rubriek 2).</div></div></div>
|
||||
<div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="wg0-loonheffing" value="41992"></div>
|
||||
</div>
|
||||
<div class="money-col">
|
||||
<div class="money-label">Arbeidskorting: <div class="help-container"><button class="help-btn">?</button><div class="tooltip">Arbeidskorting verrekend door werkgever (rubriek 5).</div></div></div>
|
||||
<div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="wg0-arbeidskorting" value="869"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col" style="align-self:flex-start;padding-top:4px">
|
||||
Andere inkomsten bij deze werkgever waarop geen loonheffing wordt ingehouden (zoals fooien):
|
||||
<div class="help-container" style="margin-left:4px"><button class="help-btn">?</button><div class="tooltip">Bijv. fooien of andere inkomsten die niet op de loonstrook staan.</div></div>
|
||||
</div>
|
||||
<div class="form-value-col" style="padding-top:4px">
|
||||
<div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="wg0-andere" value="0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sub-section-title">Reiskosten MINISTERIE VAN FINANCIEN</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Reisde U met openbaar vervoer naar het werk?: <div class="help-container"><button class="help-btn">?</button><div class="tooltip">U kunt reiskosten aftrekken als u met OV reisde zonder volledige vergoeding.</div></div></div>
|
||||
<div class="form-value-col">
|
||||
<div class="radio-row">
|
||||
<label class="radio-option"><input type="radio" name="reiskosten-0" value="ja"> ja</label>
|
||||
<label class="radio-option"><input type="radio" name="reiskosten-0" value="nee" checked> nee</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-toevoegen">+ Werkgever toevoegen</button>
|
||||
<div class="bottom-nav">
|
||||
<button class="btn-primary" onclick="opslaanEnVolgende('pensioen')">Volgende ▶</button>
|
||||
<button class="btn-secondary" onclick="showSection('vooraf')">◀ Vorige</button>
|
||||
<button class="btn-secondary" onclick="opslaan()">💾 Opslaan</button>
|
||||
<div class="status-bar"><div class="status-dot" id="statusDot"></div><span id="statusText">Niet opgeslagen</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PENSIOEN -->
|
||||
<div id="section-pensioen" class="section-tabs">
|
||||
<div class="content-title">Pensioen en andere uitkeringen</div>
|
||||
<div class="content-subtitle">A C KRINGS</div>
|
||||
<p class="info-text">Controleer de bedragen aan de hand van uw jaaropgaven.</p>
|
||||
<div class="pension-block">
|
||||
<div class="pension-header" onclick="togglePension(this)">
|
||||
<span>∧ Nationale Nederlanden – € 646</span>
|
||||
<button class="btn-verwijderen" onclick="event.stopPropagation()">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="money-row">
|
||||
<div class="money-col"><div class="money-label">Loon:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p0-loon" value="646"></div></div>
|
||||
<div class="money-col"><div class="money-label">Loonheffing:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p0-heffing" value="114"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pension-block">
|
||||
<div class="pension-header" onclick="togglePension(this)">
|
||||
<span>∧ ABP – € 45.926</span>
|
||||
<button class="btn-verwijderen" onclick="event.stopPropagation()">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="money-row">
|
||||
<div class="money-col"><div class="money-label">Loon:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p1-loon" value="45926"></div></div>
|
||||
<div class="money-col"><div class="money-label">Loonheffing:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p1-heffing" value="10149"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pension-block">
|
||||
<div class="pension-header" onclick="togglePension(this)">
|
||||
<span>∧ Nationale Nederlanden – € 472</span>
|
||||
<button class="btn-verwijderen" onclick="event.stopPropagation()">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="money-row">
|
||||
<div class="money-col"><div class="money-label">Loon:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p2-loon" value="472"></div></div>
|
||||
<div class="money-col"><div class="money-label">Loonheffing:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p2-heffing" value="82"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pension-block">
|
||||
<div class="pension-header" onclick="togglePension(this)">
|
||||
<span>∧ UWV – € 13.336</span>
|
||||
<button class="btn-verwijderen" onclick="event.stopPropagation()">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="money-row">
|
||||
<div class="money-col"><div class="money-label">Loon:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p3-loon" value="13336"></div></div>
|
||||
<div class="money-col"><div class="money-label">Loonheffing:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="p3-heffing" value="2538"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-toevoegen">+ Uitkering toevoegen</button>
|
||||
<div class="bottom-nav">
|
||||
<button class="btn-primary" onclick="opslaanEnVolgende('woningen')">Volgende ▶</button>
|
||||
<button class="btn-secondary" onclick="showSection('loondienst')">◀ Vorige</button>
|
||||
<button class="btn-secondary" onclick="opslaan()">💾 Opslaan</button>
|
||||
<div class="status-bar"><div class="status-dot" id="statusDot2"></div><span id="statusText2">Niet opgeslagen</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WONINGEN -->
|
||||
<div id="section-woningen" class="section-tabs">
|
||||
<div class="content-title">Woningen en andere onroerende zaken</div>
|
||||
<div class="content-subtitle">A C KRINGS</div>
|
||||
<div class="employer-block">
|
||||
<div class="employer-header">
|
||||
<div class="employer-header-left">∧ Warnsveld – Postcode 7231GH nr. 42</div>
|
||||
<button class="btn-verwijderen">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Situatie begin jaar:</div>
|
||||
<div class="form-value-col"><input class="bd-text-input" type="text" value="woning: Hoofdverblijf" readonly></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">WOZ-waarde:</div>
|
||||
<div class="form-value-col"><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" id="woz-waarde" value="528000"></div></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Verhuurd in 2024?</div>
|
||||
<div class="form-value-col"><div class="radio-row">
|
||||
<label class="radio-option"><input type="radio" name="verhuurd" value="ja"> ja</label>
|
||||
<label class="radio-option"><input type="radio" name="verhuurd" value="nee" checked> nee</label>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Erfpachtcanon betaald?</div>
|
||||
<div class="form-value-col"><div class="radio-row">
|
||||
<label class="radio-option"><input type="radio" name="erfpacht" value="ja"> ja</label>
|
||||
<label class="radio-option"><input type="radio" name="erfpacht" value="nee" checked> nee</label>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-nav">
|
||||
<button class="btn-primary" onclick="opslaanEnVolgende('hypotheken')">Volgende ▶</button>
|
||||
<button class="btn-secondary" onclick="showSection('pensioen')">◀ Vorige</button>
|
||||
<button class="btn-secondary" onclick="opslaan()">💾 Opslaan</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HYPOTHEKEN -->
|
||||
<div id="section-hypotheken" class="section-tabs">
|
||||
<div class="content-title">Hypotheken en andere schulden</div>
|
||||
<div class="content-subtitle">A C KRINGS</div>
|
||||
<div class="employer-block">
|
||||
<div class="employer-header">
|
||||
<div class="employer-header-left">∧ BijBouwe – nr. 290396101</div>
|
||||
<button class="btn-verwijderen">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="money-row">
|
||||
<div class="money-col"><div class="money-label">Schuld 01-01-2024:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" value="217500"></div></div>
|
||||
<div class="money-col"><div class="money-label">Schuld 31-12-2024:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" value="217500"></div></div>
|
||||
<div class="money-col"><div class="money-label">Rente betaald:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" value="3546"></div></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-label-col">Schuld voor eigen woning?</div>
|
||||
<div class="form-value-col"><div class="radio-row">
|
||||
<label class="radio-option"><input type="radio" name="woning-schuld" value="ja" checked> ja</label>
|
||||
<label class="radio-option"><input type="radio" name="woning-schuld" value="nee"> nee</label>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="employer-block">
|
||||
<div class="employer-header">
|
||||
<div class="employer-header-left">∧ BijBouwe – nr. 290396101 (aflossing)</div>
|
||||
<button class="btn-verwijderen">🗑 verwijderen</button>
|
||||
</div>
|
||||
<div class="employer-body">
|
||||
<div class="money-row">
|
||||
<div class="money-col"><div class="money-label">Schuld 01-01-2024:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" value="88431"></div></div>
|
||||
<div class="money-col"><div class="money-label">Schuld 31-12-2024:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" value="85263"></div></div>
|
||||
<div class="money-col"><div class="money-label">Rente betaald:</div><div class="money-input-wrap"><span class="euro-sign">€</span><input type="number" value="1423"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-toevoegen">+ Lening toevoegen</button>
|
||||
<div class="bottom-nav">
|
||||
<button class="btn-primary" onclick="opslaanEnVolgende('intro')">Opslaan & afronden ▶</button>
|
||||
<button class="btn-secondary" onclick="showSection('woningen')">◀ Vorige</button>
|
||||
<button class="btn-secondary" onclick="opslaan()">💾 Opslaan</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<div id="section-intro" class="section-tabs"><div class="content-title">Introductie</div><p class="info-text" style="margin-top:12px">Welkom bij de aangifte Inkomstenbelasting 2024. Uw gegevens worden opgeslagen in CouchDB.</p><div class="bottom-nav"><button class="btn-primary" onclick="showSection('persoonlijk')">Volgende ▶</button></div></div>
|
||||
<div id="section-persoonlijk" class="section-tabs"><div class="content-title">Persoonlijke gegevens A C KRINGS</div><div style="margin-top:12px"><div class="form-row"><div class="form-label-col">Naam:</div><div class="form-value-col"><input class="bd-text-input" type="text" value="A C KRINGS"></div></div><div class="form-row"><div class="form-label-col">Geboortedatum:</div><div class="form-value-col"><input class="bd-text-input" type="date" value="1956-05-22"></div></div><div class="form-row"><div class="form-label-col">Burgerservicenummer:</div><div class="form-value-col"><input class="bd-text-input" type="text" value="4444444444"></div></div></div><div class="bottom-nav"><button class="btn-primary" onclick="showSection('partner')">Volgende ▶</button></div></div>
|
||||
<div id="section-partner" class="section-tabs"><div class="content-title">Partner</div><div style="margin-top:12px"><div class="form-row"><div class="form-label-col">Naam partner:</div><div class="form-value-col"><input class="bd-text-input" type="text" value="H M A VAN DER POL"></div></div><div class="form-row"><div class="form-label-col">Geboortedatum partner:</div><div class="form-value-col"><input class="bd-text-input" type="date" value="1960-05-15"></div></div><div class="form-row"><div class="form-label-col">Fiscale partner?</div><div class="form-value-col"><div class="radio-row"><label class="radio-option"><input type="radio" name="fiscaal" value="ja" checked> ja</label><label class="radio-option"><input type="radio" name="fiscaal" value="nee"> nee</label></div></div></div></div><div class="bottom-nav"><button class="btn-primary" onclick="showSection('loondienst')">Volgende ▶</button></div></div>
|
||||
<div id="section-vooraf" class="section-tabs"><div class="content-title">Vooraf ingevulde gegevens</div><p class="info-text" style="margin-top:12px">Gegevens zijn vooraf ingevuld vanuit uw werkgever(s) en pensioenuitvoerder(s). Controleer zorgvuldig.</p><div class="bottom-nav"><button class="btn-primary" onclick="showSection('loondienst')">Naar inkomsten ▶</button></div></div>
|
||||
<div id="section-partner-gegevens" class="section-tabs"><div class="content-title">Persoonlijke gegevens partner</div><p class="info-text" style="margin-top:12px">H M A VAN DER POL – BSN: 3333333333</p></div>
|
||||
<div id="section-kinderen" class="section-tabs"><div class="content-title">Persoonlijke gegevens kinderen</div><p class="info-text" style="margin-top:12px">2 kinderen: A M KRINGS (2005) en A C KRINGS (2006).</p></div>
|
||||
<div id="section-onderneming" class="section-tabs"><div class="content-title">Onderneming</div><p class="info-text" style="margin-top:12px">Ondernemer IB: nee. Geldverstrekker: ja.</p></div>
|
||||
<div id="section-overige-inkomsten" class="section-tabs"><div class="content-title">Overige inkomsten</div><p class="info-text" style="margin-top:12px">Geen overige inkomsten opgegeven.</p></div>
|
||||
<div id="section-beschikbaar" class="section-tabs"><div class="content-title">Inkomsten uit beschikbaar gestelde bezittingen</div></div>
|
||||
<div id="section-partneralimentatie" class="section-tabs"><div class="content-title">Partneralimentatie</div></div>
|
||||
<div id="section-bank" class="section-tabs"><div class="content-title">Bank- en spaarrekeningen</div></div>
|
||||
<div id="section-aanmerkelijk" class="section-tabs"><div class="content-title">Aanmerkelijk belang</div></div>
|
||||
<div id="section-beleggingen" class="section-tabs"><div class="content-title">Beleggingen</div></div>
|
||||
<div id="section-kapitaalverzekeringen" class="section-tabs"><div class="content-title">Kapitaalverzekeringen</div></div>
|
||||
<div id="section-bouwdepots" class="section-tabs"><div class="content-title">Bouwdepots</div></div>
|
||||
<div id="section-andere-bezittingen" class="section-tabs"><div class="content-title">Andere bezittingen</div></div>
|
||||
<div id="section-lijfrente" class="section-tabs"><div class="content-title">Uitgaven voor lijfrente</div></div>
|
||||
<div id="section-zorgkosten" class="section-tabs"><div class="content-title">Zorgkosten</div></div>
|
||||
<div id="section-giften" class="section-tabs"><div class="content-title">Giften</div></div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
const DB = '/api/couchdb/aangifte';
|
||||
const DOC_ID = 'aangifte-2024-allard';
|
||||
let currentRev = null;
|
||||
|
||||
async function ensureDb() {
|
||||
await fetch(`${DB}`, { method: 'PUT' });
|
||||
}
|
||||
|
||||
function collectData() {
|
||||
return {
|
||||
_id: DOC_ID,
|
||||
login_naam: 'allard',
|
||||
jaar_aangifte: 2024,
|
||||
naam: 'A C KRINGS',
|
||||
geboortedatum: '1956-05-22',
|
||||
burgerservicenummer: 4444444444,
|
||||
naam_partner: 'H M A VAN DER POL',
|
||||
geboortedatum_partner: '1960-05-15',
|
||||
burgerservicenummer_partner: 3333333333,
|
||||
inkomstenUitLoondienst: [{
|
||||
werkgever: val('wg0-naam'),
|
||||
soortInkomsten: 'loon',
|
||||
loon: num('wg0-loon'),
|
||||
loonheffing: num('wg0-loonheffing'),
|
||||
arbeidskorting: num('wg0-arbeidskorting'),
|
||||
andereInkomsten: num('wg0-andere') || null,
|
||||
reiskosten: document.querySelector('input[name="reiskosten-0"]:checked')?.value === 'ja'
|
||||
}],
|
||||
pensioenEnAndereUitkeringen: [
|
||||
{ verzekeringsmaatschappij: 'Nationale Nederlanden', loon: num('p0-loon'), loonheffing: num('p0-heffing') },
|
||||
{ verzekeringsmaatschappij: 'ABP', loon: num('p1-loon'), loonheffing: num('p1-heffing') },
|
||||
{ verzekeringsmaatschappij: 'Nationale Nederlanden', loon: num('p2-loon'), loonheffing: num('p2-heffing') },
|
||||
{ verzekeringsmaatschappij: 'UWV', loon: num('p3-loon'), loonheffing: num('p3-heffing') },
|
||||
],
|
||||
woningen: [{
|
||||
postcode: '7231GH', huisnummer: 42, woonplaats: 'Warnsveld',
|
||||
woz_waarde: num('woz-waarde'),
|
||||
verhuurd: document.querySelector('input[name="verhuurd"]:checked')?.value === 'ja',
|
||||
erfpachtcanon: document.querySelector('input[name="erfpacht"]:checked')?.value === 'ja',
|
||||
situatie_begin_jaar: 'woning: Hoofdverblijf'
|
||||
}],
|
||||
updated_at: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
async function opslaan() {
|
||||
setStatus('saving', 'Opslaan...');
|
||||
try {
|
||||
await ensureDb();
|
||||
const doc = collectData();
|
||||
if (currentRev) doc._rev = currentRev;
|
||||
const res = await fetch(`${DB}/${DOC_ID}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(doc)
|
||||
});
|
||||
const json = await res.json();
|
||||
if (res.ok) {
|
||||
currentRev = json.rev;
|
||||
setStatus('saved', 'Opgeslagen ✓');
|
||||
showToast('✓ Opgeslagen in CouchDB', 'success');
|
||||
} else {
|
||||
throw new Error(json.reason || res.statusText);
|
||||
}
|
||||
} catch (e) {
|
||||
setStatus('error', 'Fout bij opslaan');
|
||||
showToast('✗ Fout: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function laadDocument() {
|
||||
try {
|
||||
const res = await fetch(`${DB}/${DOC_ID}`);
|
||||
if (res.ok) {
|
||||
const doc = await res.json();
|
||||
currentRev = doc._rev;
|
||||
if (doc.inkomstenUitLoondienst?.[0]) {
|
||||
const w = doc.inkomstenUitLoondienst[0];
|
||||
set('wg0-naam', w.werkgever);
|
||||
set('wg0-loon', w.loon);
|
||||
set('wg0-loonheffing', w.loonheffing);
|
||||
set('wg0-arbeidskorting', w.arbeidskorting);
|
||||
set('wg0-andere', w.andereInkomsten || 0);
|
||||
}
|
||||
const p = doc.pensioenEnAndereUitkeringen || [];
|
||||
if (p[0]) { set('p0-loon', p[0].loon); set('p0-heffing', p[0].loonheffing); }
|
||||
if (p[1]) { set('p1-loon', p[1].loon); set('p1-heffing', p[1].loonheffing); }
|
||||
if (p[2]) { set('p2-loon', p[2].loon); set('p2-heffing', p[2].loonheffing); }
|
||||
if (p[3]) { set('p3-loon', p[3].loon); set('p3-heffing', p[3].loonheffing); }
|
||||
if (doc.woningen?.[0]) set('woz-waarde', doc.woningen[0].woz_waarde);
|
||||
setStatus('saved', 'Geladen uit CouchDB ✓');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Geen bestaand document, nieuw document wordt aangemaakt bij opslaan.');
|
||||
}
|
||||
}
|
||||
|
||||
function val(id) { return document.getElementById(id)?.value || ''; }
|
||||
function num(id) { return parseInt(document.getElementById(id)?.value) || 0; }
|
||||
function set(id, v) { const el = document.getElementById(id); if (el) el.value = v; }
|
||||
|
||||
function setStatus(state, text) {
|
||||
['statusDot','statusDot2'].forEach(id => {
|
||||
const d = document.getElementById(id);
|
||||
if (d) d.className = 'status-dot ' + state;
|
||||
});
|
||||
['statusText','statusText2'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = text;
|
||||
});
|
||||
}
|
||||
|
||||
function showToast(msg, type) {
|
||||
const t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.className = 'toast ' + type + ' show';
|
||||
setTimeout(() => t.classList.remove('show'), 3000);
|
||||
}
|
||||
|
||||
function showSection(id) {
|
||||
document.querySelectorAll('.section-tabs').forEach(s => s.classList.remove('active-section'));
|
||||
const el = document.getElementById('section-' + id);
|
||||
if (el) el.classList.add('active-section');
|
||||
document.querySelectorAll('.nav-item').forEach(n => {
|
||||
n.classList.toggle('active', !!(n.getAttribute('onclick') && n.getAttribute('onclick').includes("'" + id + "'")));
|
||||
});
|
||||
}
|
||||
|
||||
async function opslaanEnVolgende(next) {
|
||||
await opslaan();
|
||||
showSection(next);
|
||||
}
|
||||
|
||||
function toggleNav(id) {
|
||||
const el = document.getElementById(id);
|
||||
const chev = document.getElementById('chev-' + id);
|
||||
const hidden = el.style.display === 'none';
|
||||
el.style.display = hidden ? 'block' : 'none';
|
||||
if (chev) chev.textContent = hidden ? '▼' : '▲';
|
||||
}
|
||||
|
||||
function toggleEmployer(idx) {
|
||||
const body = document.getElementById('emp-body-' + idx);
|
||||
const icon = document.getElementById('emp-icon-' + idx);
|
||||
const hidden = body.style.display === 'none';
|
||||
body.style.display = hidden ? 'block' : 'none';
|
||||
icon.textContent = hidden ? '∧' : '∨';
|
||||
}
|
||||
|
||||
function togglePension(header) {
|
||||
const body = header.nextElementSibling;
|
||||
const span = header.querySelector('span');
|
||||
const hidden = body.style.display === 'none';
|
||||
body.style.display = hidden ? 'block' : 'none';
|
||||
span.textContent = span.textContent.replace(hidden ? '∨' : '∧', hidden ? '∧' : '∨');
|
||||
}
|
||||
|
||||
laadDocument();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
const express = require('express');
|
||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
const PORT = 3000;
|
||||
|
||||
const COUCHDB_URL = process.env.COUCHDB_URL || 'http://admin:Couchdb01@couchdb.couchdb.svc.cluster.local:5984';
|
||||
|
||||
// Proxy /api/couchdb → CouchDB
|
||||
app.use('/api/couchdb', createProxyMiddleware({
|
||||
target: COUCHDB_URL,
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/api/couchdb': '' },
|
||||
on: {
|
||||
error: (err, req, res) => {
|
||||
console.error('CouchDB proxy error:', err.message);
|
||||
res.status(502).json({ error: 'CouchDB unreachable', detail: err.message });
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// Serve static files
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Aangifte app running on port ${PORT}`);
|
||||
console.log(`CouchDB proxy → ${COUCHDB_URL}`);
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
allard
|
||||
@@ -0,0 +1,10 @@
|
||||
FROM golang:1.22-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY main.go .
|
||||
RUN go mod init aangifte && go build -o aangifte .
|
||||
|
||||
FROM alpine:3.19
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/aangifte .
|
||||
EXPOSE 8080
|
||||
CMD ["./aangifte"]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker build -t allardkrings/aangifte:latest .
|
||||
docker push allardkrings/aangifte:latest
|
||||
@@ -0,0 +1,68 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: aangifte
|
||||
namespace: couchdb
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: aangifte
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: aangifte
|
||||
spec:
|
||||
containers:
|
||||
- name: aangifte
|
||||
image: allardkrings/aangifte:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: COUCHDB_URL
|
||||
value: "http://couchdb-lb.couchdb.svc.cluster.local:5984"
|
||||
- name: COUCHDB_USER
|
||||
value: "admin"
|
||||
- name: COUCHDB_PASS
|
||||
value: "Couchdb01"
|
||||
- name: COUCHDB_DB
|
||||
value: "aangiftes"
|
||||
- name: LISTEN_ADDR
|
||||
value: ":8080"
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "200m"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: aangifte
|
||||
namespace: couchdb
|
||||
spec:
|
||||
selector:
|
||||
app: aangifte
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: aangifte-ingress
|
||||
namespace: couchdb
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`aangifte-dev.allarddcs.nl`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: aangifte
|
||||
port: 8080
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
Executable
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,415 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config
|
||||
var (
|
||||
couchdbURL = getEnv("COUCHDB_URL", "http://10.152.183.59:5984")
|
||||
couchdbUser = getEnv("COUCHDB_USER", "admin")
|
||||
couchdbPass = getEnv("COUCHDB_PASS", "Couchdb01")
|
||||
dbName = getEnv("COUCHDB_DB", "aangiftes")
|
||||
listenAddr = getEnv("LISTEN_ADDR", ":8080")
|
||||
)
|
||||
|
||||
func getEnv(key, def string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// Data structures
|
||||
type CouchDate struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (c *CouchDate) UnmarshalJSON(b []byte) error {
|
||||
s := strings.Trim(string(b), `"`)
|
||||
if s == "null" || s == "" {
|
||||
return nil
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
c.Time = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c CouchDate) MarshalJSON() ([]byte, error) {
|
||||
if c.Time.IsZero() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(`"` + c.Time.Format(time.RFC3339) + `"`), nil
|
||||
}
|
||||
|
||||
func (c CouchDate) String() string {
|
||||
if c.Time.IsZero() {
|
||||
return ""
|
||||
}
|
||||
return c.Time.Format("2006-01-02")
|
||||
}
|
||||
|
||||
type Huisgenoot struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
Naam string `json:"naam"`
|
||||
DatumVan CouchDate `json:"datumVan"`
|
||||
DatumTotEnMet CouchDate `json:"datumTotEnMet"`
|
||||
Samenlevingscontract bool `json:"samenlevingscontract"`
|
||||
Pensioenregeling bool `json:"pensioenregeling"`
|
||||
EigenaarWoning bool `json:"eigenaarwoning"`
|
||||
MinderjarigKind bool `json:"minderjarigkind"`
|
||||
FiscalePartner bool `json:"fiscalePartner"`
|
||||
}
|
||||
|
||||
type Kind struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
Naam string `json:"naam"`
|
||||
Geboortedatum CouchDate `json:"geboortedatum"`
|
||||
Burgerservicenummer int64 `json:"burgerservicenummer"`
|
||||
}
|
||||
|
||||
type InkomenLoondienst struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
Werkgever string `json:"werkgever"`
|
||||
SoortInkomsten string `json:"soortInkomsten"`
|
||||
Loon float64 `json:"loon"`
|
||||
Loonheffing float64 `json:"loonheffing"`
|
||||
Arbeidskorting float64 `json:"arbeidskorting"`
|
||||
AndereInkomsten *float64 `json:"andereInkomsten"`
|
||||
Reiskosten bool `json:"reiskosten"`
|
||||
}
|
||||
|
||||
type PensioenUitkering struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
Land string `json:"land"`
|
||||
Verzekeringsmaatschappij string `json:"verzekeringsmaatschappij"`
|
||||
Loon float64 `json:"loon"`
|
||||
Loonheffing float64 `json:"loonheffing"`
|
||||
Kosten *float64 `json:"kosten"`
|
||||
}
|
||||
|
||||
type Woning struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
Land string `json:"land"`
|
||||
Postcode string `json:"postcode"`
|
||||
Huisnummer int `json:"huisnummer"`
|
||||
Woonplaats string `json:"woonplaats"`
|
||||
Eigenaar bool `json:"eigenaar"`
|
||||
AndereEigenaar bool `json:"andere_eigenaar"`
|
||||
Eigendom bool `json:"eigendom"`
|
||||
VeranderdEigendomsdeelLoopJaar bool `json:"veranderd_eigendomsdeel_loop_jaar"`
|
||||
SituatieBeginJaar string `json:"situatie_begin_jaar"`
|
||||
SituatieRestJaar bool `json:"situatie_rest_jaar"`
|
||||
WozWaarde float64 `json:"woz_waarde"`
|
||||
Verhuurd bool `json:"verhuurd"`
|
||||
Erfpachtcanon bool `json:"erfpachtcanon"`
|
||||
}
|
||||
|
||||
type Schuld struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
BankOfGeldverstrekker string `json:"bank_of_geldverstrekker"`
|
||||
Nummer string `json:"nummer"`
|
||||
SchuldVoorWoningJaNee string `json:"schuld_voor_woning_ja_nee"`
|
||||
Jaar string `json:"jaar"`
|
||||
Schuld0101 float64 `json:"schuld_0101"`
|
||||
Schuld3112 float64 `json:"schuld_3112"`
|
||||
Rente float64 `json:"rente"`
|
||||
SchuldVanBeidenJaNee string `json:"schuld_van_beiden_ja_nee"`
|
||||
LeningVoorWoningJaNee string `json:"lening_voor_woning_ja_nee"`
|
||||
LeningGeheelVoorWoningJaNee string `json:"lening_geheel_voor_woning_ja_nee"`
|
||||
}
|
||||
|
||||
type Aangifte struct {
|
||||
ID string `json:"_id,omitempty"`
|
||||
Rev string `json:"_rev,omitempty"`
|
||||
LoginNaam string `json:"login_naam"`
|
||||
Wachtwoord string `json:"wachtwoord"`
|
||||
JaarAangifte int `json:"jaar_aangifte"`
|
||||
JaarVoorJaarAangifte int `json:"jaar_voor_jaar_aangifte"`
|
||||
Naam string `json:"naam"`
|
||||
Geboortedatum CouchDate `json:"geboortedatum"`
|
||||
Burgerservicenummer int64 `json:"burgerservicenummer"`
|
||||
Telefoonnummer *string `json:"telefoonnummer"`
|
||||
NummerBelastingconsulent *string `json:"nummer_belastingconsulent"`
|
||||
Echtgenoot bool `json:"echtgenoot"`
|
||||
Huisgenoot bool `json:"huisgenoot"`
|
||||
SamenIngeschrevenJaNee string `json:"samen_ingeschreven_ja_nee"`
|
||||
FiscalePartnerJaNee string `json:"fiscale_partner_ja_nee"`
|
||||
AndereHuisgenootJaNee string `json:"andere_huisgenoot_ja_nee"`
|
||||
NaamPartner string `json:"naam_partner"`
|
||||
GeboortedatumPartner CouchDate `json:"geboortedatum_partner"`
|
||||
BurgerservicenummerPartner int64 `json:"burgerservicenummer_partner"`
|
||||
TelefoonnummerPartner *string `json:"telefoonnummer_partner"`
|
||||
NummerBelastingconsulentPartner *string `json:"nummer_belastingconsulent_partner"`
|
||||
Huisgenoten []Huisgenoot `json:"huisgenoten"`
|
||||
Kinderen []Kind `json:"kinderen"`
|
||||
InkomstenUitLoondienst []InkomenLoondienst `json:"inkomstenUitLoondienst"`
|
||||
PensioenEnAndereUitkeringen []PensioenUitkering `json:"pensioenEnAndereUitkeringen"`
|
||||
OndernemingJaNee string `json:"onderneming_ja_nee"`
|
||||
OndernenerIBJaNee string `json:"ondernemer_ib_ja_nee"`
|
||||
GeldverstrekkerJaNee string `json:"geldverstrekker_ja_nee"`
|
||||
PartnerOndernenerIBJaNee string `json:"partner_ondernemer_ib_ja_nee"`
|
||||
PartnerGeldverstrekkerJaNee string `json:"partner_geldverstrekker_ja_nee"`
|
||||
Woningen []Woning `json:"woningen"`
|
||||
SchuldenJaNee string `json:"schulden_ja_nee"`
|
||||
Schulden []Schuld `json:"schulden"`
|
||||
|
||||
BankEnSpaarrekeningen bool `json:"bank_en_spaarrekeningen_ja_nee"`
|
||||
GroeneSpaartegoeden bool `json:"groene_spaartegoeden_ja_nee"`
|
||||
Beleggingen bool `json:"beleggingen_ja_nee"`
|
||||
GroeneBeleggingen bool `json:"groene_beleggingen_ja_nee"`
|
||||
AanmerkelijkBelang bool `json:"aanmerkelijk_belang_ja_nee"`
|
||||
Kapitaalverzekeringen bool `json:"kapitaalverzekeringen_ja_nee"`
|
||||
Bouwdepots bool `json:"bouwdepots_ja_nee"`
|
||||
ContantGeld bool `json:"contant_geld_ja_nee"`
|
||||
UitgeleendGeld bool `json:"uitgeleend_geld_ja_nee"`
|
||||
RechtenOpPeriodiekUitkeringen bool `json:"rechten_op_periodieke_uitkeringen_ja_nee"`
|
||||
OverigeBezittingen bool `json:"overige_bezittingen_ja_nee"`
|
||||
WaardeHogerDanJaNee string `json:"waarde_meer_dan_ja_nee"`
|
||||
LijfrenteJaNee bool `json:"lijfrente_ja_nee"`
|
||||
InkomensvoorzieningenJaNee bool `json:"inkomensvoorzieningen_ja_nee"`
|
||||
ZorgkostenJaNee bool `json:"zorgkosten_ja_nee"`
|
||||
GiftenJaNee bool `json:"giften_ja_nee"`
|
||||
StudiefinancieringJaNee bool `json:"studiefinanciering_ja_nee"`
|
||||
AlimentatieJaNee bool `json:"alimentatie_ja_nee"`
|
||||
GehandicapteJaNee bool `json:"gehandicapte_ja_nee"`
|
||||
VoorJaarAangifteJaNee bool `json:"voor_jaar_aangifte_ja_nee"`
|
||||
DatumIngediend *CouchDate `json:"datum_ingediend,omitempty"`
|
||||
}
|
||||
// mapCheckboxes returns the mapping of labels to struct field names
|
||||
func mapCheckboxes(a *Aangifte) map[string]string {
|
||||
return map[string]string{
|
||||
"Bank- en spaarrekeningen": "bank_en_spaarrekeningen_ja_nee",
|
||||
"Groene spaartegoeden": "groene_spaartegoeden_ja_nee",
|
||||
"Beleggingen": "beleggingen_ja_nee",
|
||||
"Groene beleggingen": "groene_beleggingen_ja_nee",
|
||||
"Aanmerkelijk belang": "aanmerkelijk_belang_ja_nee",
|
||||
"Kapitaalverzekeringen": "kapitaalverzekeringen_ja_nee",
|
||||
"Bouwdepots": "bouwdepots_ja_nee",
|
||||
"Contant geld": "contant_geld_ja_nee",
|
||||
"Uitgeleend geld": "uitgeleend_geld_ja_nee",
|
||||
"Rechten op periodieke uitkeringen": "rechten_op_periodieke_uitkeringen_ja_nee",
|
||||
"Overige bezittingen": "overige_bezittingen_ja_nee",
|
||||
"Lijfrente": "lijfrente_ja_nee",
|
||||
"Inkomensvoorzieningen": "inkomensvoorzieningen_ja_nee",
|
||||
"Zorgkosten": "zorgkosten_ja_nee",
|
||||
"Giften": "giften_ja_nee",
|
||||
"Studiefinanciering": "studiefinanciering_ja_nee",
|
||||
"Alimentatie": "alimentatie_ja_nee",
|
||||
"Gehandicapte": "gehandicapte_ja_nee",
|
||||
"Voor jaar aangifte": "voor_jaar_aangifte_ja_nee",
|
||||
}
|
||||
}
|
||||
|
||||
// template setup with the fix
|
||||
var tmpl = template.Must(template.New("").Funcs(template.FuncMap{
|
||||
"add": func(a, b int) int { return a + b },
|
||||
"deref": func(p *string) string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
return *p
|
||||
},
|
||||
"mapCheckboxes": mapCheckboxes, // 👈 register the function
|
||||
}).Parse(allTemplates))
|
||||
|
||||
// handler for login page
|
||||
func handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "GET" {
|
||||
tmpl.ExecuteTemplate(w, "login", map[string]interface{}{})
|
||||
return
|
||||
}
|
||||
|
||||
bsn := strToInt64(r.FormValue("bsn"))
|
||||
wachtwoord := r.FormValue("wachtwoord")
|
||||
|
||||
aangifte, err := findByBSN(bsn)
|
||||
if err != nil {
|
||||
tmpl.ExecuteTemplate(w, "login", map[string]interface{}{
|
||||
"Error": "Fout bij ophalen gegevens.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if aangifte != nil && aangifte.Wachtwoord != wachtwoord {
|
||||
tmpl.ExecuteTemplate(w, "login", map[string]interface{}{
|
||||
"Error": "Onjuist BSN of wachtwoord.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if aangifte == nil {
|
||||
aangifte = &Aangifte{
|
||||
Burgerservicenummer: bsn,
|
||||
Wachtwoord: wachtwoord,
|
||||
JaarAangifte: time.Now().Year() - 1,
|
||||
JaarVoorJaarAangifte: time.Now().Year() - 2,
|
||||
}
|
||||
}
|
||||
|
||||
sid := fmt.Sprintf("%d-%d", bsn, time.Now().UnixNano())
|
||||
sessions[sid] = &Session{
|
||||
BSN: bsn,
|
||||
Aangifte: aangifte,
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session",
|
||||
Value: sid,
|
||||
Path: "/",
|
||||
})
|
||||
|
||||
http.Redirect(w, r, "/aangifte", http.StatusSeeOther)
|
||||
}
|
||||
// handleAangifte shows the main form page
|
||||
func handleAangifte(w http.ResponseWriter, r *http.Request) {
|
||||
sess, ok := getSession(r)
|
||||
if !ok {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
tmpl.ExecuteTemplate(w, "aangifte", map[string]interface{}{
|
||||
"Aangifte": sess.Aangifte,
|
||||
})
|
||||
}
|
||||
|
||||
// handleSave updates the Aangifte struct from POST form data
|
||||
func handleSave(w http.ResponseWriter, r *http.Request) {
|
||||
sess, ok := getSession(r)
|
||||
if !ok {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "Kon formulier niet parsen", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// update all fields
|
||||
checks := mapCheckboxes(sess.Aangifte)
|
||||
for label, field := range checks {
|
||||
val := r.FormValue(label)
|
||||
b := val == "on"
|
||||
setBoolField(sess.Aangifte, field, b)
|
||||
}
|
||||
|
||||
// optional: update jaar fields if present
|
||||
if jaar := r.FormValue("jaar_aangifte"); jaar != "" {
|
||||
if y, err := strconv.Atoi(jaar); err == nil {
|
||||
sess.Aangifte.JaarAangifte = y
|
||||
}
|
||||
}
|
||||
if jaarVoor := r.FormValue("jaar_voor_jaar_aangifte"); jaarVoor != "" {
|
||||
if y, err := strconv.Atoi(jaarVoor); err == nil {
|
||||
sess.Aangifte.JaarVoorJaarAangifte = y
|
||||
}
|
||||
}
|
||||
|
||||
// store/save to your DB if needed; here we just update session
|
||||
http.Redirect(w, r, "/aangifte", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// handleLogout deletes the session and redirects to login
|
||||
func handleLogout(w http.ResponseWriter, r *http.Request) {
|
||||
cookie, err := r.Cookie("session")
|
||||
if err == nil {
|
||||
delete(sessions, cookie.Value)
|
||||
cookie.MaxAge = -1
|
||||
http.SetCookie(w, cookie)
|
||||
}
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// helper to set boolean field via reflection
|
||||
func setBoolField(a *Aangifte, fieldName string, val bool) {
|
||||
v := reflect.ValueOf(a).Elem().FieldByName(fieldName)
|
||||
if v.IsValid() && v.Kind() == reflect.Bool {
|
||||
v.SetBool(val)
|
||||
}
|
||||
}
|
||||
|
||||
// getSession retrieves session from cookie
|
||||
func getSession(r *http.Request) (*Session, bool) {
|
||||
cookie, err := r.Cookie("session")
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
sess, ok := sessions[cookie.Value]
|
||||
return sess, ok
|
||||
}
|
||||
// allTemplates holds embedded templates (login + aangifte)
|
||||
var allTemplates = `
|
||||
{{define "login"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Login</title></head>
|
||||
<body>
|
||||
<h1>Login</h1>
|
||||
<form method="POST" action="/login">
|
||||
<label>Username: <input type="text" name="username"></label><br>
|
||||
<label>Password: <input type="password" name="password"></label><br>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
|
||||
{{define "aangifte"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Aangifte</title></head>
|
||||
<body>
|
||||
<h1>Aangifte Form</h1>
|
||||
<form method="POST" action="/save">
|
||||
<label>Jaar Aangifte: <input type="text" name="jaar_aangifte" value="{{.Aangifte.JaarAangifte}}"></label><br>
|
||||
<label>Jaar Voor Jaar Aangifte: <input type="text" name="jaar_voor_jaar_aangifte" value="{{.Aangifte.JaarVoorJaarAangifte}}"></label><br>
|
||||
|
||||
{{range $i, $h := .Aangifte.Huisgenoten}}
|
||||
<h3>Huisgenoot {{$i}}</h3>
|
||||
<label>Naam: <input type="text" name="huisgenoot_{{$i}}_naam" value="{{$h.Naam}}"></label><br>
|
||||
<label>Partner: <input type="checkbox" name="huisgenoot_{{$i}}_partner" {{if $h.Partner}}checked{{end}}></label><br>
|
||||
<label>Aangifte: <input type="checkbox" name="huisgenoot_{{$i}}_aangifte" {{if $h.Aangifte}}checked{{end}}></label><br>
|
||||
{{end}}
|
||||
|
||||
<button type="submit">Opslaan</button>
|
||||
</form>
|
||||
<br>
|
||||
<a href="/logout">Logout</a>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
`
|
||||
|
||||
func main() {
|
||||
// parse templates
|
||||
tmpl = template.Must(template.New("all").Parse(allTemplates))
|
||||
|
||||
// initialize sessions map
|
||||
sessions = make(map[string]*Session)
|
||||
|
||||
// routes
|
||||
http.HandleFunc("/login", handleLogin)
|
||||
http.HandleFunc("/aangifte", handleAangifte)
|
||||
http.HandleFunc("/save", handleSave)
|
||||
http.HandleFunc("/logout", handleLogout)
|
||||
|
||||
fmt.Println("Server gestart op :8080")
|
||||
err := http.ListenAndServe(":8080", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: couchdb
|
||||
namespace: couchdb
|
||||
labels:
|
||||
app: couchdb
|
||||
spec:
|
||||
ports:
|
||||
- port: 5984
|
||||
name: http
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: couchdb
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: couchdb-lb
|
||||
namespace: couchdb
|
||||
labels:
|
||||
app: couchdb
|
||||
spec:
|
||||
ports:
|
||||
- port: 5984
|
||||
name: http
|
||||
selector:
|
||||
app: couchdb
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: couchdb
|
||||
namespace: couchdb
|
||||
spec:
|
||||
serviceName: couchdb
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: couchdb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: couchdb
|
||||
spec:
|
||||
containers:
|
||||
- name: couchdb
|
||||
image: couchdb:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 5984
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: NODENAME
|
||||
value: "$(POD_NAME).couchdb.couchdb.svc.cluster.local"
|
||||
- name: COUCHDB_UUID
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.uid
|
||||
- name: ERL_FLAGS
|
||||
value: "-setcookie couchdb_cookie"
|
||||
- name: COUCHDB_USER
|
||||
value: "admin"
|
||||
- name: COUCHDB_PASSWORD
|
||||
value: "Couchdb01"
|
||||
volumeMounts:
|
||||
- name: couchdb
|
||||
mountPath: /opt/couchdb/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: couchdb
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
storageClassName: ""
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
selector:
|
||||
matchLabels:
|
||||
pv: couchdb-data
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: couchdb-ingress
|
||||
namespace: couchdb
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`couchdb-prod.allarddcs.nl`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: couchdb-lb
|
||||
port: 5984
|
||||
namespace: couchdb
|
||||
sticky:
|
||||
cookie:
|
||||
name: couchdb_sticky
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: couchdb-pv-0
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 2Gi
|
||||
nfs:
|
||||
path: /mnt/nfs_share/prod/couchdb/data/couchdb-0
|
||||
server: 192.168.2.111
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
volumeMode: Filesystem
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: couchdb-pv-1
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 2Gi
|
||||
nfs:
|
||||
path: /mnt/nfs_share/prod/couchdb/data/couchdb-1
|
||||
server: 192.168.2.111
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
volumeMode: Filesystem
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: couchdb-pv-2
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 2Gi
|
||||
nfs:
|
||||
path: /mnt/nfs_share/prod/couchdb/data/couchdb-2
|
||||
server: 192.168.2.111
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
volumeMode: Filesystem
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: couchdb-couchdb-0
|
||||
namespace: couchdb
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
storageClassName: ""
|
||||
volumeMode: Filesystem
|
||||
volumeName: couchdb-pv-0
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: couchdb-couchdb-1
|
||||
namespace: couchdb
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
storageClassName: ""
|
||||
volumeMode: Filesystem
|
||||
volumeName: couchdb-pv-1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: couchdb-couchdb-2
|
||||
namespace: couchdb
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
storageClassName: ""
|
||||
volumeMode: Filesystem
|
||||
volumeName: couchdb-pv-2
|
||||
@@ -0,0 +1,100 @@
|
||||
; CouchDB Configuration Settings
|
||||
|
||||
; Custom settings should be made in this file. They will override settings
|
||||
; in default.ini, but unlike changes made to default.ini, this file won't be
|
||||
; overwritten on server upgrade.
|
||||
|
||||
[couchdb]
|
||||
;max_document_size = 4294967296 ; bytes
|
||||
;os_process_timeout = 5000
|
||||
|
||||
[couch_peruser]
|
||||
; If enabled, couch_peruser ensures that a private per-user database
|
||||
; exists for each document in _users. These databases are writable only
|
||||
; by the corresponding user. Databases are in the following form:
|
||||
; userdb-{hex encoded username}
|
||||
;enable = true
|
||||
|
||||
; If set to true and a user is deleted, the respective database gets
|
||||
; deleted as well.
|
||||
;delete_dbs = true
|
||||
|
||||
; Set a default q value for peruser-created databases that is different from
|
||||
; cluster / q
|
||||
;q = 1
|
||||
|
||||
[chttpd]
|
||||
;port = 5984
|
||||
;bind_address = 127.0.0.1
|
||||
|
||||
; Options for the MochiWeb HTTP server.
|
||||
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
|
||||
|
||||
; For more socket options, consult Erlang's module 'inet' man page.
|
||||
;socket_options = [{sndbuf, 262144}, {nodelay, true}]
|
||||
|
||||
[httpd]
|
||||
; NOTE that this only configures the "backend" node-local port, not the
|
||||
; "frontend" clustered port. You probably don't want to change anything in
|
||||
; this section.
|
||||
; Uncomment next line to trigger basic-auth popup on unauthorized requests.
|
||||
;WWW-Authenticate = Basic realm="administrator"
|
||||
|
||||
; Uncomment next line to set the configuration modification whitelist. Only
|
||||
; whitelisted values may be changed via the /_config URLs. To allow the admin
|
||||
; to change this value over HTTP, remember to include {httpd,config_whitelist}
|
||||
; itself. Excluding it from the list would require editing this file to update
|
||||
; the whitelist.
|
||||
;config_whitelist = [{httpd,config_whitelist}, {log,level}, {etc,etc}]
|
||||
|
||||
[ssl]
|
||||
;enable = true
|
||||
;cert_file = /full/path/to/server_cert.pem
|
||||
;key_file = /full/path/to/server_key.pem
|
||||
;password = somepassword
|
||||
|
||||
; set to true to validate peer certificates
|
||||
;verify_ssl_certificates = false
|
||||
|
||||
; Set to true to fail if the client does not send a certificate. Only used if verify_ssl_certificates is true.
|
||||
;fail_if_no_peer_cert = false
|
||||
|
||||
; Path to file containing PEM encoded CA certificates (trusted
|
||||
; certificates used for verifying a peer certificate). May be omitted if
|
||||
; you do not want to verify the peer.
|
||||
;cacert_file = /full/path/to/cacertf
|
||||
|
||||
; The verification fun (optional) if not specified, the default
|
||||
; verification fun will be used.
|
||||
;verify_fun = {Module, VerifyFun}
|
||||
|
||||
; maximum peer certificate depth
|
||||
;ssl_certificate_max_depth = 1
|
||||
|
||||
; Reject renegotiations that do not live up to RFC 5746.
|
||||
;secure_renegotiate = true
|
||||
|
||||
; The cipher suites that should be supported.
|
||||
; Can be specified in erlang format "{ecdhe_ecdsa,aes_128_cbc,sha256}"
|
||||
; or in OpenSSL format "ECDHE-ECDSA-AES128-SHA256".
|
||||
;ciphers = ["ECDHE-ECDSA-AES128-SHA256", "ECDHE-ECDSA-AES128-SHA"]
|
||||
|
||||
; The SSL/TLS versions to support
|
||||
;tls_versions = [tlsv1, 'tlsv1.1', 'tlsv1.2']
|
||||
|
||||
; To enable Virtual Hosts in CouchDB, add a vhost = path directive. All requests to
|
||||
; the Virtual Host will be redirected to the path. In the example below all requests
|
||||
; to http://example.com/ are redirected to /database.
|
||||
; If you run CouchDB on a specific port, include the port number in the vhost:
|
||||
; example.com:5984 = /database
|
||||
[vhosts]
|
||||
;example.com = /database/
|
||||
|
||||
; To create an admin account uncomment the '[admins]' section below and add a
|
||||
; line in the format 'username = password'. When you next start CouchDB, it
|
||||
; will change the password to a hash (so that your passwords don't linger
|
||||
; around in plain-text files). You can add more admin accounts with more
|
||||
; 'username = password' lines. Don't forget to restart CouchDB after
|
||||
; changing this.
|
||||
[admins]
|
||||
;admin = mysecretpassword
|
||||
Reference in New Issue
Block a user