diff --git a/.gitignore b/.gitignore
index 8dac68273..2fc3378cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,8 @@ node_modules
*.sketch
crowdin.yml
kotlin-js-store
+
+# Python / Django
+db.sqlite3
+__pycache__/
+*.pyc
diff --git a/habits_tracker/habits/__init__.py b/habits_tracker/habits/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/habits_tracker/habits/admin.py b/habits_tracker/habits/admin.py
new file mode 100644
index 000000000..8c38f3f3d
--- /dev/null
+++ b/habits_tracker/habits/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/habits_tracker/habits/apps.py b/habits_tracker/habits/apps.py
new file mode 100644
index 000000000..8a1905717
--- /dev/null
+++ b/habits_tracker/habits/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class HabitsConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "habits"
diff --git a/habits_tracker/habits/management/commands/send_reminders.py b/habits_tracker/habits/management/commands/send_reminders.py
new file mode 100644
index 000000000..54f975983
--- /dev/null
+++ b/habits_tracker/habits/management/commands/send_reminders.py
@@ -0,0 +1,25 @@
+from django.core.management.base import BaseCommand
+from django.core.mail import send_mail
+from django.utils import timezone
+from habits.models import Habit
+
+class Command(BaseCommand):
+ help = 'Sends habit reminders to users'
+
+ def handle(self, *args, **options):
+ now = timezone.now()
+ habits_to_remind = Habit.objects.filter(
+ send_reminder=True,
+ reminder_time__hour=now.hour,
+ reminder_time__minute=now.minute
+ )
+
+ for habit in habits_to_remind:
+ send_mail(
+ f'Reminder: {habit.name}',
+ f'This is a reminder to complete your habit: {habit.name}',
+ 'from@example.com',
+ [habit.user.email],
+ fail_silently=False,
+ )
+ self.stdout.write(self.style.SUCCESS(f'Successfully sent reminder for "{habit.name}" to {habit.user.email}'))
diff --git a/habits_tracker/habits/migrations/0001_initial.py b/habits_tracker/habits/migrations/0001_initial.py
new file mode 100644
index 000000000..37c622139
--- /dev/null
+++ b/habits_tracker/habits/migrations/0001_initial.py
@@ -0,0 +1,63 @@
+# Generated by Django 5.2.6 on 2025-09-13 17:33
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Habit",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=255)),
+ ("description", models.TextField(blank=True)),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ (
+ "user",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ migrations.CreateModel(
+ name="Repetition",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("date", models.DateField()),
+ ("value", models.IntegerField(default=1)),
+ (
+ "habit",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to="habits.habit"
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/habits_tracker/habits/migrations/0002_habit_reminder_time_habit_send_reminder.py b/habits_tracker/habits/migrations/0002_habit_reminder_time_habit_send_reminder.py
new file mode 100644
index 000000000..f6c621501
--- /dev/null
+++ b/habits_tracker/habits/migrations/0002_habit_reminder_time_habit_send_reminder.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.2.6 on 2025-09-13 17:39
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("habits", "0001_initial"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="habit",
+ name="reminder_time",
+ field=models.TimeField(blank=True, null=True),
+ ),
+ migrations.AddField(
+ model_name="habit",
+ name="send_reminder",
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/habits_tracker/habits/migrations/__init__.py b/habits_tracker/habits/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/habits_tracker/habits/models.py b/habits_tracker/habits/models.py
new file mode 100644
index 000000000..00efe7ac7
--- /dev/null
+++ b/habits_tracker/habits/models.py
@@ -0,0 +1,21 @@
+from django.db import models
+from django.contrib.auth.models import User
+
+class Habit(models.Model):
+ user = models.ForeignKey(User, on_delete=models.CASCADE)
+ name = models.CharField(max_length=255)
+ description = models.TextField(blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+ send_reminder = models.BooleanField(default=False)
+ reminder_time = models.TimeField(null=True, blank=True)
+
+ def __str__(self):
+ return self.name
+
+class Repetition(models.Model):
+ habit = models.ForeignKey(Habit, on_delete=models.CASCADE)
+ date = models.DateField()
+ value = models.IntegerField(default=1)
+
+ def __str__(self):
+ return f"{self.habit.name} - {self.date}"
diff --git a/habits_tracker/habits/templates/habits/habit_confirm_delete.html b/habits_tracker/habits/templates/habits/habit_confirm_delete.html
new file mode 100644
index 000000000..22b2ef2f1
--- /dev/null
+++ b/habits_tracker/habits/templates/habits/habit_confirm_delete.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+
+{% block content %}
+
Are you sure you want to delete "{{ object.name }}"?
+
+{% endblock %}
diff --git a/habits_tracker/habits/templates/habits/habit_detail.html b/habits_tracker/habits/templates/habits/habit_detail.html
new file mode 100644
index 000000000..ecf4f3a62
--- /dev/null
+++ b/habits_tracker/habits/templates/habits/habit_detail.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% block content %}
+ {{ object.name }}
+ {{ object.description }}
+
+ Calendar
+
+
+
+ Mon |
+ Tue |
+ Wed |
+ Thu |
+ Fri |
+ Sat |
+ Sun |
+
+
+
+ {% for week in month_days %}
+
+ {% for day in week %}
+
+ {% if day.month == current_month %}
+ {{ day.day }}
+ {% endif %}
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+ Back to Habits
+{% endblock %}
diff --git a/habits_tracker/habits/templates/habits/habit_form.html b/habits_tracker/habits/templates/habits/habit_form.html
new file mode 100644
index 000000000..86eb83d73
--- /dev/null
+++ b/habits_tracker/habits/templates/habits/habit_form.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+
+{% block content %}
+ {% if object %}Edit Habit{% else %}Create Habit{% endif %}
+
+{% endblock %}
diff --git a/habits_tracker/habits/templates/habits/habit_list.html b/habits_tracker/habits/templates/habits/habit_list.html
new file mode 100644
index 000000000..2ff35f88c
--- /dev/null
+++ b/habits_tracker/habits/templates/habits/habit_list.html
@@ -0,0 +1,45 @@
+{% extends "base.html" %}
+{% load habit_tags %}
+
+{% block content %}
+ My Habits
+ Create New Habit
+ Export to CSV
+
+
+
+ Habit |
+ {% for day in days %}
+ {{ day|date:"D" }} |
+ {% endfor %}
+
+
+
+ {% for habit, reps in habits_with_reps %}
+
+
+ {{ habit.name }}
+ Edit
+ Delete
+ |
+ {% for day in days %}
+
+
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+{% endblock %}
diff --git a/habits_tracker/habits/templatetags/habit_tags.py b/habits_tracker/habits/templatetags/habit_tags.py
new file mode 100644
index 000000000..4b04b5c64
--- /dev/null
+++ b/habits_tracker/habits/templatetags/habit_tags.py
@@ -0,0 +1,7 @@
+from django import template
+
+register = template.Library()
+
+@register.filter
+def get_item(dictionary, key):
+ return dictionary.get(key)
diff --git a/habits_tracker/habits/tests.py b/habits_tracker/habits/tests.py
new file mode 100644
index 000000000..014d555cd
--- /dev/null
+++ b/habits_tracker/habits/tests.py
@@ -0,0 +1,43 @@
+from django.test import TestCase
+from django.contrib.auth.models import User
+from .models import Habit, Repetition
+from django.urls import reverse
+
+class HabitTestCase(TestCase):
+ def setUp(self):
+ self.user = User.objects.create_user(username='testuser', password='password')
+ self.client.login(username='testuser', password='password')
+ self.habit = Habit.objects.create(user=self.user, name='Test Habit')
+ self.repetition = Repetition.objects.create(habit=self.habit, date='2025-01-01')
+
+ def test_habit_list_view(self):
+ response = self.client.get(reverse('habits:habit_list'))
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'Test Habit')
+
+ def test_habit_detail_view(self):
+ response = self.client.get(reverse('habits:habit_detail', args=[self.habit.pk]))
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'Test Habit')
+
+ def test_habit_create_view(self):
+ response = self.client.post(reverse('habits:habit_create'), {'name': 'New Habit'})
+ self.assertEqual(response.status_code, 302)
+ self.assertTrue(Habit.objects.filter(name='New Habit').exists())
+
+ def test_habit_update_view(self):
+ response = self.client.post(reverse('habits:habit_update', args=[self.habit.pk]), {'name': 'Updated Habit'})
+ self.assertEqual(response.status_code, 302)
+ self.habit.refresh_from_db()
+ self.assertEqual(self.habit.name, 'Updated Habit')
+
+ def test_habit_delete_view(self):
+ response = self.client.post(reverse('habits:habit_delete', args=[self.habit.pk]))
+ self.assertEqual(response.status_code, 302)
+ self.assertFalse(Habit.objects.filter(pk=self.habit.pk).exists())
+
+ def test_export_csv_view(self):
+ response = self.client.get(reverse('habits:export_csv'))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response['Content-Type'], 'text/csv')
+ self.assertIn('Test Habit,2025-01-01,1', response.content.decode())
diff --git a/habits_tracker/habits/urls.py b/habits_tracker/habits/urls.py
new file mode 100644
index 000000000..3c62a7a79
--- /dev/null
+++ b/habits_tracker/habits/urls.py
@@ -0,0 +1,14 @@
+from django.urls import path
+from . import views
+
+app_name = 'habits'
+
+urlpatterns = [
+ path('', views.HabitListView.as_view(), name='habit_list'),
+ path('/', views.HabitDetailView.as_view(), name='habit_detail'),
+ path('create/', views.HabitCreateView.as_view(), name='habit_create'),
+ path('/update/', views.HabitUpdateView.as_view(), name='habit_update'),
+ path('/delete/', views.HabitDeleteView.as_view(), name='habit_delete'),
+ path('export/csv/', views.ExportCSVView.as_view(), name='export_csv'),
+ path('log/', views.LogRepetitionView.as_view(), name='log_repetition'),
+]
diff --git a/habits_tracker/habits/views.py b/habits_tracker/habits/views.py
new file mode 100644
index 000000000..a4e4d54b0
--- /dev/null
+++ b/habits_tracker/habits/views.py
@@ -0,0 +1,102 @@
+from django.shortcuts import render
+from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, View
+from django.contrib.auth.mixins import LoginRequiredMixin
+from .models import Habit
+from django.urls import reverse_lazy
+import csv
+from django.http import HttpResponse
+
+import datetime
+from django.utils import timezone
+
+class HabitListView(LoginRequiredMixin, ListView):
+ model = Habit
+ template_name = 'habits/habit_list.html'
+
+ def get_queryset(self):
+ return Habit.objects.filter(user=self.request.user)
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ today = timezone.now().date()
+ days = [today - datetime.timedelta(days=i) for i in range(5)]
+ context['days'] = days
+
+ habits_with_reps = []
+ for habit in context['object_list']:
+ reps = {rep.date: rep for rep in habit.repetition_set.filter(date__in=days)}
+ habits_with_reps.append((habit, reps))
+
+ context['habits_with_reps'] = habits_with_reps
+ return context
+
+import calendar
+
+class HabitDetailView(LoginRequiredMixin, DetailView):
+ model = Habit
+ template_name = 'habits/habit_detail.html'
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ today = timezone.now().date()
+ cal = calendar.Calendar()
+ month_days = cal.monthdatescalendar(today.year, today.month)
+
+ reps = {rep.date for rep in self.object.repetition_set.filter(date__year=today.year, date__month=today.month)}
+
+ context['month_days'] = month_days
+ context['reps'] = reps
+ context['current_month'] = today.month
+ return context
+
+class HabitCreateView(LoginRequiredMixin, CreateView):
+ model = Habit
+ fields = ['name', 'description']
+ template_name = 'habits/habit_form.html'
+ success_url = reverse_lazy('habits:habit_list')
+
+ def form_valid(self, form):
+ form.instance.user = self.request.user
+ return super().form_valid(form)
+
+class HabitUpdateView(LoginRequiredMixin, UpdateView):
+ model = Habit
+ fields = ['name', 'description']
+ template_name = 'habits/habit_form.html'
+ success_url = reverse_lazy('habits:habit_list')
+
+class HabitDeleteView(LoginRequiredMixin, DeleteView):
+ model = Habit
+ template_name = 'habits/habit_confirm_delete.html'
+ success_url = reverse_lazy('habits:habit_list')
+
+from django.shortcuts import get_object_or_404
+from .models import Repetition
+
+class ExportCSVView(LoginRequiredMixin, View):
+ def get(self, request, *args, **kwargs):
+ response = HttpResponse(content_type='text/csv')
+ response['Content-Disposition'] = 'attachment; filename="habits.csv"'
+
+ writer = csv.writer(response)
+ writer.writerow(['Habit', 'Date', 'Value'])
+
+ habits = Habit.objects.filter(user=request.user)
+ for habit in habits:
+ for repetition in habit.repetition_set.all():
+ writer.writerow([habit.name, repetition.date, repetition.value])
+
+ return response
+
+class LogRepetitionView(LoginRequiredMixin, View):
+ def post(self, request, *args, **kwargs):
+ habit_id = request.POST.get('habit_id')
+ date_str = request.POST.get('date')
+ date = datetime.datetime.strptime(date_str, '%Y-%m-%d').date()
+ habit = get_object_or_404(Habit, pk=habit_id, user=request.user)
+
+ rep, created = Repetition.objects.get_or_create(habit=habit, date=date)
+ if not created:
+ rep.delete()
+
+ return HttpResponse(status=204)
diff --git a/habits_tracker/habits_tracker/__init__.py b/habits_tracker/habits_tracker/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/habits_tracker/habits_tracker/asgi.py b/habits_tracker/habits_tracker/asgi.py
new file mode 100644
index 000000000..7097ebeca
--- /dev/null
+++ b/habits_tracker/habits_tracker/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for habits_tracker project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "habits_tracker.settings")
+
+application = get_asgi_application()
diff --git a/habits_tracker/habits_tracker/settings.py b/habits_tracker/habits_tracker/settings.py
new file mode 100644
index 000000000..e369c32e3
--- /dev/null
+++ b/habits_tracker/habits_tracker/settings.py
@@ -0,0 +1,140 @@
+"""
+Django settings for habits_tracker project.
+
+Generated by 'django-admin startproject' using Django 5.2.6.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/5.2/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = "django-insecure-ck4e+hvwh86i8b*-v0d0uwn$le-o=qvu)f(ss(%6arverkar8f"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+ "habits",
+ # The following apps are required by django-allauth
+ 'allauth',
+ 'allauth.account',
+ 'allauth.socialaccount',
+]
+
+AUTHENTICATION_BACKENDS = [
+ # Needed to login by username in Django admin, regardless of `allauth`
+ 'django.contrib.auth.backends.ModelBackend',
+
+ # `allauth` specific authentication methods, such as login by e-mail
+ 'allauth.account.auth_backends.AuthenticationBackend',
+]
+
+MIDDLEWARE = [
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "allauth.account.middleware.AccountMiddleware",
+]
+
+ROOT_URLCONF = "habits_tracker.urls"
+
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [BASE_DIR / 'templates'],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = "habits_tracker.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": BASE_DIR / "db.sqlite3",
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/5.2/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/5.2/howto/static-files/
+
+STATIC_URL = "static/"
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+
+SITE_ID = 1
+
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
diff --git a/habits_tracker/habits_tracker/urls.py b/habits_tracker/habits_tracker/urls.py
new file mode 100644
index 000000000..07ec761a8
--- /dev/null
+++ b/habits_tracker/habits_tracker/urls.py
@@ -0,0 +1,25 @@
+"""
+URL configuration for habits_tracker project.
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/5.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+
+from django.contrib import admin
+from django.urls import path, include
+
+urlpatterns = [
+ path("admin/", admin.site.urls),
+ path("accounts/", include("allauth.urls")),
+ path("habits/", include("habits.urls", namespace="habits")),
+]
diff --git a/habits_tracker/habits_tracker/wsgi.py b/habits_tracker/habits_tracker/wsgi.py
new file mode 100644
index 000000000..b1a5c65c7
--- /dev/null
+++ b/habits_tracker/habits_tracker/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for habits_tracker project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "habits_tracker.settings")
+
+application = get_wsgi_application()
diff --git a/habits_tracker/manage.py b/habits_tracker/manage.py
new file mode 100755
index 000000000..f71e1130c
--- /dev/null
+++ b/habits_tracker/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "habits_tracker.settings")
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/habits_tracker/templates/account/login.html b/habits_tracker/templates/account/login.html
new file mode 100644
index 000000000..b7050086b
--- /dev/null
+++ b/habits_tracker/templates/account/login.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+
+{% block content %}
+Log In
+
+{% endblock %}
diff --git a/habits_tracker/templates/account/signup.html b/habits_tracker/templates/account/signup.html
new file mode 100644
index 000000000..afcc7755e
--- /dev/null
+++ b/habits_tracker/templates/account/signup.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+
+{% block content %}
+Sign Up
+
+{% endblock %}
diff --git a/habits_tracker/templates/base.html b/habits_tracker/templates/base.html
new file mode 100644
index 000000000..6eb102623
--- /dev/null
+++ b/habits_tracker/templates/base.html
@@ -0,0 +1,53 @@
+
+
+
+ Habits Tracker
+
+
+
+
+
+ {% block content %}
+ {% endblock %}
+
+
+
+