Streakly is a modern web application built with ASP.NET Core MVC that helps users build better habits and achieve their goals through consistent tracking, meaningful insights, and AI-powered analytics.
- Create and manage daily, weekday, weekend, or custom scheduled habits
- Track habit completion with an intuitive interface
- Visualize streaks and progress with interactive calendars
- Customizable habit icons and colors
- Progress heatmaps and statistics
- Set measurable goals with target values and deadlines
- Track progress with detailed logging
- Multiple goal categories (Personal, Health, Career, etc.)
- Progress visualization and analytics
- Goal completion tracking and milestones
- Overview of daily habits and active goals
- Completion rates and streak tracking
- Weekly and monthly progress views
- Visual progress indicators and statistics
- AI-Powered Insights: ML.NET-powered weekly insights analyzing habit patterns, goal progress, and mood correlations
- Personalized recommendations and encouragement messages
- Daily reflection entries with mood tracking
- Tag-based organization
- Search and filter capabilities
- Mood analysis and trends
- Clean, modern Bootstrap UI
- Responsive design for mobile and desktop
- Customizable user preferences
-
Backend
- ASP.NET Core MVC (.NET 10)
- Entity Framework Core
- ASP.NET Core Identity (Custom MVC Authentication)
- ML.NET (for AI-powered insights)
- C# 13.0
-
Frontend
- Bootstrap 5
- JavaScript/jQuery
- SVG Icons
- Custom CSS
-
Database
- SQL Server
- Entity Framework Core Migrations
The application uses a custom MVC-based authentication system built on ASP.NET Core Identity:
- Custom AuthController replaces default Identity Razor Pages
- Routes:
/auth/login,/auth/register,/auth/logout,/auth/forgot-password - Features: password reset, account lockout, remember me, secure cookies
- Email confirmation required for new registrations
- SMTP email service with MailKit (configurable via environment variables)
- .NET 10 SDK (for local non-Docker development)
- Docker Desktop (for containerized development)
- SQL Server (Local/Express or Dockerized via
docker-compose) - optional, app can run with in-memory database - Visual Studio 2022 or later (optional but recommended)
The simplest way to try the app - runs with an in-memory database (data resets on restart):
docker run -p 8080:8080 bykeny/habit-goal-trackerThen open http://localhost:8080 in your browser.
For persistent data storage, use docker-compose which runs the app with a SQL Server database.
git clone https://github.com/bykeny/Streakly.git
cd StreaklyIn the project root (Streakly), create a file named .env:
MSSQL_SA_PASSWORD=YourStrong!Passw0rd123
# Email settings (optional - if not set, emails are logged to console)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-gmail-app-password
SMTP_FROM_EMAIL=your-email@gmail.com
SMTP_FROM_NAME=Streakly
SMTP_USE_SSL=true
⚠️ Important:
- Use a strong password and do not commit the
.envfile to source control.- For Gmail, you need an App Password (requires 2FA enabled).
From the project root:
docker compose up --buildThis will:
- Build the
bykeny/habit-goal-trackerimage using theDockerfile. - Start the
dbcontainer (SQL Server 2022) with a healthcheck. - Wait for SQL Server to be healthy, then start the
webcontainer (ASP.NET Core app). - Configure the app to connect to SQL Server via the
DATABASE_URLenvironment variable.
- Open your browser and go to:
http://localhost:5032 - Register a new account to get started.
Press Ctrl+C in the terminal that is running docker compose up, or run:
docker compose downYou can also run the app directly with the .NET SDK and your own SQL Server instance.
- Clone the repository (same as above).
- Configure the connection string:
-
Open
appsettings.json. -
Update
ConnectionStrings:HabitGoalConnectionto point to your SQL Server. -
Alternatively, use user-secrets:
dotnet user-secrets set "ConnectionStrings:HabitGoalConnection" "Server=(localdb)\\MSSQLLocalDB;Database=HabitGoalDB;Trusted_Connection=True;"
- Apply database migrations (optional, if not applied yet):
dotnet ef database update- Run the application:
dotnet run- Access the application:
- Open your browser at
https://localhost:5032or the URL printed in the console.
The application supports various configuration options through appsettings.json:
- Database connection
- Authentication settings
- Email service configuration
- Logging preferences
This repository includes a GitHub Actions workflow (.github/workflows/ci-docker.yml) that builds, tests, and containerizes the app, then pushes images to Docker Hub.
On pushes to main or containers branches:
- Build & test (
build_and_testjob)
- Checks out the repository.
- Sets up .NET 10 SDK.
- Runs
dotnet restore,dotnet build, anddotnet testin Release configuration.
- Docker build & push (
docker_build_and_pushjob)
- Runs only if the build & tests succeed.
- Logs in to Docker Hub using repository secrets:
DOCKERHUB_USERNAMEDOCKERHUB_PASSWORD(access token with read/write scope).
- Builds the Docker image using the root
Dockerfile. - Pushes the image to Docker Hub (
bykeny/habit-goal-tracker) with tags:latest${{ github.sha }}(commit SHA)v0.1.${{ github.run_number }}(simple semantic-style build tag)
This makes it easy to track exactly which build is running from the tag.
Once the CI pipeline has pushed an image, you can pull and run it directly from Docker Hub.
For quick testing without any database setup:
docker run -p 8080:8080 bykeny/habit-goal-tracker
⚠️ Note: Data is stored in-memory and will be lost when the container stops.
Connect to an existing SQL Server instance using the DATABASE_URL environment variable:
docker run -p 8080:8080 \
-e "DATABASE_URL=Server=your-server,1433;Database=HabitGoalDB;User Id=sa;Password=YourPassword;TrustServerCertificate=True;Encrypt=False" \
bykeny/habit-goal-trackerUse docker-compose.yml to run both the app and SQL Server together:
# Set the SQL Server password
export MSSQL_SA_PASSWORD="YourStrong!Passw0rd123" # Linux/Mac
# or
$env:MSSQL_SA_PASSWORD = "YourStrong!Passw0rd123" # Windows PowerShell
# Start everything
docker compose upThen open http://localhost:5032 in your browser.
# Latest version
docker pull bykeny/habit-goal-tracker:latest
# Specific version
docker pull bykeny/habit-goal-tracker:v0.1.10For production deployment, this application can be deployed to Azure Container Apps using Terraform infrastructure-as-code. This provides a fully managed, serverless container hosting platform with built-in monitoring and scalability.
The Terraform configuration in the terraform/ directory creates the following Azure resources:
┌─────────────────────────────────────────────────────────┐
│ Azure Resource Group │
│ (rg-streakly) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Log Analytics Workspace (law-streakly) │ │
│ │ • Logs and metrics collection │ │
│ │ • 30-day retention │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Application Insights (appi-streakly) │ │
│ │ • APM and monitoring │ │
│ │ • Performance tracking │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Container App Environment (env-streakly) │ │
│ │ • Managed Kubernetes-like environment │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Container App (streakly-app) │ │
│ │ • Docker image: bykeny/habit-goal-tracker:latest │ │
│ │ • CPU: 0.25 cores, Memory: 0.5 Gi │ │
│ │ • Scale: 0-1 replicas (scale-to-zero) │ │
│ │ • External ingress on port 8080 │ │
│ │ • SMTP/Email configuration (secrets) │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Resources Created:
- Resource Group - Container for all Azure resources
- Log Analytics Workspace - Centralized logging (30-day retention)
- Application Insights - Application performance monitoring and telemetry
- Container App Environment - Managed environment for running containers
- Container App - The Streakly application with external HTTPS endpoint
Before deploying to Azure, ensure you have:
- Azure Subscription - Active Azure account (Free trial available)
- Terraform CLI - Version >= 1.5.0 (Download)
- Azure CLI - For authentication (Install guide)
- SMTP Credentials - Gmail account with app password for email notifications
- Azure Service Principal (for GitHub Actions) - See Azure docs
# Login to Azure
az login
# Set your subscription (if you have multiple)
az account set --subscription "YOUR_SUBSCRIPTION_ID"
# Verify authentication
az account showCreate a terraform/terraform.tfvars file with your configuration:
# Azure Configuration
location = "polandcentral" # or your preferred region
resource_group_name = "rg-streakly"
containerapp_name = "streakly-app"
environment_name = "env-streakly"
# Docker Image
image_name = "bykeny/habit-goal-tracker:latest"
# SMTP Configuration (Required for email notifications)
smtp_host = "smtp.gmail.com"
smtp_port = "587"
smtp_username = "your-email@gmail.com"
smtp_password = "your-gmail-app-password" # Use Gmail App Password
smtp_from_email = "your-email@gmail.com"
smtp_from_name = "Streakly"
smtp_use_ssl = "true"
# Application Insights
appinsights_name = "appi-streakly"
⚠️ Security Warning:
- Never commit
terraform.tfvarsto source control - it contains sensitive credentials- Add
terraform.tfvarsto.gitignore- For production, use Azure Key Vault or GitHub Secrets instead of plain text passwords
- Use Gmail App Passwords (requires 2FA enabled)
cd terraform
terraform initThis downloads the Azure provider and prepares the working directory.
terraform planReview the proposed changes. Terraform will show you what resources will be created.
terraform applyType yes when prompted to create the resources. This process takes 3-5 minutes.
After successful deployment:
terraform output container_app_urlOpen the URL in your browser to access your deployed application.
terraform destroyType yes to delete all Azure resources and stop incurring costs.
The repository includes three automated Terraform workflows:
Trigger: Pull requests to main branch
Purpose: Validates Terraform configuration and shows infrastructure changes before merging
Actions:
- Checks out code
- Authenticates with Azure using OIDC
- Sets up Terraform
- Runs
terraform fmt -check(validates formatting) - Runs
terraform init - Runs
terraform validate(checks syntax) - Runs
terraform plan(shows proposed changes) - Posts plan results as PR comment with status table
- Uploads plan artifact
Required Secrets:
AZURE_CLIENT_ID- Service Principal Client IDAZURE_TENANT_ID- Azure Tenant IDAZURE_SUBSCRIPTION_ID- Azure Subscription ID
Features:
- ✅ Concurrency control per PR
- ✅ Automated PR comments with plan results
- ✅ Format checking
Trigger: Push to main branch
Purpose: Automatically applies infrastructure changes to Azure
Actions:
- Authenticates with Azure using OIDC
- Runs
terraform init - Runs
terraform apply -auto-approve(creates/updates infrastructure)
Required Secrets:
AZURE_CLIENT_ID- Service Principal Client IDAZURE_TENANT_ID- Azure Tenant IDAZURE_SUBSCRIPTION_ID- Azure Subscription IDSMTP_USERNAME- SMTP username (passed asTF_VAR_smtp_username)SMTP_PASSWORD- SMTP password (passed asTF_VAR_smtp_password)
Features:
- ✅ Concurrency control (prevents simultaneous applies)
Note: Variables prefixed with
TF_VAR_are automatically passed to Terraform as input variables.
Trigger: Push to main branch
Purpose: Updates the Azure Container App with the latest Docker image
Actions:
- Authenticates with Azure using OIDC
- Updates container app image to latest version
- Triggers new revision deployment
Required Secrets:
AZURE_CLIENT_ID- Service Principal Client IDAZURE_TENANT_ID- Azure Tenant IDAZURE_SUBSCRIPTION_ID- Azure Subscription ID
Features:
- ✅ OIDC authentication (no stored credentials)
- ✅ Concurrency control
To enable automated deployments with OIDC:
- Create Azure Service Principal:
az ad sp create-for-rbac --name "github-actions-streakly" \
--role contributor \
--scopes /subscriptions/YOUR_SUBSCRIPTION_IDSave the appId (Client ID) and tenant from the output.
- Configure Federated Credentials (for OIDC):
# Replace with your values
APP_ID="your-app-id-from-step-1"
REPO_OWNER="bykeny"
REPO_NAME="Streakly"
# Create federated credential
az ad app federated-credential create \
--id $APP_ID \
--parameters '{
"name": "github-actions",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:'"$REPO_OWNER"'/'"$REPO_NAME"':ref:refs/heads/main",
"audiences": ["api://AzureADTokenExchange"]
}'- Add Repository Secrets (Settings → Secrets and variables → Actions):
| Secret Name | Value | Description |
|---|---|---|
AZURE_CLIENT_ID |
From Service Principal (appId) | Client ID for OIDC |
AZURE_TENANT_ID |
From Service Principal (tenant) | Tenant ID for OIDC |
AZURE_SUBSCRIPTION_ID |
Your Azure subscription ID | Subscription ID |
SMTP_USERNAME |
Your email address | SMTP username |
SMTP_PASSWORD |
Gmail app password | SMTP password |
🔒 Security Note: This setup uses OIDC (OpenID Connect) federated credentials instead of storing long-lived secrets. Authentication happens via short-lived tokens - no passwords or keys are stored in GitHub.
After deployment, Terraform provides the following outputs:
| Output | Description | Usage |
|---|---|---|
container_app_url |
Public HTTPS URL of your application | Access your deployed app |
app_insights_url |
Application Insights App ID | For monitoring and diagnostics |
Access outputs:
# All outputs
terraform output
# Specific output
terraform output container_app_url- Access: Azure Portal → Resource Group → Application Insights (appi-streakly)
- Features:
- Real-time performance monitoring
- Request/response tracking
- Failure and exception tracking
- Custom metrics and events
- User analytics
- Access: Azure Portal → Resource Group → Log Analytics Workspace (law-streakly)
- Query Logs: Use Kusto Query Language (KQL) to analyze container logs
- Retention: 30 days (configurable in
terraform/loganalytics.tf)
Example Log Query:
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == "streakly-app"
| order by TimeGenerated desc
| take 100Azure Container Apps pricing is based on:
- vCPU: $0.000024/vCPU-second (0.25 vCPU configured)
- Memory: $0.000003/GiB-second (0.5 GiB configured)
- Scale-to-zero: No charges when app has 0 replicas (no traffic)
- Log Analytics: Free tier: 5GB/month, then $2.99/GB
- Application Insights: Free tier: 5GB/month, then $2.99/GB
Estimated Monthly Cost: ~$5-15 for low to moderate traffic
💡 Tip: The app is configured with
min_replicas = 0to enable scale-to-zero, reducing costs during idle periods.
For Production Use, consider:
- Adding Azure SQL Database to
terraform/configuration - Updating connection string in Container App environment variables
- Implementing database migrations in the deployment pipeline
The current configuration uses local state files (terraform.tfstate). For team collaboration or production use:
Recommended: Configure Azure Blob Storage backend:
# Add to terraform/provider.tf
terraform {
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "tfstatestreakly"
container_name = "tfstate"
key = "streakly.terraform.tfstate"
}
}With min_replicas = 0, the first request after idle period may experience a cold start (3-5 seconds). To avoid this:
- Set
min_replicas = 1interraform/containerapp.tf - Accept slightly higher costs for always-on availability
| Feature | Docker Compose (Local) | Azure Container Apps (Terraform) |
|---|---|---|
| Environment | Local development | Cloud production |
| Database | SQL Server container | In-memory (add Azure SQL for persistence) |
| Scalability | Single instance | Auto-scaling (0-1 replicas configured) |
| High Availability | ❌ No | ✅ Yes (Azure SLA 99.95%) |
| Monitoring | Console logs only | Application Insights + Log Analytics |
| Email Notifications | Optional | Configured via SMTP secrets |
| HTTPS/SSL | ❌ HTTP only | ✅ Automatic HTTPS with Azure |
| Cost | Free (local resources) | ~$5-15/month |
| Deployment Time | Instant | 3-5 minutes |
| Best For | Development & Testing | Production & Staging |
-
Terraform Error: "Subscription not found"
# Verify subscription az account show az account set --subscription "YOUR_SUBSCRIPTION_ID"
-
Container App Not Starting
- Check logs: Azure Portal → Container App → Log stream
- Verify SMTP credentials are correct
- Ensure Docker image exists on Docker Hub
-
SMTP Authentication Failed
- Use Gmail App Password, not regular password
- Enable 2FA on your Google account first
- Verify credentials in
terraform.tfvars
-
Terraform State Lock
# If state is locked (force unlock - use with caution) terraform force-unlock LOCK_ID -
High Costs
- Verify scale-to-zero is working: Check metrics in Azure Portal
- Review Log Analytics data ingestion
- Consider setting retention to 7 days for dev environments
- AI-powered insights with ML.NET
- Email notifications (registration confirmation, password reset)
- Mobile app integration
- Social features and habit sharing
- Advanced analytics and reporting
- API endpoints for third-party integration
- Data export/import functionality
- Gamification and achievement system
- Push notifications and reminders
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Kanan Ramazanov - kenanramaznov@gmail.com
Built with ❤️ using ASP.NET Core and ML.NET