Skip to content
Simão Barbosa edited this page Feb 27, 2026 · 1 revision

EAP: Architecture Specification and Prototype

PingPong Q&A helps communities share and build knowledge in a simple, organized way. By making it easy to ask questions, find answers, and recognize contributions, it encourages people to engage and learn together. With smart search, badges, and an interface that works on any device, the platform makes knowledge easier to discover, trust, and keep for the long term.

A7: Web Resources Specification

This artifact specifies the web architecture for the PingPong Q&A platform. It defines the catalog of resources (pages and API endpoints), their required permissions, and their request/response formats. This specification adheres to the OpenAPI standard (using YAML) to provide a clear blueprint for the vertical prototype.

1. Modules

This section provides a high-level overview of the application's architecture, organized into functional modules that group related web resources.

Module Name Description
M01: Authentication and User Profile Web resources associated with user authentication, account management, and personal profile operations. Includes registration, login and session management, profile view and edit, viewing own questions and answers, and password recovery initiation.
M02: Questions and Answers Web resources associated with creating, viewing, and managing questions and answers. Includes posting questions and answers, editing and deleting own questions and answers and editing tags on own questions.
M03: Search and Discovery Web resources associated with browsing and filtering content. Includes exact match and full-text search across questions and answers, viewing top or trending questions, and accessing personal feeds of relevant content.
M04: Moderation and Administration Web resources associated with moderation and administrative operations. Includes reviewing and managing reported content, deleting inappropriate content, managing tags (create/edit/delete/synonyms), managing user accounts and roles, and enforcing anonymization and account deletion.
M05: Static Pages and General Information Web resources associated with non-interactive informational content. Includes static pages such as About, Contact, and other informational sections, as well as a simple landing or home page with public highlights.

2. Permissions

This section defines the permission codes used throughout the API, specifying the access rights required for each type of user, from public visitors to administrators.

Code Name Description
PUB Public Users without authentication; can browse public content and static pages.
USR User Authenticated users with general access to platform features such as viewing, replying, searching and asking questions.
OWN Owner Authenticated users acting on resources they created or own (e.g., their own profile, questions, answers, or comments).
MOD Moderator Users with moderation privileges; can review reports, remove inappropriate content, and enforce rules.
ADM Administrator System administrators with full control over users, tags, and platform configuration.

3. OpenAPI Specification

The following YAML document provides the complete and formal OpenAPI specification for the web resources, pages, and API endpoints included in the vertical prototype.

a7_openapi.yaml

openapi: 3.0.0

info:
  version: '1.0'
  title: 'PingPong Q&A Web API'
  description: 'Web Resources Specification (A7) for the PingPong Q&A'

servers:
  - url: http://lbaw.fe.up.pt
    description: Production server

tags:
  - name: 'M01: Authentication and User Profile'
  - name: 'M02: Questions and Answers'
  - name: 'M03: Search and Discovery'
  - name: 'M04: Moderation and Administration'
  - name: 'M05: Static Pages and General Information'

paths:
  /register:
    get:
      operationId: R101
      summary: 'R101: Registration Form'
      description: 'Display the sign-up form. Access: PUB'
      tags:
        - 'M01: Authentication and User Profile'
      responses:
        '200':
          description: 'OK. Show registration UI.'
    post:
      operationId: R102
      summary: 'R102: Registration Action'
      description: 'Process the sign-up submission and create a member account. Access: PUB'
      tags:
        - 'M01: Authentication and User Profile'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                username:
                  type: string
                email:
                  type: string
                  format: email
                password:
                  type: string
                  format: password
                displayName:
                  type: string
              required:
                - username
                - email
                - password
      responses:
        '302':
          description: 'Redirect after creating the account.'
          headers:
            Location:
              schema:
                type: string
              examples:
                success:
                  description: 'Account created; redirect to personal feed.'
                  value: '/me/feed'
                failure:
                  description: 'Validation failed; redirect back to registration.'
                  value: '/register'

  /login:
    get:
      operationId: R103
      summary: 'R103: Login Form'
      description: 'Display the login form. Access: PUB'
      tags:
        - 'M01: Authentication and User Profile'
      responses:
        '200':
          description: 'OK. Show login UI.'
    post:
      operationId: R104
      summary: 'R104: Login Action'
      description: 'Authenticate member credentials and start a session. Access: PUB'
      tags:
        - 'M01: Authentication and User Profile'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                username:
                  type: string
                password:
                  type: string
                  format: password
                rememberMe:
                  type: boolean
              required:
                - username
                - password
      responses:
        '302':
          description: 'Redirect after login attempt.'
          headers:
            Location:
              schema:
                type: string
              examples:
                success:
                  description: 'Authentication succeeded; redirect to personal feed.'
                  value: '/me/feed'
                failure:
                  description: 'Authentication failed; redirect back to login.'
                  value: '/login'

  /logout:
    post:
      operationId: R105
      summary: 'R105: Logout Action'
      description: 'Invalidate the current session. Access: USR'
      tags:
        - 'M01: Authentication and User Profile'
      responses:
        '302':
          description: 'Redirect after logout.'
          headers:
            Location:
              schema:
                type: string
              example: '/'

  /me/profile:
    get:
      operationId: R201
      summary: 'R201: View Own Profile'
      description: 'Display the authenticated member profile information. Access: OWN'
      tags:
        - 'M01: Authentication and User Profile'
      responses:
        '200':
          description: 'OK. Show profile UI.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileDetail'
    put:
      operationId: R202
      summary: 'R202: Update Own Profile'
      description: 'Update display name, bio, avatar and preferences. Access: OWN'
      tags:
        - 'M01: Authentication and User Profile'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                displayName:
                  type: string
                bio:
                  type: string
                avatar:
                  type: string
                  format: binary
                preferences:
                  type: object
                  additionalProperties: true
      responses:
        '200':
          description: 'Profile updated. Return the fresh data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileDetail'

  /me/profile/edit:
    get:
      operationId: R208
      summary: 'R208: Edit Profile Form'
      description: 'Display profile edit form. Access: OWN'
      tags:
        - 'M01: Authentication and User Profile'
      responses:
        '200':
          description: 'OK. Show profile edit UI.'

  /users/{id}:
    get:
      operationId: R209
      summary: 'R209: View User Profile'
      description: 'Display another user profile information. Access: USR'
      tags:
        - 'M01: Authentication and User Profile'
      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true
      responses:
        '200':
          description: 'OK. Show user profile UI.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileDetail'

  /me/feed:
    get:
      operationId: R203
      summary: 'R203: Personal Feed'
      description: 'List personalized feed entries for followed tags and questions. Access: USR'
      tags:
        - 'M03: Search and Discovery'
      parameters:
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
          required: false
        - in: query
          name: pageSize
          schema:
            type: integer
            default: 20
          required: false
      responses:
        '200':
          description: 'OK. Return paginated feed entries.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/FeedItem'
                  pagination:
                    $ref: '#/components/schemas/PaginationMetadata'

  /search:
    get:
      operationId: R206
      summary: 'R206: Search Page'
      description: 'Display search interface. Access: USR'
      tags:
        - 'M03: Search and Discovery'
      responses:
        '200':
          description: 'OK. Show search UI.'

  /api/search:
    get:
      operationId: R207
      summary: 'R207: Search API'
      description: 'Search API endpoint for questions. Access: USR'
      tags:
        - 'M03: Search and Discovery'
      parameters:
        - in: query
          name: q
          schema:
            type: string
          description: 'Search query.'
      responses:
        '200':
          description: 'OK. Return search results.'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/QuestionSummary'

  /me/questions:
    get:
      operationId: R204
      summary: 'R204: List Own Questions'
      description: 'Retrieve a paginated list of questions authored by the member. Access: OWN'
      tags:
        - 'M01: Authentication and User Profile'
      parameters:
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
        - in: query
          name: status
          schema:
            type: string
            description: 'Optional status filter (open, answered, closed).'
      responses:
        '200':
          description: 'OK. Return question summaries.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/QuestionSummary'
                  pagination:
                    $ref: '#/components/schemas/PaginationMetadata'

  /me/answers:
    get:
      operationId: R205
      summary: 'R205: List Own Answers'
      description: 'Retrieve a paginated list of answers authored by the member. Access: OWN'
      tags:
        - 'M01: Authentication and User Profile'
      parameters:
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
      responses:
        '200':
          description: 'OK. Return answer summaries.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AnswerSummary'
                  pagination:
                    $ref: '#/components/schemas/PaginationMetadata'

  /questions:
    get:
      operationId: R301
      summary: 'R301: Browse & Search Questions'
      description: 'Browse public questions with support for pagination and exact/full-text search. Access: PUB'
      tags:
        - 'M03: Search and Discovery'
      parameters:
        - in: query
          name: q
          schema:
            type: string
          description: 'Search phrase applied to titles and content.'
        - in: query
          name: match
          schema:
            type: string
            enum:
              - exact
              - full
          description: 'Select between exact-match (US11) or full-text (US12) search.'
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
          description: 'Pagination page number.'
        - in: query
          name: pageSize
          schema:
            type: integer
            default: 20
          description: 'Number of results per page.'
      responses:
        '200':
          description: 'OK. Return question results.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/QuestionSummary'
                  pagination:
                    $ref: '#/components/schemas/PaginationMetadata'
    post:
      operationId: R302
      summary: 'R302: Create Question'
      description: 'Submit a new question with title, body and tags. Access: USR'
      tags:
        - 'M02: Questions and Answers'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                title:
                  type: string
                body:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
                attachments:
                  type: array
                  items:
                    type: string
                    format: binary
              required:
                - title
                - body
      responses:
        '201':
          description: 'Question created.'
          headers:
            Location:
              schema:
                type: string
              example: '/questions/42'

  /top:
    get:
      operationId: R303
      summary: 'R303: Top Questions'
      description: 'Retrieve highlighted questions sorted by score and acceptance. Access: PUB'
      tags:
        - 'M03: Search and Discovery'
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            default: 10
          description: 'Maximum number of highlighted questions.'
      responses:
        '200':
          description: 'OK. Return highlighted questions.'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/QuestionSummary'

  /questions/{questionId}:
    put:
      operationId: R304
      summary: 'R304: Update Question'
      description: 'Edit the title and body of an owned question. Access: OWN, MOD'
      tags:
        - 'M02: Questions and Answers'
      parameters:
        - in: path
          name: questionId
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                body:
                  type: string
              required:
                - title
                - body
      responses:
        '200':
          description: 'Question updated.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuestionDetail'
    delete:
      operationId: R305
      summary: 'R305: Delete Question'
      description: 'Remove an owned question (with anonymization rules applied). Access: OWN, MOD'
      tags:
        - 'M02: Questions and Answers'
      parameters:
        - in: path
          name: questionId
          schema:
            type: integer
          required: true
      responses:
        '204':
          description: 'Question removed.'

  /questions/{questionId}/tags:
    put:
      operationId: R306
      summary: 'R306: Update Question Tags'
      description: 'Replace the tag set of an owned question. Access: OWN, MOD'
      tags:
        - 'M02: Questions and Answers'
      parameters:
        - in: path
          name: questionId
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                tags:
                  type: array
                  items:
                    type: string
              required:
                - tags
      responses:
        '200':
          description: 'Tags updated.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuestionDetail'

  /questions/{questionId}/answers:
    post:
      operationId: R401
      summary: 'R401: Post Answer'
      description: 'Submit an answer to a question. Access: USR'
      tags:
        - 'M02: Questions and Answers'
      parameters:
        - in: path
          name: questionId
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                body:
                  type: string
              required:
                - body
      responses:
        '201':
          description: 'Answer created.'
          headers:
            Location:
              schema:
                type: string
              example: '/answers/128'

  /answers/{answerId}:
    put:
      operationId: R402
      summary: 'R402: Update Answer'
      description: 'Edit an owned answer. Access: OWN, MOD'
      tags:
        - 'M02: Questions and Answers'
      parameters:
        - in: path
          name: answerId
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                body:
                  type: string
              required:
                - body
      responses:
        '200':
          description: 'Answer updated.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnswerDetail'
    delete:
      operationId: R403
      summary: 'R403: Delete Answer'
      description: 'Remove an owned answer. Access: OWN, MOD'
      tags:
        - 'M02: Questions and Answers'
      parameters:
        - in: path
          name: answerId
          schema:
            type: integer
          required: true
      responses:
        '204':
          description: 'Answer removed.'

  /moderator/reports:
    get:
      operationId: R501
      summary: 'R501: List Content Reports'
      description: 'Retrieve reported content with context for triage. Access: MOD'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: query
          name: status
          schema:
            type: string
            enum:
              - pending
              - in_review
              - resolved
          required: false
      responses:
        '200':
          description: 'OK. Return reported items.'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ReportEntry'

  /moderator/cases/{type}/{id}:
    put:
      operationId: R502
      summary: 'R502: Update Case Status'
      description: 'Update the status or actions taken for a moderation case. Access: MOD'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: type
          schema:
            type: string
          required: true
          description: 'The type of content (question, answer, comment).'
        - in: path
          name: id
          schema:
            type: integer
          required: true
          description: 'The ID of the content.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  enum:
                    - pending
                    - in_review
                    - resolved
                resolutionNotes:
                  type: string
      responses:
        '200':
          description: 'Case updated.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportEntry'

  /admin:
    get:
      operationId: R600
      summary: 'R600: Admin Dashboard'
      description: 'Display admin dashboard. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      responses:
        '200':
          description: 'OK. Show admin dashboard.'

  /admin/tags:
    get:
      operationId: R601
      summary: 'R601: List Tags'
      description: 'Retrieve available tags for management. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      responses:
        '200':
          description: 'OK. Return tags.'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TagDetail'
    post:
      operationId: R602
      summary: 'R602: Create Tag'
      description: 'Create a new tag or synonym. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                synonyms:
                  type: array
                  items:
                    type: string
              required:
                - name
      responses:
        '201':
          description: 'Tag created.'
          headers:
            Location:
              schema:
                type: string
              example: '/admin/tags/12'

  /admin/tags/{tagId}:
    put:
      operationId: R603
      summary: 'R603: Update Tag'
      description: 'Edit an existing tag or its synonyms. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: tagId
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                synonyms:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: 'Tag updated.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TagDetail'
    delete:
      operationId: R604
      summary: 'R604: Delete Tag'
      description: 'Remove a tag from the taxonomy. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: tagId
          schema:
            type: integer
          required: true
      responses:
        '204':
          description: 'Tag deleted.'

  /admin/tags/{tag}/merge:
    get:
      operationId: R604a
      summary: 'R604a: Show Tag Merge Form'
      description: 'Display form to merge tags. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: tag
          schema:
            type: integer
          required: true
      responses:
        '200':
          description: 'OK. Show merge form.'
    post:
      operationId: R604b
      summary: 'R604b: Merge Tags'
      description: 'Merge one tag into another. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: tag
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                targetTagId:
                  type: integer
              required:
                - targetTagId
      responses:
        '200':
          description: 'Tags merged.'

  /admin/tags/{tag}/synonyms:
    post:
      operationId: R604c
      summary: 'R604c: Add Tag Synonym'
      description: 'Add a synonym to a tag. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: tag
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                synonym:
                  type: string
              required:
                - synonym
      responses:
        '200':
          description: 'Synonym added.'
    delete:
      operationId: R604d
      summary: 'R604d: Remove Tag Synonym'
      description: 'Remove a synonym from a tag. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: tag
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                synonym:
                  type: string
              required:
                - synonym
      responses:
        '200':
          description: 'Synonym removed.'

  /admin/users:
    get:
      operationId: R605
      summary: 'R605: Search Users'
      description: 'Search, filter and list user accounts. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: query
          name: query
          schema:
            type: string
          description: 'Search by username or email.'
        - in: query
          name: role
          schema:
            type: string
            enum:
              - member
              - moderator
              - admin
          required: false
      responses:
        '200':
          description: 'OK. Return user accounts.'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/UserAdminSummary'
    post:
      operationId: R606
      summary: 'R606: Create User Account'
      description: 'Create a new user account or elevate roles. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
                email:
                  type: string
                  format: email
                role:
                  type: string
                  enum:
                    - member
                    - moderator
                    - admin
                temporaryPassword:
                  type: string
              required:
                - username
                - email
      responses:
        '201':
          description: 'User account created.'
          headers:
            Location:
              schema:
                type: string
              example: '/admin/users/73'

  /admin/users/{userId}:
    get:
      operationId: R607
      summary: 'R607: View User Account'
      description: 'Fetch account details and roles. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: userId
          schema:
            type: integer
          required: true
      responses:
        '200':
          description: 'OK. Return account detail.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserAdminDetail'
    put:
      operationId: R608
      summary: 'R608: Update User Account'
      description: 'Edit account fields and roles. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: userId
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserAdminUpdate'
      responses:
        '200':
          description: 'Account updated.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserAdminDetail'
    delete:
      operationId: R609
      summary: 'R609: Delete User Account'
      description: 'Delete a user account according to policy. This action automatically anonymizes all user contributions (questions, answers, comments) as per BR.011. Access: ADM'
      tags:
        - 'M04: Moderation and Administration'
      parameters:
        - in: path
          name: userId
          schema:
            type: integer
          required: true
      responses:
        '204':
          description: 'User deleted.'

components:
  schemas:
    PaginationMetadata:
      type: object
      properties:
        page:
          type: integer
        pageSize:
          type: integer
        totalItems:
          type: integer
        totalPages:
          type: integer
    ProfileDetail:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        displayName:
          type: string
        bio:
          type: string
        avatarUrl:
          type: string
          format: uri
        preferences:
          type: object
          additionalProperties: true
    FeedItem:
      type: object
      properties:
        id:
          type: integer
        type:
          type: string
          enum:
            - question
            - answer
        question:
          $ref: '#/components/schemas/QuestionSummary'
        answer:
          $ref: '#/components/schemas/AnswerSummary'
        createdAt:
          type: string
          format: date-time
    QuestionSummary:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        excerpt:
          type: string
        score:
          type: integer
        answersCount:
          type: integer
        tags:
          type: array
          items:
            type: string
        createdAt:
          type: string
          format: date-time
    QuestionDetail:
      allOf:
        - $ref: '#/components/schemas/QuestionSummary'
        - type: object
          properties:
            body:
              type: string
    AnswerSummary:
      type: object
      properties:
        id:
          type: integer
        questionId:
          type: integer
        excerpt:
          type: string
        score:
          type: integer
        createdAt:
          type: string
          format: date-time
    AnswerDetail:
      allOf:
        - $ref: '#/components/schemas/AnswerSummary'
        - type: object
          properties:
            body:
              type: string
    ReportEntry:
      type: object
      properties:
        id:
          type: integer
        contentType:
          type: string
          enum:
            - question
            - answer
            - comment
        contentId:
          type: integer
        reporter:
          type: string
        reason:
          type: string
        status:
          type: string
          enum:
            - pending
            - in_review
            - resolved
        submittedAt:
          type: string
          format: date-time
        resolutionNotes:
          type: string
    TagDetail:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        synonyms:
          type: array
          items:
            type: string
    UserAdminSummary:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string
        role:
          type: string
    UserAdminDetail:
      allOf:
        - $ref: '#/components/schemas/UserAdminSummary'
        - type: object
          properties:
            displayName:
              type: string
            reputation:
              type: integer
            badges:
              type: array
              items:
                type: string
    UserAdminUpdate:
      type: object
      properties:
        email:
          type: string
          format: email
        role:
          type: string
          enum:
            - member
            - moderator
            - admin
        temporaryPassword:
          type: string
        notes:
          type: string

A8: Vertical prototype

The Vertical Prototype delivers a fully functional slice of the application's core, validating the architectural stack from the database to the user interface by implementing high-priority user stories. Its primary goal is to prove the technical feasibility of critical features and establish a stable foundation for subsequent development phases.

1. Implemented Features

1.1. Implemented User Stories

The following table lists the user stories completed in this prototype, including their priority and the developer responsible for their implementation.

User Story reference Name Priority Responsible Description
US01 Sign-up / Registration Very High Simão Barbosa As a Visitor, I want to register an account, so that I can become an authenticated member and contribute to the community.
US02 Sign-in / Login Very High Simão Barbosa As a Visitor, I want to log in, so that I can access member-only features.
US11 Exact Match Search High Raul Oliveira As a User, I want to perform an exact-match search over questions and answers, so that I can find specific phrases or precise content.
US12 Full-text Search High Alexandre Ferreira As a User, I want to perform full-text search across questions and answers, so that I can find relevant discussions using natural language queries.
US13 View Top Questions (Home Highlights) Medium Raul Oliveira As a User, I want to view the top (highest voted/accepted) questions on the homepage, so that I can quickly find high-quality content.
US14 Browse Questions (pagination/list) High Dinis Lima As a User, I want to browse questions in a paginated/list view, so that I can explore topics without needing to search.
US21 View Personal Feed (followed tags/questions) High Dinis Lima As a Member, I want to view a personal feed of questions and answers based on my followed tags and follows, so that I can see relevant, personalized content.
US22 Post Question Very High Simão Barbosa As a Member, I want to post a new question (title, body, tags, optional attachments), so that I can ask the community for help or share knowledge.
US23 Post Answer Very High Raul Oliveira As a Member, I want to post answers to questions, so that I can contribute solutions and be recognized by the community.
US24 Edit Own Profile (view & edit) High Alexandre Ferreira As a Member, I want to view and edit my profile (display name, bio, picture, preferences), so that my public presence is accurate and helpful.
US25 Login/Logout (session management) High Simão Barbosa As a Member, I want to log out and have session management (remember me), so that my account is secure and accessible when needed.
US26 View My Questions Medium Simão Barbosa As a Member, I want a page listing my own questions (with status & metrics), so that I can manage and follow progress on my posts.
US27 View My Answers Medium Raul Oliveira As a Member, I want a page listing my own answers (with metrics), so that I can track my contributions and follow-up.
US31 Edit Question (own) High Dinis Lima As an Author, I want to edit my own question (title, body), so that I can clarify or correct information after posting.
US32 Delete Question (own) High Simão Barbosa As an Author, I want to delete my own question, so that I can remove content I no longer want public (subject to anonymization rules).
US33 Edit Answer (own) High Raul Oliveira As an Author, I want to edit my own answers, so that I can improve accuracy or fix mistakes.
US34 Delete Answer (own) High Raul Oliveira As an Author, I want to delete my own answer, so that I can remove outdated or incorrect contributions.
US35 Edit Question Tags (own question) High Dinis Lima As an Author, I want to edit the tags on my question, so that it is categorized correctly and reaches the right audience.
US41 Review and Manage Content Reports High Simão Barbosa As a Moderator, I want to view and triage reported content with context and history, so that I can decide on appropriate moderation actions.
US42 Delete Content (questions/answers/comments) High Dinis Lima As a Moderator, I want to delete or remove content that violates rules, so that the community remains safe and high-quality.
US51 Manage Tags (create/edit/delete, synonyms) Very High Dinis Lima As an Administrator, I want to manage tags (create, merge, delete, add synonyms), so that taxonomy is consistent and searchable.
US52 Administer User Accounts (search/view/edit/create) High Alexandre Ferreira As an Administrator, I want to search for, view, edit, and create user accounts (including promoting to moderator/admin), so that I can maintain community membership and roles.
US53 Enforce Account Deletion Anonymization Rule Very High Alexandre Ferreira As an Administrator, I want the system to anonymize contributions upon account deletion (retain content but remove PII), so that privacy rules are respected while preserving knowledge.
US54 Delete User Account High Alexandre Ferreira As an Administrator, I want to delete user accounts when necessary, so that I can remove inappropriate accounts in accordance with platform policies.

1.2. Implemented Web Resources

This section maps the implemented functionality to specific web resources and their corresponding URLs, organized by module.

Module M01: Authentication and User Profile
Web Resource Reference URL
R101: Registration Form GET /register
R102: Registration Action POST /register
R103: Login Form GET /login
R104: Login Action POST /login
R105: Logout Action POST /logout
R201: View Own Profile GET /me/profile
R202: Update Own Profile PUT /me/profile
R205: List Own Answers GET /me/answers
Module M02: Questions and Answers
Web Resource Reference URL
R302: Create Question POST /questions
R305: Delete Question DELETE /questions/{id}
R401: Post Answer POST /questions/{id}/answers
R402: Update Answer PUT /answers/{id}
R403: Delete Answer DELETE /answers/{id}
Module M03: Search and Discovery
Web Resource Reference URL
R203: Personal Feed GET /me/feed
R301: Browse & Search Questions GET /search
R303: Top Questions GET /top
R307: View Question Details GET /questions/{id}
Module M04: Moderation and Administration
Web Resource Reference URL
R600: Admin Dashboard GET /admin
R605: Search Users GET /admin/users
R606: Create User Account POST /admin/users
R607: View User Account GET /admin/users/{id}
R608: Update User Account PUT /admin/users/{id}
R609: Delete User Account DELETE /admin/users/{id}

2. Prototype

The prototype Docker image can be run with:

docker run -d --name lbaw2522 -p 8001:80 gitlab.up.pt:5050/lbaw/lbaw2526/lbaw2522

The application will be available at http://localhost:8001.

To stop and remove the container:

docker stop lbaw2522
docker rm lbaw2522

Authenticated Users Credentials

Role Username Password
Admin admin_user 1234
Moderator mod_user 1234
Member raul 1234
Member simao 1234
Member alex 1234
Member dinis 1234

Revision history

Changes made to the first submission:

  1. None

GROUP2522, 25/11/2025

Clone this wiki locally