{"id":49826827,"url":"https://github.com/raullopezpenalva/contact-service","last_synced_at":"2026-05-13T17:09:12.159Z","repository":{"id":340168054,"uuid":"1164634239","full_name":"raullopezpenalva/contact-service","owner":"raullopezpenalva","description":"Spring Boot microservice handling contact submissions for my personal website. Includes persistence, admin management and notification system.","archived":false,"fork":false,"pushed_at":"2026-04-17T08:34:40.000Z","size":128,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-17T10:29:35.498Z","etag":null,"topics":["backend","backend-api","backend-service","documentation","feature","infrastructure","java","security","spring-boot"],"latest_commit_sha":null,"homepage":"https://raullopezpenalva.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/raullopezpenalva.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-23T10:06:30.000Z","updated_at":"2026-04-17T08:34:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/raullopezpenalva/contact-service","commit_stats":null,"previous_names":["raullopezpenalva/contact-service"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/raullopezpenalva/contact-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raullopezpenalva%2Fcontact-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raullopezpenalva%2Fcontact-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raullopezpenalva%2Fcontact-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raullopezpenalva%2Fcontact-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raullopezpenalva","download_url":"https://codeload.github.com/raullopezpenalva/contact-service/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raullopezpenalva%2Fcontact-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32992055,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","backend-api","backend-service","documentation","feature","infrastructure","java","security","spring-boot"],"created_at":"2026-05-13T17:09:11.529Z","updated_at":"2026-05-13T17:09:12.153Z","avatar_url":"https://github.com/raullopezpenalva.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Contact Service\n\nContact Service is a Spring Boot microservice designed to handle contact form submissions for a personal website. It provides secure message persistence, administrative management, and notification capabilities, serving both as a real functional backend and a professional portfolio demonstration.\n\n---\n\n## Features\n\n- **Public REST API** for receiving contact messages (`email`, `subject`, `content`).\n- **Data validation** and secure persistence using PostgreSQL.\n- **Notification system**: Notifies the website owner via Telegram and SMTP email when a new message is received.\n- **Admin endpoints** (protected):\n\t- List messages with filtering and pagination\n\t- View message details\n\t- Change message status (`NEW`, `READ`, `ARCHIVED`, `SPAM`, `NOTIFICATION_FAILED`)\n\t- Add internal admin notes\n- **Traceability**: Stores metadata such as source IP and User-Agent for anti-abuse and debugging.\n- **Simple authentication** for admin endpoints (Basic Auth).\n- **Docker Compose** setup for local development (backend + PostgreSQL).\n\n---\n\n## Technology Stack\n\n- Java 21\n- Spring Boot 3.5.11\n- RESTful JSON API\n- Spring Data JPA + PostgreSQL\n- Event-driven design\n- Spring Mail (SMTP notifications) (MVPv1.2.0)\n- Spring Security (Basic Auth for admin endpoints)\n- Docker Compose (local infrastructure)\n\n---\n\n## Architecture\n\nThe service follows a modular clean architecture dsign.\n\nModules:\n- Contact (busines domain)\n- Notification (platform integration)\n\nThe system uses domain events to decouple business logic from architecture concerns.\n```\nClient\n  ↓\nContact Module\n  ↓\nDomain Event\n  ↓\nNotification Module\n  ↓\nTelegram API or Email SMTP\n```\n\n---\n\n## Design Decisions\n\n- Domain events are used to decouple modules.\n- Notification logic is isolated from business logic.\n- Infrastructure dependencies are kept out of the domain layer.\n- The system is designed for future extensibility (audit logs, etc).\n\n---\n\n## Domain Model\n\n### Main Entity: `ContactMessage`\n\n| Attribute            | Type                    | Nullable | Description                                                      |\n|----------------------|-------------------------|----------|------------------------------------------------------------------|\n| id                   | UUID                    | No       | Unique identifier for the message                                |\n| email                | String                  | No       | Sender's email                                                  |\n| subject              | String                  | No       | Message subject                                                 |\n| content              | String (TEXT)           | No       | Message content (long text)                                     |\n| status               | ContactMessageStatus    | No       | Current status of the message                                   |\n| adminNote            | String (TEXT)           | Yes      | Internal note for management                                    |\n| sourceIp             | String                  | Yes      | Source IP of the request                                        |\n| userAgent            | String (TEXT)           | Yes      | Client User-Agent                                               |\n| notificationAttempts | Integer                 | No       | Number of notification attempts made                             |\n| lastNotifiedAt       | Instant                 | Yes      | Timestamp of the last successful notification attempt            |\n| contentHash          | String                  | Yes      | Content hash for deduplication                                  |\n| createdAt            | Instant                 | No       | Creation date/time                                              |\n| updatedAt            | Instant                 | No       | Last update date/time                                           |\n\n---\n\n## API Flows\n\n### 1. Public: Create Contact Message\n- User submits the contact form (`email`, `subject`, `content`).\n- Backend validates and persists the message.\n- Attempts to notify the owner (does not block user response).\n- Returns `201 Created` with message `id` and `createdAt`.\n\n### 2. Admin: List Messages\n- Authenticated admin can list messages, filter by status, and paginate results.\n\n### 3. Admin: Retrieve Detailed Message by ID\n- Retrieve a specific message with comprehensive details.\n\n### 4. Admin: Change Message Status\n- Admin can update message status (`NEW`, `READ`, `ARCHIVED`, `SPAM`, `NOTIFICATION_FAILED`) and add internal notes.\n\n---\n\n## MVP Scope\n\n### Included\n- Public REST endpoint for message submission\n- Secure persistence and validation\n- Notification to owner\n- Basic admin management (list, view, change status)\n\n### Not Included\n- Attachments\n- Admin UI panel\n- Complex roles or JWT\n- Advanced rate limiting or captcha\n- Event-driven architecture\n- Physical deletion of messages\n\n---\n## Notification Strategy\n\nv1.0.0 – Telegram Bot notification  \nv1.2.0 – SMTP / Email provider integration\n---\n## Security\n\n\nThe application is secured using Spring Security. Endpoints under `/api/v1/admin/*` are protected with Basic Auth authentication.\n\nThe admin username and password can be easily changed using environment variables in the `example.env` file:\n\n```\nSPRING_SECURITY_USER_NAME=user-example\nSPRING_SECURITY_USER_PASSWORD=password-example\n```\n---\n## Domain Events \u0026 Notifications\n\nThe system uses domain events to decouple business logic from external integrations.\n\nWhen a contact request is created:\n\n1. The entity is persisted\n2. A domain event is published\n3. A notification handler reacts and persist the notification\n4. A Telegram notification is sent\n\nThis design allows adding new notification channels (email, SMS, etc.) without modifying the contact module.\n\n---\n## Documentation\n\nProjects documentation is located in `/docs`:\n\n- [`project-overview.md`](./docs/01-Project-overview.md) -- Overview of the project\n- [`MVP-scope.md`](./docs/02-MVP-scope.md) -- MVP scope\n- [`stack.md`](./docs/03-Stack.md) -- Stack decisions\n- [`domain.md`](./docs/04-Domain.md) -- Domain model definition\n- [`flows.md`](./docs/05-Flows.md) -- Functional flows (public + admin)\n- [`DTO.md`](./docs/06-DTO.md) -- DTO information\n- [`Events.md`](./docs/07-Events.md) -- Events information\n- [`Notification.md`](./docs/08-Notification.md) -- Notification information\n- [`Tests.md`](./docs/09-Tests.md) -- Tests information\n\n---\n\n## OpenAPI/Swagger\n\nThis repository integrates API documentation using **springdoc-openapi-starter-webmvc-ui**, enabling comprehensive and interactive exploration of all available endpoints. The documentation is accessible via two primary methods:\n\n- **Swagger UI**  \n  Accessible at [http://localhost:port/swagger-ui.html](http://localhost:8080/swagger-ui.html), this browser-based interface provides a user-friendly visualization of the API, allowing developers to review and test endpoints directly.\n\n- **OpenAPI JSON Specification**  \n  Available at [http://localhost:port/v3/api-docs](http://localhost:8080/v3/api-docs), this endpoint serves the OpenAPI specification in JSON format. The specification can be imported into tools such as SwaggerHub or Postman for further analysis, testing, or integration.\n\nAll OpenAPI documentation configuration is centralized in the `OpenApiConfig.java` class within the `config` package, ensuring maintainability and consistency across the service.\n\n---\n\n## Local Development\n\n1. Clone the repository.\n2. Set up environment for postgres and the app with two files:\n   1. postgres.env\n\t\tExample:\n\t\t```\n\t\tPOSTGRES_DB=example_db\n\t\tPOSTGRES_USER=user-example\n\t\tPOSTGRES_PASSWORD=password-example\n\t\t```\n   2. service.env\n\t\tExample:\n\t\t```\n\t\t# -----------------------------------------------\n\t\t# --- SPRING APPLICATION CONFIGURATION ---\n\t\t# -----------------------------------------------\n\n\t\t# --- Application Environment Variables ---\n\t\tSPRING_APPLICATION_NAME=contact-service\n\t\tSPRING_SERVER_PORT=8080\n\n\t\t# --- PostgreSQL Database Configuration ---\n\t\tSPRING_DATASOURCE_URL=jdbc:postgresql://contact_postgres:5432/example_db\n\t\tSPRING_DATASOURCE_USERNAME=user-example\n\t\tSPRING_DATASOURCE_PASSWORD=password-example\n\n\t\t# --- Security Configuration ---\n\t\tSPRING_SECURITY_USER_NAME=user-example\n\t\tSPRING_SECURITY_USER_PASSWORD=password-example\n\n\t\t# --- Spring SMTP Server Configuration ---\n\t\tSPRING_MAIL_HOST=email-host\n\t\tSPRING_MAIL_PORT=1025\n\t\tSPRING_MAIL_USERNAME=no-reply@example.com\n\n\t\t# --- Notification Service Configuration ---\n\n\t\tNOTIFICATION_ENABLED=true\n\t\tNOTIFICATIONS_CHANNELS=EMAIL\n\n\t\tTELEGRAM_BOT_TOKEN=token-example\n\t\tTELEGRAM_CHAT_ID=id-example\n\t\tTELEGRAM_API_BASE_URL=https://api.telegram.org\n\n\t\tEMAIL_RECIPIENT=email@example.com\n\t\t```\n3. Start the infrastructure with Docker Compose:\n\t ```sh\n\t docker-compose up -d --build\n\t ```\n\tRemenber to setup the host port what you want to use in the ports setup for the contact_service in the compose.yml\n\n---\n\n## Testing\n\nThe project includes both unit tests and integration tests.\n\nUnit tests verify isolated components such as mappers and domain transformations.\n\nIntegration tests start the Spring Boot context and validate the full request flow from the HTTP API down to the event-driven notification system.\n\nRun the test suite with:\n```\nmvn clean test\n```\nSee [docs/09-Tests.md](./docs/09-Tests.md) for detailed information about the testing strategy.\n\n---\n\n## Success Criteria\n\n- Users can submit contact forms and messages are stored.\n- Owner receives notifications for new messages.\n- Admin can manage messages via protected endpoints.\n- Service is deployable in a real environment.\n\n---\n\n## Project Purpose\n\nThis project is part of my backend architecture and DevOps learning path.\nIt focuses on event-driven design, modular structure and clean separation of concerns.\n\n---\n\n## Project status\n\nv1.2.0 in progress\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraullopezpenalva%2Fcontact-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraullopezpenalva%2Fcontact-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraullopezpenalva%2Fcontact-service/lists"}