{"id":50925663,"url":"https://github.com/carlos-aisa/outreachflow","last_synced_at":"2026-06-16T23:00:35.153Z","repository":{"id":355720113,"uuid":"1229305007","full_name":"carlos-aisa/OutreachFlow","owner":"carlos-aisa","description":"A lightweight CRM and controlled email outreach manager for contacts, templates, drafts, attachments, and communication history.","archived":false,"fork":false,"pushed_at":"2026-06-14T21:25:55.000Z","size":534,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T23:13:10.898Z","etag":null,"topics":["aspnetcore","blazor","clean-architecture","contact-management","crm","dotnet","ef-core","email-outreach","sqlite"],"latest_commit_sha":null,"homepage":"","language":"C#","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/carlos-aisa.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-04T23:01:17.000Z","updated_at":"2026-06-14T21:24:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"3d314410-1b07-404a-9f36-fbf1ac175aa0","html_url":"https://github.com/carlos-aisa/OutreachFlow","commit_stats":null,"previous_names":["carlos-aisa/outreachflow"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/carlos-aisa/OutreachFlow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlos-aisa%2FOutreachFlow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlos-aisa%2FOutreachFlow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlos-aisa%2FOutreachFlow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlos-aisa%2FOutreachFlow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/carlos-aisa","download_url":"https://codeload.github.com/carlos-aisa/OutreachFlow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlos-aisa%2FOutreachFlow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34426745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["aspnetcore","blazor","clean-architecture","contact-management","crm","dotnet","ef-core","email-outreach","sqlite"],"created_at":"2026-06-16T23:00:15.626Z","updated_at":"2026-06-16T23:00:35.142Z","avatar_url":"https://github.com/carlos-aisa.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OutreachFlow\n\n[![CI](https://github.com/carlos-aisa/OutreachFlow/actions/workflows/ci.yml/badge.svg)](https://github.com/carlos-aisa/OutreachFlow/actions/workflows/ci.yml)\n[![Coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/carlos-aisa/OutreachFlow/main/.github/badges/coverage.json)](https://github.com/carlos-aisa/OutreachFlow/actions/workflows/ci.yml)\n[![Latest Release](https://img.shields.io/github/v/release/carlos-aisa/OutreachFlow?sort=semver)](https://github.com/carlos-aisa/OutreachFlow/releases)\n[![.NET](https://img.shields.io/badge/.NET-8-512BD4)](https://dotnet.microsoft.com/)\n[![OpenAPI](https://img.shields.io/badge/OpenAPI-v1-6BA539)](docs/api/openapi.v1.yaml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nOutreachFlow is a lightweight CRM and controlled email outreach manager for small teams and independent professionals. It helps organize contacts, classify audiences with flexible tags, generate personalized drafts from reusable templates, attach reusable assets, send through configurable providers, and keep a complete communication history.\n\nCurrent stable line: `v0.19.0` ([CHANGELOG](CHANGELOG.md), [Releases](https://github.com/carlos-aisa/OutreachFlow/releases)).\n\n## Table of Contents\n\n- [Why OutreachFlow](#why-outreachflow)\n- [What It Is Not](#what-it-is-not)\n- [Project Highlights](#project-highlights)\n- [Feature Scope](#feature-scope)\n- [Technology Stack](#technology-stack)\n- [Architecture](#architecture)\n- [Repository Structure](#repository-structure)\n- [API and Contracts](#api-and-contracts)\n- [Local Setup](#local-setup)\n- [Quality and CI](#quality-and-ci)\n- [Testing Matrix](#testing-matrix)\n- [Release Strategy](#release-strategy)\n- [Documentation Map](#documentation-map)\n- [Roadmap](#roadmap)\n- [Contributing](#contributing)\n- [Security](#security)\n\n## Why OutreachFlow\n\nMany small organizations need outreach discipline but not enterprise CRM complexity. OutreachFlow focuses on a practical middle ground:\n\n- Contact-centric workflow with full traceability\n- Human approval before send\n- Provider abstraction (`Fake`, `SMTP`, and future providers)\n- Rules that block unsafe sending (Do Not Contact, unresolved variables, duplicate/equivalent recent send protection)\n\n### Who It Is For\n\n- Freelancers\n- Small businesses\n- NGOs\n- Consultants\n- Trainers and educators\n- Associations\n- Independent professionals\n- Small teams needing controlled external communication\n\n## What It Is Not\n\nOutreachFlow is not a spam engine and is not designed for aggressive bulk mailing, scraping, or invasive automation.\n\n## Project Highlights\n\n- Clean layered architecture with strict dependency direction\n- Explicit business rules in Domain and Application layers\n- Template rendering engine with unknown/missing variable diagnostics\n- Controlled draft lifecycle: generate, review, approve, send, audit\n- Provider abstraction and swap-ready infrastructure design\n- Rich automated test suite across domain, application, and integration levels\n- OpenSpec-driven delivery with one-change-per-branch workflow\n- CI with coverage reporting visible in PRs and README badge\n- Manual, auditable release process based on archived OpenSpec changes\n\n## Feature Scope\n\n### Completed\n\n- Organizations, contacts, tags, and status management\n- Sender profiles and email templates with variable catalog\n- Sender profile signatures (HTML/RTF) with validation and draft-body append behavior\n- Attachment assets and template default attachments\n- Draft generation, review, approval, cancellation, and controlled send\n- Activity timeline (contact and email events)\n- SMTP provider support (configuration-based)\n- Follow-up tasks with optional post-send automation\n- CSV contact imports with preview, duplicate detection, tag assignment, and import job tracking\n- Windows installer wizard distribution (`setup.exe` + `.msi`) for API and Web deployment\n- Spanish localization across the supported Web workflows, including dashboard, contacts, sender profiles, templates, drafts, follow-ups, attachments, and imports, with persisted language selection\n- Dedicated Settings page with persisted language and theme preferences, including system/light/dark workspace theming\n\n### Next\n\n- Future providers (Gmail API, Microsoft Graph)\n- Queue and throttling controls\n- PostgreSQL support profile\n\n## Technology Stack\n\n- .NET 8\n- ASP.NET Core Web API\n- Blazor Web App\n- EF Core + SQLite\n- xUnit + FluentAssertions\n- Swagger/OpenAPI\n- GitHub Actions (CI, coverage, release workflow)\n\n## Architecture\n\n- `OutreachFlow.Domain`: entities, value objects, business invariants\n- `OutreachFlow.Application`: use cases, DTOs, service contracts, orchestration rules\n- `OutreachFlow.Infrastructure`: EF Core persistence, repositories, migrations, provider implementations\n- `OutreachFlow.Api`: REST endpoints and API composition\n- `OutreachFlow.Web`: Blazor Web App management UI\n\nDetailed architecture document: [docs/architecture/ARCHITECTURE.md](docs/architecture/ARCHITECTURE.md)\n\n## Repository Structure\n\n```text\nOutreachFlow/\n|- src/\n|  |- OutreachFlow.Domain/\n|  |- OutreachFlow.Application/\n|  |- OutreachFlow.Infrastructure/\n|  |- OutreachFlow.Api/\n|  |- OutreachFlow.Web/\n|- tests/\n|  |- OutreachFlow.Domain.Tests/\n|  |- OutreachFlow.Application.Tests/\n|  |- OutreachFlow.IntegrationTests/\n|- docs/\n|  |- api/openapi.v1.yaml\n|  |- architecture/ARCHITECTURE.md\n|  |- standards/\n|- openspec/\n|- scripts/\n|- CHANGELOG.md\n|- VERSION\n|- README.md\n```\n\n## API and Contracts\n\n- OpenAPI contract: [docs/api/openapi.v1.yaml](docs/api/openapi.v1.yaml)\n- Swagger UI is enabled in local API runs\n- API uses `/api/v1/*` versioned routes\n\nCurrent endpoint groups:\n\n- Organizations\n- Contacts, contact tags, and activities\n- Tags\n- Sender profiles\n- Templates and template attachments\n- Attachment assets\n- Draft generation, review, approval, cancellation, and send\n- Follow-up tasks\n\n## Local Setup\n\n### Prerequisites\n\n- .NET SDK 8.x\n- Git\n\n### Run\n\n1. Restore dependencies.\n\n```bash\ndotnet restore\n```\n\n2. Apply migrations (optional; API also applies pending migrations on startup).\n\n```bash\ndotnet ef database update --project src/OutreachFlow.Infrastructure --startup-project src/OutreachFlow.Api\n```\n\n3. Run API.\n\n```bash\ndotnet run --project src/OutreachFlow.Api\n```\n\n4. Run Web UI.\n\n```bash\ndotnet run --project src/OutreachFlow.Web\n```\n\nDefault local API base URL expected by Web: `http://localhost:5131`.\n\n### Optional SMTP Configuration (Local Only)\n\n```bash\ndotnet user-secrets set \"EmailSending:Provider\" \"SMTP\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"EmailSending:Smtp:Host\" \"smtp.example.com\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"EmailSending:Smtp:Port\" \"587\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"EmailSending:Smtp:UseSsl\" \"true\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"EmailSending:Smtp:Username\" \"your-user\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"EmailSending:Smtp:Password\" \"your-password\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"EmailSending:Smtp:TimeoutSeconds\" \"30\" --project src/OutreachFlow.Api\n```\n\n### Optional Follow-up Automation\n\n```bash\ndotnet user-secrets set \"FollowUpAutomation:AutoCreateAfterSuccessfulSend\" \"true\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"FollowUpAutomation:DueDaysAfterSend\" \"7\" --project src/OutreachFlow.Api\ndotnet user-secrets set \"FollowUpAutomation:DefaultType\" \"Email\" --project src/OutreachFlow.Api\n```\n\n## Quality and CI\n\n### Tests\n\n```bash\ndotnet test\n```\n\n### Pull Request CI\n\n- `dotnet restore`\n- `dotnet build --configuration Release --no-restore`\n- `dotnet test --configuration Release --no-build --collect:\"XPlat Code Coverage\"`\n- Merged coverage summary via ReportGenerator\n- Sticky PR comment with total coverage\n- HTML coverage report artifact upload\n- Coverage badge refresh on `main`\n\nCoverage is report-only (no threshold gate yet).\n\n### Engineering Quality Gates\n\n| Area | Mechanism | Signal |\n| --- | --- | --- |\n| Build and tests | `.github/workflows/ci.yml` | Required quality baseline for PRs |\n| Coverage visibility | ReportGenerator summary + sticky PR comment + README badge | Continuous visibility without hard gate |\n| Release control | `.github/workflows/release-openspec-change.yml` | Manual, auditable SemVer releases from archived OpenSpec changes |\n| Branch governance | `change/\u003cchange-id-or-short-description\u003e` validation in CI | One change per branch and review-ready traceability |\n\n## Testing Matrix\n\nRun all automated tests:\n\n```bash\ndotnet test\n```\n\nRun by suite:\n\n```bash\ndotnet test tests/OutreachFlow.Domain.Tests\ndotnet test tests/OutreachFlow.Application.Tests\ndotnet test tests/OutreachFlow.IntegrationTests\n```\n\n## CSV Import Format\n\nOutreachFlow CSV imports are review-first: preview always runs before commit.\n\n- Required headers: `displayName`, `email`\n- Optional headers: `phone`, `role`, `source`\n- Encoding: UTF-8 text CSV\n- Duplicate detection: normalized email against current database contacts and repeated emails in the same CSV file\n- Commit behavior: only valid non-duplicate rows are created\n- Tag assignment: selected existing tag ids are assigned to each imported contact\n- Scope limits: no Excel import, no Google/Outlook contacts sync, and no background batch processing in current phase\n\n## Release Strategy\n\nReleases are manual and controlled after an OpenSpec change is completed.\n\n1. Implement one OpenSpec change in `change/\u003cid\u003e` branch.\n2. Complete tasks in `tasks.md`.\n3. Archive change under `openspec/changes/archive/`.\n4. Bump `VERSION` and add matching `CHANGELOG.md` section.\n5. Merge to `main` after CI passes.\n6. Run `release-openspec-change` workflow with `change_id` and `version`.\n7. Download release assets:\n   - `OutreachFlow-v\u003cversion\u003e-win-x64-setup.exe`\n   - `OutreachFlow-v\u003cversion\u003e-win-x64.msi`\n\nVersioning follows Semantic Versioning (`vX.Y.Z`).\n\n## Documentation Map\n\n- Architecture baseline: [docs/architecture/ARCHITECTURE.md](docs/architecture/ARCHITECTURE.md)\n- OpenAPI contract: [docs/api/openapi.v1.yaml](docs/api/openapi.v1.yaml)\n- Engineering standards: [docs/standards](docs/standards)\n- Future integration boundaries: [docs/architecture/FUTURE_INTEGRATIONS.md](docs/architecture/FUTURE_INTEGRATIONS.md)\n- Installer packaging details: [docs/release/INSTALLER_RELEASE.md](docs/release/INSTALLER_RELEASE.md)\n- Localization setup and translation keys: [docs/localization/LOCALIZATION.md](docs/localization/LOCALIZATION.md)\n- Change proposals and archived delivery history: [openspec](openspec)\n- Release history: [CHANGELOG.md](CHANGELOG.md)\n\n## Roadmap\n\n- Phase 12: Future integration foundation (boundaries, safety rules, and disabled-by-default configuration placeholders)\n- Phase 16+: Contact/provider integrations, queueing, observability, PostgreSQL profile\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for branch naming, PR expectations, and quality checks.\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for responsible disclosure and secret-handling expectations.\n\n## License\n\nThis project is licensed under the MIT License. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarlos-aisa%2Foutreachflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcarlos-aisa%2Foutreachflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarlos-aisa%2Foutreachflow/lists"}