Files
timemaster/backend/templates/migration_template.py
T
patrickandClaude Sonnet 5 5cbeebe66d
Security Audit / Python Dependency Audit (push) Has been cancelled
Security Audit / Node.js Dependency Audit (push) Has been cancelled
feat(reports): DATEV-Monatsblatt-Export (Blanko-Vorlage) für Steuerberater
Neuer PDF-Export GET /reports/datev-monthly/export: ein Blatt pro
Mitarbeiter/Monat im Layout der DATEV-Stundenaufzeichnungs-Vorlage
(Beginn/Pause/Ende/Dauer + K/U/UU/F/SA/SU-Kürzel + Bemerkungen +
Summe + Unterschriftsfelder). Führt time_entries, Absences und
Feiertage pro Kalendertag zusammen.

Außerdem: Mustervorlagen für neue Backend-Module (Model/Schema/Router/
Migration/Test) und eine Frontend-Page-Vorlage, abgeleitet vom
hours_payouts-Modul als aktuellstem sauberen Muster.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CviFgc739S89xS97pvjszj
2026-08-06 22:19:54 +02:00

70 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
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.
"""TEMPLATE Mustervorlage für Migration mit NEUER Tabelle + RLS-Policy.
Abgeleitet vom Muster in migrations/versions/0035_absence_comments.py.
WICHTIG (siehe project_dsgvo_multitenant_priority):
- JEDE neue company-bezogene Tabelle braucht company_id-Spalte + RLS-Policy
- NACH dieser Migration: tests/conftest.py muss die RLS-Policy manuell
replizieren (Test-DB nutzt keine echten Migrationen) sonst schlagen
Company-Isolation-Tests unbemerkt fehl (false green)
- Nur neue SPALTEN auf bereits RLS-gefencten Tabellen brauchen KEINE
RLS-Änderung (siehe 0042_payout_requests.py als Gegenbeispiel)
Anleitung:
1. Nach backend/migrations/versions/00XX_xxx_things.py kopieren
2. revision/down_revision auf nächste freie Nummer setzen (siehe
"Datenbank-Migrationen Chronik" in docmost für die aktuell höchste Nummer)
3. Tabellenname/Spalten anpassen
4. conftest.py RLS-Replikation ergänzen
5. Lokal (auf 137!) testen: alembic upgrade head, dann pytest
"""
from alembic import op
from sqlalchemy import text
revision = "00XX" # TODO: nächste freie Nummer
down_revision = "00XX-1" # TODO: vorherige Migration
branch_labels = None
depends_on = None
_BYPASS = "COALESCE(current_setting('app.bypass_rls', true), 'off') = 'on'"
_CID = "company_id = NULLIF(current_setting('app.company_id', true), '')::uuid"
_USING = f"({_BYPASS} OR {_CID})"
def _exec(sql: str) -> None:
op.execute(text(sql))
def upgrade() -> None:
# 1) Tabelle anlegen
_exec("""
CREATE TABLE IF NOT EXISTS xxx_things (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
note TEXT,
status VARCHAR(12) NOT NULL DEFAULT 'requested',
rejection_reason TEXT,
created_by UUID NOT NULL REFERENCES users(id) ON DELETE SET NULL,
decided_by UUID REFERENCES users(id) ON DELETE SET NULL,
decided_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
)
""")
_exec("CREATE INDEX IF NOT EXISTS ix_xxx_things_company_id ON xxx_things(company_id)")
_exec("CREATE INDEX IF NOT EXISTS ix_xxx_things_user_id ON xxx_things(user_id)")
# 2) RLS (company_id-gefenced)
_exec("ALTER TABLE xxx_things ENABLE ROW LEVEL SECURITY")
_exec("ALTER TABLE xxx_things FORCE ROW LEVEL SECURITY")
for cmd in ("select", "insert", "update", "delete"):
_exec(f"DROP POLICY IF EXISTS rls_xxx_things_{cmd} ON xxx_things")
_exec(f"CREATE POLICY rls_xxx_things_select ON xxx_things FOR SELECT USING {_USING}")
_exec(f"CREATE POLICY rls_xxx_things_insert ON xxx_things FOR INSERT WITH CHECK {_USING}")
_exec(f"CREATE POLICY rls_xxx_things_update ON xxx_things FOR UPDATE USING {_USING} WITH CHECK {_USING}")
_exec(f"CREATE POLICY rls_xxx_things_delete ON xxx_things FOR DELETE USING {_USING}")
def downgrade() -> None:
_exec("DROP TABLE IF EXISTS xxx_things")