2 Commits

Author SHA1 Message Date
87595300b7 docs: обновлён план разработки - этап 2 завершён
- Отмечены все выполненные шаги этапа 2
- Добавлены результаты тестирования аутентификации
- Готово к переходу на этап 3
2025-08-27 15:06:12 +04:00
0f93308c65 style: форматирование кода - убраны лишние пустые строки 2025-08-27 15:05:25 +04:00
3 changed files with 27 additions and 19 deletions

View File

@@ -182,9 +182,9 @@ type ItemPlacement struct {
--- ---
## 🔐 Этап 2: Аутентификация (Неделя 2) ## 🔐 Этап 2: Аутентификация (Неделя 2) ✅ ЗАВЕРШЁН
### Шаг 2.1: JWT аутентификация ### Шаг 2.1: JWT аутентификация
- [x] Создать `internal/auth/jwt.go` - [x] Создать `internal/auth/jwt.go`
- [x] Реализовать генерацию и валидацию JWT токенов - [x] Реализовать генерацию и валидацию JWT токенов
- [x] Добавить organization-scope в токены - [x] Добавить organization-scope в токены
@@ -201,12 +201,12 @@ type Claims struct {
} }
``` ```
### Шаг 2.2: Хеширование паролей ### Шаг 2.2: Хеширование паролей
- [x] Создать `internal/auth/password.go` - [x] Создать `internal/auth/password.go`
- [x] Использовать bcrypt для хеширования - [x] Использовать bcrypt для хеширования
- [x] Добавить функции проверки паролей - [x] Добавить функции проверки паролей
### Шаг 2.3: API endpoints для аутентификации ### Шаг 2.3: API endpoints для аутентификации
- [x] `POST /api/auth/register` - регистрация организации и пользователя - [x] `POST /api/auth/register` - регистрация организации и пользователя
- [x] `POST /api/auth/login` - вход в систему - [x] `POST /api/auth/login` - вход в систему
- [x] `POST /api/auth/refresh` - обновление токена (опционально) - [x] `POST /api/auth/refresh` - обновление токена (опционально)
@@ -226,6 +226,13 @@ type LoginRequest struct {
} }
``` ```
**Результаты тестирования:**
- ✅ Регистрация: `POST /api/auth/register` - 201 Created
- ✅ Вход: `POST /api/auth/login` - 200 OK
- ✅ Middleware: JWT токены проходят валидацию
- ✅ JSON поля: исправлена конвертация в PostgreSQL
```
--- ---
## 🏗️ Этап 3: API структура (Неделя 3) ## 🏗️ Этап 3: API структура (Неделя 3)

View File

@@ -90,9 +90,9 @@ type OrganizationResponse struct {
// LoginResponse ответ на аутентификацию // LoginResponse ответ на аутентификацию
type LoginResponse struct { type LoginResponse struct {
Token string `json:"token"` Token string `json:"token"`
User UserResponse `json:"user"` User UserResponse `json:"user"`
Organization OrganizationResponse `json:"organization"` Organization OrganizationResponse `json:"organization"`
} }
// CreateLocationRequest запрос на создание места хранения // CreateLocationRequest запрос на создание места хранения

View File

@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"erp-mvp/core-service/internal/models" "erp-mvp/core-service/internal/models"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -29,18 +30,18 @@ func (r *organizationRepository) Create(ctx context.Context, org *models.Organiz
INSERT INTO organizations (id, name, type, settings, created_at) INSERT INTO organizations (id, name, type, settings, created_at)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
` `
// Конвертируем JSON в строку // Конвертируем JSON в строку
settingsJSON, err := json.Marshal(org.Settings) settingsJSON, err := json.Marshal(org.Settings)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshal settings: %w", err) return fmt.Errorf("failed to marshal settings: %w", err)
} }
_, err = r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, string(settingsJSON), org.CreatedAt) _, err = r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, string(settingsJSON), org.CreatedAt)
if err != nil { if err != nil {
return fmt.Errorf("failed to create organization: %w", err) return fmt.Errorf("failed to create organization: %w", err)
} }
return nil return nil
} }
@@ -50,7 +51,7 @@ func (r *organizationRepository) GetByID(ctx context.Context, id uuid.UUID) (*mo
FROM organizations FROM organizations
WHERE id = $1 WHERE id = $1
` `
var settingsJSON []byte var settingsJSON []byte
org := &models.Organization{} org := &models.Organization{}
err := r.db.QueryRowContext(ctx, query, id).Scan( err := r.db.QueryRowContext(ctx, query, id).Scan(
@@ -60,14 +61,14 @@ func (r *organizationRepository) GetByID(ctx context.Context, id uuid.UUID) (*mo
&settingsJSON, &settingsJSON,
&org.CreatedAt, &org.CreatedAt,
) )
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, fmt.Errorf("organization not found") return nil, fmt.Errorf("organization not found")
} }
return nil, fmt.Errorf("failed to get organization: %w", err) return nil, fmt.Errorf("failed to get organization: %w", err)
} }
// Конвертируем JSON строку в map // Конвертируем JSON строку в map
if len(settingsJSON) > 0 { if len(settingsJSON) > 0 {
err = json.Unmarshal(settingsJSON, &org.Settings) err = json.Unmarshal(settingsJSON, &org.Settings)
@@ -77,7 +78,7 @@ func (r *organizationRepository) GetByID(ctx context.Context, id uuid.UUID) (*mo
} else { } else {
org.Settings = make(models.JSON) org.Settings = make(models.JSON)
} }
return org, nil return org, nil
} }
@@ -87,26 +88,26 @@ func (r *organizationRepository) Update(ctx context.Context, org *models.Organiz
SET name = $2, type = $3, settings = $4 SET name = $2, type = $3, settings = $4
WHERE id = $1 WHERE id = $1
` `
// Конвертируем JSON в строку // Конвертируем JSON в строку
settingsJSON, err := json.Marshal(org.Settings) settingsJSON, err := json.Marshal(org.Settings)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshal settings: %w", err) return fmt.Errorf("failed to marshal settings: %w", err)
} }
result, err := r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, string(settingsJSON)) result, err := r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, string(settingsJSON))
if err != nil { if err != nil {
return fmt.Errorf("failed to update organization: %w", err) return fmt.Errorf("failed to update organization: %w", err)
} }
rowsAffected, err := result.RowsAffected() rowsAffected, err := result.RowsAffected()
if err != nil { if err != nil {
return fmt.Errorf("failed to get rows affected: %w", err) return fmt.Errorf("failed to get rows affected: %w", err)
} }
if rowsAffected == 0 { if rowsAffected == 0 {
return fmt.Errorf("organization not found") return fmt.Errorf("organization not found")
} }
return nil return nil
} }