Skip to content

Add training certificate endpoint with completion validation - #665

Merged
marceloarocha merged 2 commits into
developfrom
claude/training-module-certificates-3iaoeo
Sep 1, 2026
Merged

Add training certificate endpoint with completion validation#665
marceloarocha merged 2 commits into
developfrom
claude/training-module-certificates-3iaoeo

Conversation

@marceloarocha

Copy link
Copy Markdown
Collaborator

Summary

Adds a new GET /training/<id>/certificate endpoint that allows users to retrieve certificate data for completed training modules. The endpoint validates that all active lessons are finished before issuing a certificate and includes fallback logic for legacy completion records.

Key Changes

  • New Repository Functions:

    • get_training(): Retrieves active training records by ID
    • get_lesson_completion_stats(): Returns total lessons, completed lessons, and last completion timestamp for a user
    • get_training_user(): Retrieves the training completion record for a user
    • Refactored is_training_finished() to use the new get_lesson_completion_stats() function
  • New Service Function:

    • get_training_certificate(): Validates training completion and returns certificate data including user name, training title, total lessons, and completion date
    • Includes permission check for READ_BASIC_FEATURES
    • Validates that training exists and is active
    • Validates that all active lessons are completed
    • Falls back to last lesson completion date for legacy records without treinamento_usuario entries
  • New API Endpoint:

    • GET /training/<id>/certificate: Returns certificate data for completed trainings
    • Requires READ_BASIC_FEATURES permission
    • Returns 400 if training doesn't exist, is inactive, or has pending lessons
    • Returns 401 if user lacks required permissions
  • Comprehensive Test Coverage:

    • Tests successful certificate retrieval after module completion
    • Tests rejection while lessons are pending
    • Tests handling of unknown/inactive modules
    • Tests fallback to last lesson completion date for legacy records
    • Tests permission enforcement

Implementation Details

The certificate endpoint enforces strict validation: it refuses to issue certificates while any active lesson remains unfinished. This ensures certificates are only issued for truly completed modules. The implementation also handles backward compatibility by falling back to the last lesson completion timestamp for records created before the treinamento_usuario table was introduced.

https://claude.ai/code/session_011woQiKv9LnkUj5E6JeahY8

Adds GET /training/<id>/certificate returning the data the frontend needs
to render a completion certificate: user name, module title, completion
date and lesson count. The endpoint refuses unknown/inactive modules and
modules with pending lessons. The completion date comes from the
treinamento_usuario record, falling back to the last lesson-finish date
for completions recorded before that table was populated.

is_training_finished now derives from the shared lesson-completion stats
query, so the certificate and the finish flow share one source of truth.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011woQiKv9LnkUj5E6JeahY8

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This PR adds a certificate endpoint with comprehensive test coverage and clean refactoring. However, one critical issue must be fixed before merge:

Critical Issue:

  • Missing null check on user query (line 174) can cause AttributeError crashes

Approved Changes:

  • Repository refactoring extracts get_lesson_completion_stats for reuse
  • New get_training and get_training_user functions provide clear abstractions
  • Certificate validation properly enforces completion requirements
  • Comprehensive test coverage (5 test cases) covering success, validation, permissions, and legacy compatibility
  • Clean separation of concerns between route, service, and repository layers

Once the null check is added, this PR is ready to merge.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

)

# user_context is a JWT stub without the name column
user = db.session.query(User).filter(User.id == user_context.id).first()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Crash Risk: Query returns None when user doesn't exist, causing AttributeError on line 184 when accessing user.name.

Suggested change
user = db.session.query(User).filter(User.id == user_context.id).first()
user = db.session.query(User).filter(User.id == user_context.id).first()
if user is None:
raise ValidationError(
"Usuário não encontrado",
"errors.invalidUser",
status.HTTP_400_BAD_REQUEST,
)

Publishing new lessons in a module reopens it, but must not revoke
certificates already earned. The treinamento_usuario record is now the
single proof of completion: the certificate endpoint no longer matches
current active-lesson counts (and no longer requires the module to still
be active), and the lesson count printed on the certificate is what the
user actually finished back then. /training/list gains a
certificateAvailable flag derived from the same record so the frontend
can keep offering the certificate on reopened modules.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011woQiKv9LnkUj5E6JeahY8
@marceloarocha
marceloarocha merged commit aad9c0a into develop Sep 1, 2026
9 checks passed
@marceloarocha
marceloarocha deleted the claude/training-module-certificates-3iaoeo branch September 1, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants