Files
armarium-suite/backend/core/urls.py
T
Daniel Krähenbühl 1a7ef09805 feat: Armarium v1.1.0 — dashboard, auth, 2FA, SMTP, settings, deploy
Dashboard:
- ApexCharts bar chart (income vs fixed costs vs expenses) and donut chart
- KPI cards: income, fixed costs, savings rate with configurable goal
- Greeting with time-of-day and locale-aware date/time display

Authentication & security:
- Email-based login (no username), case-insensitive lookup
- JWT access/refresh tokens with rotation and blacklist
- TOTP 2FA with QR code, backup codes (copy + PDF export)
- 2FA recovery via email code
- Cloudflare Turnstile CAPTCHA on login and register

Email flows:
- Email verification on registration (24h token)
- Password reset flow (15min token, anti-enumeration)
- Brevo SMTP integration with HTML + plaintext email templates
- Notification emails: 2FA recovery, password changed, email changed

Settings page:
- 2FA management (enable/disable, QR, backup codes)
- Active sessions list with per-device revoke
- Data export: ZIP with 6 PDFs via fpdf2
- Notification preferences (3 toggles)
- Danger zone: account deletion with mandatory export + confirmation phrase

UI & layout:
- Sidebar with collapsible/flyout mode, Angular signal-based dropdowns
- Dark mode (class-based), language switcher (DE/FR/IT/EN)
- Mobile-responsive layout with touch-friendly targets
- Roboto font via @fontsource (GDPR-compliant, no Google CDN)
- Pure Tailwind CSS v3

Infrastructure:
- Forgejo Actions CI/CD pipeline (auto-deploy on push to main)
- Gunicorn + Nginx + PostgreSQL production setup
- Rate limiting, HSTS, secure cookies, CSRF protection
2026-05-25 22:46:30 +02:00

56 lines
2.9 KiB
Python

import os
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from rest_framework.routers import DefaultRouter
from rest_framework_simplejwt.views import TokenRefreshView
from finance.views import (
AccountViewSet, TransactionViewSet, BudgetViewSet,
ExpenseViewSet, DeadlineViewSet, ProfileView, RegisterView, LogoutView, ChangePasswordView,
ICalUrlView, ICalFeedView, NotificationsView, SearchView,
LoginView, TwoFactorLoginView, TwoFactorSetupView, TwoFactorEnableView, TwoFactorDisableView,
TwoFactorRecoverRequestView, TwoFactorRecoverConfirmView,
SessionListView, SessionRevokeView, SessionRevokeAllView,
DataExportView, NotificationPrefsView,
VerifyEmailView, PasswordResetRequestView, PasswordResetConfirmView,
)
router = DefaultRouter()
router.register(r'accounts', AccountViewSet, basename='account')
router.register(r'transactions', TransactionViewSet, basename='transaction')
router.register(r'budgets', BudgetViewSet, basename='budget')
router.register(r'expenses', ExpenseViewSet, basename='expense')
router.register(r'deadlines', DeadlineViewSet, basename='deadline')
_admin_url = os.environ.get('ADMIN_URL', 'manage/').strip('/')+ '/'
urlpatterns = [
path(_admin_url, admin.site.urls),
path('api/', include(router.urls)),
path('api/profile/', ProfileView.as_view()),
path('api/auth/register/', RegisterView.as_view()),
path('api/auth/token/', LoginView.as_view()),
path('api/auth/token/refresh/', TokenRefreshView.as_view()),
path('api/auth/logout/', LogoutView.as_view()),
path('api/auth/password/', ChangePasswordView.as_view()),
path('api/auth/verify-email/', VerifyEmailView.as_view()),
path('api/auth/password-reset/', PasswordResetRequestView.as_view()),
path('api/auth/password-reset/confirm/', PasswordResetConfirmView.as_view()),
path('api/auth/2fa/login/', TwoFactorLoginView.as_view()),
path('api/auth/2fa/setup/', TwoFactorSetupView.as_view()),
path('api/auth/2fa/enable/', TwoFactorEnableView.as_view()),
path('api/auth/2fa/disable/', TwoFactorDisableView.as_view()),
path('api/auth/2fa/recover/', TwoFactorRecoverRequestView.as_view()),
path('api/auth/2fa/recover/confirm/', TwoFactorRecoverConfirmView.as_view()),
path('api/auth/sessions/', SessionListView.as_view()),
path('api/auth/sessions/revoke-all/', SessionRevokeAllView.as_view()),
path('api/auth/sessions/<str:session_key>/', SessionRevokeView.as_view()),
path('api/export/', DataExportView.as_view()),
path('api/notifications/prefs/', NotificationPrefsView.as_view()),
path('api/search/', SearchView.as_view()),
path('api/notifications/', NotificationsView.as_view()),
path('api/calendar/ical-url/', ICalUrlView.as_view()),
path('api/calendar/ical/<int:user_id>/<str:token>/', ICalFeedView.as_view()),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)