shinkan-jinkendo/.claude/rules/CODING_RULES.md
Lars abee6171df
Some checks failed
Deploy Development / deploy (push) Successful in 37s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 34s
feat: enhance access layer governance and visibility checks
- Added new documentation references for access layer governance in CLAUDE.md, including multi-tenancy and endpoint audit guidelines.
- Updated ACCESS_LAYER_AND_GOVERNANCE_PLAN.md to include cursor and heuristic checks for access layer compliance.
- Enhanced ACCESS_LAYER_ENDPOINT_AUDIT.md to clarify endpoint visibility and governance requirements, including exemptions for certain routers.
- Introduced library_content_visible_to_profile function in club_tenancy.py to streamline visibility checks for library content.
- Updated exercise progression graphs router to utilize the new visibility function, improving access control.
- Bumped application version to 0.8.27 and updated changelog to reflect these changes.
2026-05-05 22:09:25 +02:00

172 lines
5.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Coding Rules Mitai Jinkendo
Diese Regeln IMMER befolgen. Sie basieren auf Erfahrungen aus der Entwicklung.
## Backend
### 1. Auth und Mandantenkontext (Shinkan)
**Jeder geschützte Endpoint braucht Auth.** Sofern der Endpoint **Vereinsdaten**, **visibility/club_id** oder **mandanten-gefilterte Listen** betrifft, zusätzlich **`TenantContext`** — nicht nur `require_auth` allein.
```python
from tenant_context import TenantContext, get_tenant_context
@router.get("/beispiel")
def beispiel(tenant: TenantContext = Depends(get_tenant_context)):
pid = tenant.profile_id
role = tenant.global_role
club_ctx = tenant.effective_club_id # kann None sein (z. B. Plattform-Admin)
```
- **Bibliotheks-/Planungslisten:** Filter wie bestehende Module (`library_content_visibility_sql` oder gleiche Leseprüfung); keine vollständige Tabelle für normale Nutzer.
- **Schreiben:** `assert_valid_governance_visibility` aus `club_tenancy`, wenn `visibility` / `club_id` gesetzt werden.
- **Dokumentation:** Änderungen in `.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md` festhalten.
- **Ausnahmen** (z.B. reiner Login, globale Kataloge): Kommentar `# ACCESS_LAYER exempt: …` und ggf. Eintrag in `backend/scripts/check_access_layer_hints.py`.
Reine Plattform-Admin-Router (ohne Vereinskontext) können bei Bedarf weiter `Depends(require_auth)` nutzen — dann im Audit als „Plattform“ kennzeichnen.
### 2. Profile-ID aus TenantContext oder Session — nie aus freiem Header
```python
pid = tenant.profile_id # ✅ bei Depends(get_tenant_context)
# oder session['profile_id'] nur wenn Endpoint ausdrücklich ohne TenantContext (Ausnahme dokumentieren)
# Nicht: request.headers.get('X-Profile-Id') ❌
```
### 3. bcrypt für Passwörter
```python
from auth import hash_pin, verify_pin
hashed = hash_pin(plain_password) # ✅
# Nicht: hashlib.sha256(...) ❌
```
### 4. PostgreSQL-Syntax
```python
cur.execute("SELECT * FROM t WHERE id = %s AND active = true", (id,))
# Nicht: ? und active = 1 (SQLite-Syntax)
```
### 5. Rate Limiting für sensitive Endpoints
```python
from slowapi import Limiter
@router.post("/sensitive")
@limiter.limit("5/minute")
def sensitive(request: Request, ...):
```
### 6. Universal CSV Import / Admin-Vorlagen
Neues **Import-Zielmodul**, Änderungen an **`csv_parser`**, Executor, DB-`source`/`CHECK`, oder System-CSV-Vorlagen:
- Pflichtlektüre und Checkliste: **`.claude/docs/technical/UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md`**
- Keine zweite DB-Connection im Importpfad; Zeilenfehler ohne „aborted transaction“ (SAVEPOINT-Muster wo nötig)
- Admin Create/Update von Systemvorlagen: Validierung über `validate_csv_template` nicht umgehen
## Frontend
### 1. api.js für alle API-Calls
```javascript
await api.listWeight() // ✅
await fetch('/api/weight') // ❌ kein Token
```
### 2. Fehlerbehandlung in async Funktionen
```javascript
try {
const data = await api.meinEndpoint()
} catch(e) {
setError(e.message) // api.js wirft bereits Error mit detail-Text
}
```
### 3. Kein TypeScript
Das Projekt nutzt bewusst kein TypeScript keine .ts/.tsx Dateien erstellen.
### 4. Keine neuen npm-Pakete ohne Absprache
Erst fragen, dann installieren.
### 5. CSS-Variablen statt Hardcoded-Farben
```javascript
// ✅ Richtig:
style={{color: 'var(--accent)'}}
// ❌ Falsch:
style={{color: '#1D9E75'}}
```
### 6. Formular-Standard (VERBINDLICH ab 2026-04-22)
**Alle neuen Formulare verwenden den Standard-Stil:**
```jsx
// ✅ Standard: Label oben, volle Breite, linksbündig
<div className="form-row">
<label className="form-label">Feldname *</label>
<input
type="text"
className="form-input"
value={formData.field}
onChange={(e) => updateFormField('field', e.target.value)}
required
/>
</div>
// ✅ Textarea
<div className="form-row">
<label className="form-label">Beschreibung</label>
<textarea
className="form-input"
rows={3}
value={formData.description}
onChange={(e) => updateFormField('description', e.target.value)}
/>
</div>
// ✅ Select
<div className="form-row">
<label className="form-label">Status</label>
<select
className="form-input"
value={formData.status}
onChange={(e) => updateFormField('status', e.target.value)}
>
<option value="active">Aktiv</option>
<option value="inactive">Inaktiv</option>
</select>
</div>
// ❌ NICHT: Inline-Layout mit Label links
// Nur für Ausnahmen (kurze Werte mit Einheit) nutzen:
<div className="form-row--inline">
<label className="form-label">Dauer</label>
<input type="number" className="form-input" value={duration} />
<span className="form-unit">min</span>
</div>
```
**Regeln:**
- Label ist `<label>` mit Klasse `.form-label` (nicht `<div>`)
- Input/Textarea/Select nutzen `.form-input`
- Volle Breite (100%), linksbündig
- Pflichtfelder mit `*` im Label kennzeichnen
- Inline-Variante (`.form-row--inline`) nur für Ausnahmen (Zahlen mit Einheit)
## Git & Deployment
### 1. Nie direkt auf main pushen
Immer über Pull Request in Gitea: develop → main
### 2. develop Branch nie löschen
Er ist permanent nicht nach Merge löschen.
### 3. .env nie committen
Steht in .gitignore nie entfernen.
### 4. Commit-Message Format
```
feat: neues Feature
fix: Bugfix
refactor: Umbau ohne Funktionsänderung
docs: Dokumentation
ci: CI/CD Änderungen
chore: Maintenance
```