diff --git a/CHURCH_MODELS.md b/CHURCH_MODELS.md new file mode 100644 index 0000000..8402582 --- /dev/null +++ b/CHURCH_MODELS.md @@ -0,0 +1,156 @@ +# Church Models - Übersicht für Daemon-Entwicklung + +## 1. ChurchOfficeType (falukant_type.church_office_type) + +**Schema:** `falukant_type` +**Tabelle:** `church_office_type` +**Zweck:** Definiert die verschiedenen Kirchenämter-Typen + +```javascript +{ + id: INTEGER (PK, auto-increment) + name: STRING (z.B. "pope", "cardinal", "lay-preacher") + seatsPerRegion: INTEGER (Anzahl verfügbarer Plätze pro Region) + regionType: STRING (z.B. "country", "duchy", "city") + hierarchyLevel: INTEGER (0-8, höhere Zahl = höhere Position) +} +``` + +**Beziehungen:** +- `hasMany` ChurchOffice (als `offices`) +- `hasMany` ChurchApplication (als `applications`) +- `hasMany` ChurchOfficeRequirement (als `requirements`) + +--- + +## 2. ChurchOfficeRequirement (falukant_predefine.church_office_requirement) + +**Schema:** `falukant_predefine` +**Tabelle:** `church_office_requirement` +**Zweck:** Definiert Voraussetzungen für Kirchenämter + +```javascript +{ + id: INTEGER (PK, auto-increment) + officeTypeId: INTEGER (FK -> ChurchOfficeType.id) + prerequisiteOfficeTypeId: INTEGER (FK -> ChurchOfficeType.id, nullable) + minTitleLevel: INTEGER (nullable, optional) +} +``` + +**Beziehungen:** +- `belongsTo` ChurchOfficeType (als `officeType`) +- `belongsTo` ChurchOfficeType (als `prerequisiteOfficeType`) + +--- + +## 3. ChurchOffice (falukant_data.church_office) + +**Schema:** `falukant_data` +**Tabelle:** `church_office` +**Zweck:** Speichert tatsächlich besetzte Kirchenämter + +```javascript +{ + id: INTEGER (PK, auto-increment) + officeTypeId: INTEGER (FK -> ChurchOfficeType.id) + characterId: INTEGER (FK -> FalukantCharacter.id) + regionId: INTEGER (FK -> RegionData.id) + supervisorId: INTEGER (FK -> FalukantCharacter.id, nullable) + createdAt: DATE + updatedAt: DATE +} +``` + +**Beziehungen:** +- `belongsTo` ChurchOfficeType (als `type`) +- `belongsTo` FalukantCharacter (als `holder`) +- `belongsTo` FalukantCharacter (als `supervisor`) +- `belongsTo` RegionData (als `region`) + +--- + +## 4. ChurchApplication (falukant_data.church_application) + +**Schema:** `falukant_data` +**Tabelle:** `church_application` +**Zweck:** Speichert Bewerbungen für Kirchenämter + +```javascript +{ + id: INTEGER (PK, auto-increment) + officeTypeId: INTEGER (FK -> ChurchOfficeType.id) + characterId: INTEGER (FK -> FalukantCharacter.id) + regionId: INTEGER (FK -> RegionData.id) + supervisorId: INTEGER (FK -> FalukantCharacter.id) + status: ENUM('pending', 'approved', 'rejected') + decisionDate: DATE (nullable) + createdAt: DATE + updatedAt: DATE +} +``` + +**Beziehungen:** +- `belongsTo` ChurchOfficeType (als `officeType`) +- `belongsTo` FalukantCharacter (als `applicant`) +- `belongsTo` FalukantCharacter (als `supervisor`) +- `belongsTo` RegionData (als `region`) + +--- + +## Zusätzlich benötigte Models (für Daemon) + +### RegionData (falukant_data.region) +- Wird für `regionId` in ChurchOffice und ChurchApplication benötigt +- Enthält `regionType` (country, duchy, markgravate, shire, county, city) +- Enthält `parentId` für Hierarchie + +### FalukantCharacter (falukant_data.character) +- Wird für `characterId` (Inhaber/Bewerber) benötigt +- Wird für `supervisorId` benötigt + +--- + +## Wichtige Queries für Daemon + +### Verfügbare Positionen finden +```sql +SELECT cot.*, COUNT(co.id) as occupied_seats +FROM falukant_type.church_office_type cot +LEFT JOIN falukant_data.church_office co + ON cot.id = co.office_type_id + AND co.region_id = ? +WHERE cot.region_type = ? +GROUP BY cot.id +HAVING COUNT(co.id) < cot.seats_per_region +``` + +### Supervisor finden +```sql +SELECT co.* +FROM falukant_data.church_office co +JOIN falukant_type.church_office_type cot ON co.office_type_id = cot.id +WHERE co.region_id = ? + AND cot.hierarchy_level > ( + SELECT hierarchy_level + FROM falukant_type.church_office_type + WHERE id = ? + ) +ORDER BY cot.hierarchy_level ASC +LIMIT 1 +``` + +### Voraussetzungen prüfen +```sql +SELECT cor.* +FROM falukant_predefine.church_office_requirement cor +WHERE cor.office_type_id = ? +``` + +### Bewerbungen für Supervisor +```sql +SELECT ca.* +FROM falukant_data.church_application ca +WHERE ca.supervisor_id = ? + AND ca.status = 'pending' +``` diff --git a/CHURCH_OFFICES.md b/CHURCH_OFFICES.md new file mode 100644 index 0000000..c7c2e36 --- /dev/null +++ b/CHURCH_OFFICES.md @@ -0,0 +1,78 @@ +# Kirchenämter - Hierarchie und Verfügbarkeit + +## Regionstypen +- **country** (Land): Falukant +- **duchy** (Herzogtum): Hessen +- **markgravate** (Markgrafschaft): Groß-Benbach +- **shire** (Grafschaft): Siebenbachen +- **county** (Kreis): Bad Homburg, Maintal +- **city** (Stadt): Frankfurt, Oberursel, Offenbach, Königstein + +## Kirchenämter (von höchstem zu niedrigstem Rang) + +| Amt | Translation Key | Hierarchie-Level | Regionstyp | Plätze pro Region | Beschreibung | +|-----|----------------|-------------------|------------|-------------------|--------------| +| **Papst** | `pope` | 8 | country | 1 | Höchstes Amt, nur einer im ganzen Land | +| **Kardinal** | `cardinal` | 7 | country | 3 | Höchste Kardinäle, mehrere pro Land möglich | +| **Erzbischof** | `archbishop` | 6 | duchy | 1 | Pro Herzogtum ein Erzbischof | +| **Bischof** | `bishop` | 5 | markgravate | 1 | Pro Markgrafschaft ein Bischof | +| **Erzdiakon** | `archdeacon` | 4 | shire | 1 | Pro Grafschaft ein Erzdiakon | +| **Dekan** | `dean` | 3 | county | 1 | Pro Kreis ein Dekan | +| **Pfarrer** | `parish-priest` | 2 | city | 1 | Pro Stadt ein Pfarrer | +| **Dorfgeistlicher** | `village-priest` | 1 | city | 1 | Pro Stadt ein Dorfgeistlicher (Einstiegsposition) | +| **Laienprediger** | `lay-preacher` | 0 | city | 3 | Pro Stadt mehrere Laienprediger (niedrigste Position) | + +## Verfügbare Positionen pro Regionstyp + +### country (Land: Falukant) +- **Papst**: 1 Platz +- **Kardinal**: 3 Plätze +- **Gesamt**: 4 Plätze + +### duchy (Herzogtum: Hessen) +- **Erzbischof**: 1 Platz +- **Gesamt**: 1 Platz + +### markgravate (Markgrafschaft: Groß-Benbach) +- **Bischof**: 1 Platz +- **Gesamt**: 1 Platz + +### shire (Grafschaft: Siebenbachen) +- **Erzdiakon**: 1 Platz +- **Gesamt**: 1 Platz + +### county (Kreis: Bad Homburg, Maintal) +- **Dekan**: 1 Platz pro Kreis +- **Gesamt**: 1 Platz pro Kreis + +### city (Stadt: Frankfurt, Oberursel, Offenbach, Königstein) +- **Pfarrer**: 1 Platz pro Stadt +- **Dorfgeistlicher**: 1 Platz pro Stadt +- **Laienprediger**: 3 Plätze pro Stadt +- **Gesamt**: 5 Plätze pro Stadt + +## Hierarchie und Beförderungsweg + +1. **Laienprediger** (lay-preacher) - Einstiegsposition, keine Voraussetzung +2. **Dorfgeistlicher** (village-priest) - Voraussetzung: Laienprediger +3. **Pfarrer** (parish-priest) - Voraussetzung: Dorfgeistlicher +4. **Dekan** (dean) - Voraussetzung: Pfarrer +5. **Erzdiakon** (archdeacon) - Voraussetzung: Dekan +6. **Bischof** (bishop) - Voraussetzung: Erzdiakon +7. **Erzbischof** (archbishop) - Voraussetzung: Bischof +8. **Kardinal** (cardinal) - Voraussetzung: Erzbischof +9. **Papst** (pope) - Voraussetzung: Kardinal + +## Gesamtübersicht verfügbarer Positionen + +- **Papst**: 1 Position (Land) +- **Kardinal**: 3 Positionen (Land) +- **Erzbischof**: 1 Position (Herzogtum) +- **Bischof**: 1 Position (Markgrafschaft) +- **Erzdiakon**: 1 Position (Grafschaft) +- **Dekan**: 2 Positionen (2 Kreise) +- **Pfarrer**: 4 Positionen (4 Städte) +- **Dorfgeistlicher**: 4 Positionen (4 Städte) +- **Laienprediger**: 12 Positionen (4 Städte × 3) + +**Gesamt**: 30 Positionen im System diff --git a/backend/utils/falukant/initializeFalukantTypes.js b/backend/utils/falukant/initializeFalukantTypes.js index 8de4c5f..1473742 100644 --- a/backend/utils/falukant/initializeFalukantTypes.js +++ b/backend/utils/falukant/initializeFalukantTypes.js @@ -1031,6 +1031,7 @@ export const initializePoliticalOfficePrerequisites = async () => { // — Church Offices — const churchOffices = [ + { tr: "lay-preacher", seatsPerRegion: 3, regionType: "city", hierarchyLevel: 0 }, { tr: "village-priest", seatsPerRegion: 1, regionType: "city", hierarchyLevel: 1 }, { tr: "parish-priest", seatsPerRegion: 1, regionType: "city", hierarchyLevel: 2 }, { tr: "dean", seatsPerRegion: 1, regionType: "county", hierarchyLevel: 3 }, @@ -1043,11 +1044,17 @@ const churchOffices = [ const churchOfficePrerequisites = [ { - officeTr: "village-priest", + officeTr: "lay-preacher", prerequisite: { prerequisiteOfficeTypeId: null // Einstiegsposition, keine Voraussetzung } }, + { + officeTr: "village-priest", + prerequisite: { + prerequisiteOfficeTypeId: "lay-preacher" + } + }, { officeTr: "parish-priest", prerequisite: { diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index 6d1d99d..e036640 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -794,6 +794,53 @@ }, "church": { "title": "Kirche", + "tabs": { + "current": "Aktuelle Positionen", + "available": "Verfügbare Positionen", + "applications": "Bewerbungen" + }, + "current": { + "office": "Amt", + "region": "Region", + "holder": "Inhaber", + "supervisor": "Vorgesetzter", + "none": "Keine aktuellen Positionen vorhanden." + }, + "available": { + "office": "Amt", + "region": "Region", + "supervisor": "Vorgesetzter", + "seats": "Verfügbare Plätze", + "action": "Aktion", + "apply": "Bewerben", + "applySuccess": "Bewerbung erfolgreich eingereicht.", + "applyError": "Fehler beim Einreichen der Bewerbung.", + "none": "Keine verfügbaren Positionen." + }, + "applications": { + "office": "Amt", + "region": "Region", + "applicant": "Bewerber", + "date": "Datum", + "action": "Aktion", + "approve": "Annehmen", + "reject": "Ablehnen", + "approveSuccess": "Bewerbung angenommen.", + "rejectSuccess": "Bewerbung abgelehnt.", + "decideError": "Fehler bei der Entscheidung.", + "none": "Keine Bewerbungen vorhanden." + }, + "offices": { + "lay-preacher": "Laienprediger", + "village-priest": "Dorfgeistlicher", + "parish-priest": "Pfarrer", + "dean": "Dekan", + "archdeacon": "Erzdiakon", + "bishop": "Bischof", + "archbishop": "Erzbischof", + "cardinal": "Kardinal", + "pope": "Papst" + }, "baptism": { "title": "Taufen", "table": { diff --git a/frontend/src/i18n/locales/en/falukant.json b/frontend/src/i18n/locales/en/falukant.json index 823d430..248fee7 100644 --- a/frontend/src/i18n/locales/en/falukant.json +++ b/frontend/src/i18n/locales/en/falukant.json @@ -347,6 +347,72 @@ "success": "The gift has been given.", "nextGiftAt": "Next gift from" } + }, + "church": { + "title": "Church", + "tabs": { + "current": "Current Positions", + "available": "Available Positions", + "applications": "Applications" + }, + "current": { + "office": "Office", + "region": "Region", + "holder": "Holder", + "supervisor": "Supervisor", + "none": "No current positions available." + }, + "available": { + "office": "Office", + "region": "Region", + "supervisor": "Supervisor", + "seats": "Available Seats", + "action": "Action", + "apply": "Apply", + "applySuccess": "Application submitted successfully.", + "applyError": "Error submitting application.", + "none": "No available positions." + }, + "applications": { + "office": "Office", + "region": "Region", + "applicant": "Applicant", + "date": "Date", + "action": "Action", + "approve": "Approve", + "reject": "Reject", + "approveSuccess": "Application approved.", + "rejectSuccess": "Application rejected.", + "decideError": "Error making decision.", + "none": "No applications available." + }, + "offices": { + "lay-preacher": "Lay Preacher", + "village-priest": "Village Priest", + "parish-priest": "Parish Priest", + "dean": "Dean", + "archdeacon": "Archdeacon", + "bishop": "Bishop", + "archbishop": "Archbishop", + "cardinal": "Cardinal", + "pope": "Pope" + }, + "baptism": { + "title": "Baptism", + "table": { + "name": "First Name", + "gender": "Gender", + "age": "Age", + "baptise": "Baptize (50)", + "newName": "Suggest Name" + }, + "gender": { + "male": "Boy", + "female": "Girl" + }, + "success": "The child has been baptized.", + "error": "The child could not be baptized." + } } } } \ No newline at end of file