feat(backend): OAuth FRONTEND_URL from config, docs update

- Add FrontendURL to config (FRONTEND_URL or VITE_FRONTEND_URL)
- OAuth handlers use config instead of os.Getenv
- Update TODOS_AUDIT: mark UUID migration items as resolved
- Add ISSUES_P2_BACKLOG.md for GitHub issues
- Add ROUTES_ORPHANES.md for routes without UI
- Document FRONTEND_URL in .env.example
This commit is contained in:
senke 2026-02-17 16:42:23 +01:00
parent 7846bbab28
commit 06d56dd298
7 changed files with 136 additions and 45 deletions

View file

@ -0,0 +1,43 @@
# P2 Issues Backlog — GitHub Issues à créer
**Date** : 2026-02-17
**Source** : [TODOS_AUDIT.md](./TODOS_AUDIT.md)
Ce document liste les items P2 identifiés dans l'audit des TODOs. Créer des issues GitHub pour les traiter par sprint.
## Items P2 à prioriser
| Priorité | Fichier | Description | Catégorie |
|----------|---------|-------------|-----------|
| 1 | `internal/core/track/service.go` | Enqueue job pour traitement asynchrone (metadata, waveform) selon ORIGIN_ASYNC_PROCESSING | Performance |
| 2 | `internal/handlers/oauth_handlers.go` | ~~Get from config (frontendURL)~~ — Résolu 2026-02 | - |
| 3 | `internal/database/database.go` | Implémenter OAuth user lookup | Feature |
| 4 | `internal/database/database.go` | Implémenter avec vraie DB (3 occurrences) | Implementation |
| 5 | `internal/handlers/session.go` | Déterminer si c'est la session actuelle | Feature |
| 6 | `internal/logging/logger.go` | Implémenter avec AtomicLevel lors de la création du logger | Enhancement |
| 7 | `internal/services/job_service.go` | Intégrer asynq ou autre système de queue (3 occurrences) | Architecture |
| 8 | `internal/api/user/service.go` | Parse JSON strings to structs / Serialize structs to JSON | Implementation |
| 9 | `internal/api/admin/service.go` | Implement based on doc_admin_handler.md (3 occurrences) | Feature |
| 10 | `internal/config/config.go` | Améliorer la configuration CORS pour utiliser c.CORSOrigins depuis la config | Code quality |
## Template issue GitHub
```markdown
**Fichier** : `internal/...`
**Priorité** : P2
**Catégorie** : [Performance|Feature|Implementation|Architecture|Code quality]
## Description
[Description du TODO]
## Contexte
Voir TODOS_AUDIT.md
## Critères d'acceptation
- [ ] ...
```
## Références
- [TODOS_AUDIT.md](./TODOS_AUDIT.md) — Audit complet
- [103_RAPPORT_ETAT_FEATURES_2026_02_16.md](../../103_RAPPORT_ETAT_FEATURES_2026_02_16.md) — État des features

View file

@ -0,0 +1,39 @@
# Routes orphelines — Backend sans UI ou partiellement exposées
**Date** : 2026-02-17
**Objectif** : Documenter les routes backend dont l'UI est absente, partielle ou non connectée.
## Définition
- **Complet** : Route utilisée par une UI dédiée
- **Partiel** : API/service prêt côté frontend mais pas d'UI (bouton, formulaire, etc.)
- **Absent** : Aucune utilisation frontend
## Routes par statut
### Routes sans UI (API prête, pas de composant)
| Méthode | Path | Handler | Note |
|---------|------|---------|------|
| POST | `/api/v1/tracks/batch/delete` | `TrackHandler.BatchDeleteTracks` | `trackApi.batchDeleteTracks`, `tracksApi.batchDelete` — aucun composant n'appelle |
| POST | `/api/v1/tracks/batch/update` | `TrackHandler.BatchUpdateTracks` | `trackApi.batchUpdateTracks`, `tracksApi.batchUpdate` — aucun composant n'appelle |
| POST | `/api/v1/uploads/batch` | `UploadHandler.BatchUpload` | Pas de service frontend |
### Routes avec UI complète
| Méthode | Path | Handler | Note |
|---------|------|---------|------|
| GET | `/api/v1/users/me/export` | `routes_users.go` (exportHandler) | `useAccountSettings` → bouton Export Data |
| GET | `/api/v1/playlists/:id/export/json` | `PlaylistExportHandler.ExportPlaylistJSON` | `ExportPlaylistButton` + `exportUtils` |
| GET | `/api/v1/playlists/:id/export/csv` | `PlaylistExportHandler.ExportPlaylistCSV` | Idem |
## Recommandations
1. **Batch delete/update** : Ajouter une UI (sélection multiple dans la bibliothèque, menu contextuel → actions groupées)
2. **Batch upload** : Évaluer si nécessaire ; sinon documenter comme API avancée pour clients tiers
## Références
- [API_DOCUMENTATION.md](./API_DOCUMENTATION.md)
- [FEATURE_STATUS.md](../../apps/web/docs/FEATURE_STATUS.md)
- [TODOS_AUDIT.md](./TODOS_AUDIT.md)

View file

@ -33,14 +33,9 @@ This document lists all TODO, FIXME, HACK, and XXX comments found in the codebas
- **Category**: Performance optimization
### `internal/core/track/handler.go`
- **TODO(P2-GO-004)**: trackUploadService attend int64 - Migration UUID partielle à compléter
- **Priority**: P1
- **Status**: Open
- **Category**: Migration incomplete
- **TODO(P2-GO-004)**: Migration UUID partielle - trackUploadService nécessite migration vers UUID
- **Priority**: P1
- **Status**: Open
- **Category**: Migration incomplete
- ~~**TODO(P2-GO-004)**: trackUploadService attend int64 - Migration UUID partielle à compléter~~
- ~~**TODO(P2-GO-004)**: Migration UUID partielle - trackUploadService nécessite migration vers UUID~~
- **Status**: **Resolved** (2026-02) — trackUploadService utilise uuid.UUID (GetUploadProgress, UpdateUploadStatus, GetUploadStats)
### `internal/database/database.go`
- **TODO**: Implémenter OAuth user lookup
@ -53,10 +48,8 @@ This document lists all TODO, FIXME, HACK, and XXX comments found in the codebas
- **Category**: Implementation placeholder
### `internal/handlers/oauth_handlers.go`
- **TODO**: Get from config (frontendURL hardcoded)
- **Priority**: P2
- **Status**: Open
- **Category**: Configuration
- ~~**TODO**: Get from config (frontendURL hardcoded)~~
- **Status**: **Resolved** (2026-02) — frontendURL lu depuis config.FrontendURL (FRONTEND_URL or VITE_FRONTEND_URL)
### `internal/handlers/session.go`
- **TODO**: Déterminer si c'est la session actuelle
@ -71,22 +64,16 @@ This document lists all TODO, FIXME, HACK, and XXX comments found in the codebas
- **Category**: Enhancement
### `internal/repositories/playlist_collaborator_repository.go`
- **FIXME**: Assurer que le modèle PlaylistCollaborator utilise UUID
- **Priority**: P1
- **Status**: Open
- **Category**: Migration incomplete
- ~~**FIXME**: Assurer que le modèle PlaylistCollaborator utilise UUID~~
- **Status**: **Resolved** (2026-02) — Interface et modèle utilisent uuid.UUID
### `internal/services/playlist_version_service.go`
- **FIXME**: models.PlaylistVersion ID types need check. Assuming repo handles UUID if struct updated.
- **Priority**: P1
- **Status**: Open
- **Category**: Migration incomplete
- ~~**FIXME**: models.PlaylistVersion ID types need check. Assuming repo handles UUID if struct updated.~~
- **Status**: **Resolved** (2026-02) — models.PlaylistVersion utilise uuid.UUID (ID, PlaylistID, UserID)
### `internal/services/track_history_service.go`
- **FIXME**: models.TrackHistory needs UUID too if not updated
- **Priority**: P1
- **Status**: Open
- **Category**: Migration incomplete
- ~~**FIXME**: models.TrackHistory needs UUID too if not updated~~
- **Status**: **Resolved** (2026-02) — models.TrackHistory et RecordHistoryParams utilisent uuid.UUID
### `internal/services/job_service.go`
- **TODO**: Intégrer asynq ou autre système de queue (3 occurrences)
@ -95,10 +82,8 @@ This document lists all TODO, FIXME, HACK, and XXX comments found in the codebas
- **Category**: Architecture
### `internal/services/playlist_service.go`
- **FIXME**: PlaylistVersionService likely needs update for UUID too, but assuming it takes what we give or we handle it later
- **Priority**: P1
- **Status**: Open
- **Category**: Migration incomplete
- ~~**FIXME**: PlaylistVersionService likely needs update for UUID too, but assuming it takes what we give or we handle it later~~
- **Status**: **Resolved** (2026-02) — PlaylistVersionService et modèles alignés sur UUID
### `internal/api/archive/api_manager.go` (archived, build-ignored)
- **TODO**: Réactiver api_manager.go après stabilisation du noyau et alignement des services (graphql, grpc, websocket, features)
@ -179,13 +164,13 @@ This document lists all TODO, FIXME, HACK, and XXX comments found in the codebas
## Summary by Priority
- **P0**: 0 items
- **P1**: 7 items (UUID migration incomplete)
- **P1**: 0 items (UUID migration completed — 7 items resolved 2026-02)
- **P2**: 18 items (various improvements)
- **P3**: 6 items (deferred/future features)
## Recommendations
1. **P1 Items (UUID Migration)**: Complete UUID migration for remaining services
1. ~~**P1 Items (UUID Migration)**~~: Completed (2026-02)
2. **P2 Items**: Prioritize based on impact and effort
3. **P3 Items**: Defer to future sprints or remove if no longer relevant
@ -198,5 +183,5 @@ This document lists all TODO, FIXME, HACK, and XXX comments found in the codebas
---
**Last Updated**: 2025-01-27
**Last Updated**: 2026-02-17
**Maintained By**: Veza Backend Team

View file

@ -87,7 +87,12 @@ func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
loginGroup.POST("", handlers.Login(authService, sessionService, twoFactorService, r.logger, r.config))
loginGroup.POST("/2fa", handlers.LoginWith2FA(authService, sessionService, twoFactorService, r.logger, r.config))
authGroup.POST("/refresh", handlers.Refresh(authService, sessionService, r.logger, r.config))
// SEC-010: Rate limit refresh to prevent token grinding
refreshGroup := authGroup.Group("")
if r.config.EndpointLimiter != nil {
refreshGroup.Use(r.config.EndpointLimiter.RefreshRateLimit())
}
refreshGroup.POST("/refresh", handlers.Refresh(authService, sessionService, r.logger, r.config))
// BE-SEC-005: Apply rate limiting to email verification endpoints
verifyEmailGroup := authGroup.Group("/verify-email")
@ -102,7 +107,12 @@ func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
}
resendVerificationGroup.POST("", handlers.ResendVerification(authService, r.logger))
authGroup.GET("/check-username", handlers.CheckUsername(authService))
// SEC-009: Rate limit check-username to prevent enumeration
checkUsernameGroup := authGroup.Group("")
if r.config.EndpointLimiter != nil {
checkUsernameGroup.Use(r.config.EndpointLimiter.CheckUsernameRateLimit())
}
checkUsernameGroup.GET("/check-username", handlers.CheckUsername(authService))
// BE-API-042: OAuth routes
jwtSecretBytes := []byte(r.config.JWTSecret)
@ -126,7 +136,7 @@ func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
oauthService.InitializeConfigs(googleClientID, googleClientSecret, githubClientID, githubClientSecret, discordClientID, discordClientSecret, baseURL)
}
oauthHandler := handlers.NewOAuthHandler(oauthService, r.logger, r.config.CORSOrigins)
oauthHandler := handlers.NewOAuthHandler(oauthService, r.logger, r.config.CORSOrigins, r.config.FrontendURL)
oauthGroup := authGroup.Group("/oauth")
{
oauthGroup.GET("/providers", oauthHandler.GetOAuthProviders)

View file

@ -76,6 +76,7 @@ type Config struct {
StreamServerInternalAPIKey string // API key for /internal/jobs/transcode (P1.1.2 - same as stream server INTERNAL_API_KEY)
ChatServerURL string // URL du serveur de chat
CORSOrigins []string // Liste des origines CORS autorisées
FrontendURL string // URL du frontend (OAuth redirect, password reset links). FRONTEND_URL ou VITE_FRONTEND_URL
// S3 Storage Configuration (BE-SVC-005)
S3Bucket string // Nom du bucket S3
@ -273,6 +274,7 @@ func NewConfig() (*Config, error) {
StreamServerInternalAPIKey: getEnv("STREAM_SERVER_INTERNAL_API_KEY", ""),
ChatServerURL: getEnv("CHAT_SERVER_URL", "http://"+appDomain+":8081"),
CORSOrigins: corsOrigins,
FrontendURL: getFrontendURL(), // OAuth callback, password reset, email links
// S3 Storage Configuration (BE-SVC-005)
S3Bucket: getEnv("AWS_S3_BUCKET", ""),

View file

@ -143,3 +143,15 @@ func parseLogAggregationLabels(value string) map[string]string {
return labels
}
// getFrontendURL returns the frontend URL for OAuth redirects, password reset links, etc.
// Reads FRONTEND_URL, then VITE_FRONTEND_URL, fallback to http://localhost:5173 for development.
func getFrontendURL() string {
if v := os.Getenv("FRONTEND_URL"); v != "" {
return strings.TrimSpace(v)
}
if v := os.Getenv("VITE_FRONTEND_URL"); v != "" {
return strings.TrimSpace(v)
}
return "http://localhost:5173" // Fallback for development only; set FRONTEND_URL in production
}

View file

@ -4,7 +4,6 @@ import (
"fmt"
"net/http"
"net/url"
"os"
"strings"
"veza-backend-api/internal/services"
@ -20,9 +19,10 @@ type OAuthServiceInterface interface {
// OAuthHandlers handles OAuth authentication flows
type OAuthHandlers struct {
oauthService OAuthServiceInterface
logger interface{}
allowedRedirectOrigins []string // SECURITY: allowlist for OAuth redirect URLs
oauthService OAuthServiceInterface
logger interface{}
allowedRedirectOrigins []string // SECURITY: allowlist for OAuth redirect URLs
frontendURL string // URL du frontend pour redirect OAuth (depuis config)
}
// OAuthHandlersInstance is the global instance
@ -37,11 +37,13 @@ func InitOAuthHandlers(oauthService *services.OAuthService) {
// NewOAuthHandler creates a new OAuth handler instance
// BE-API-042: Implement OAuth callback endpoint
func NewOAuthHandler(oauthService *services.OAuthService, logger interface{}, allowedRedirectOrigins []string) *OAuthHandlers {
// frontendURL: from config.FrontendURL (FRONTEND_URL or VITE_FRONTEND_URL env)
func NewOAuthHandler(oauthService *services.OAuthService, logger interface{}, allowedRedirectOrigins []string, frontendURL string) *OAuthHandlers {
return &OAuthHandlers{
oauthService: oauthService,
logger: logger,
allowedRedirectOrigins: allowedRedirectOrigins,
frontendURL: frontendURL,
}
}
@ -50,7 +52,8 @@ func NewOAuthHandlerWithInterface(oauthService OAuthServiceInterface, logger int
return &OAuthHandlers{
oauthService: oauthService,
logger: logger,
allowedRedirectOrigins: nil, // Tests use nil = dev fallback
allowedRedirectOrigins: nil, // Tests use nil = dev fallback
frontendURL: "http://localhost:5173", // Tests use localhost
}
}
@ -115,11 +118,8 @@ func (oh *OAuthHandlers) OAuthCallback(c *gin.Context) {
return
}
// Redirect to frontend with token
frontendURL := os.Getenv("FRONTEND_URL")
if frontendURL == "" {
frontendURL = "http://localhost:5173" // Fallback for development
}
// Redirect to frontend with token (frontendURL from config)
frontendURL := oh.frontendURL
// SECURITY: Validate redirect URL against allowlist to prevent open redirect
if !oh.isAllowedRedirectOrigin(frontendURL) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid redirect configuration"})