Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Smart Polling API

Backend CI

A Django REST API for authenticated poll creation, conditional questions, validated one-time submissions, and creator-only result aggregation.

This repository currently contains the backend API only. The implementation is intentionally documented without production, scale, frontend, or performance claims.

What is implemented

  • JWT access and refresh tokens.
  • Public poll listing and retrieval.
  • Authenticated poll creation with nested questions and options.
  • Single-choice, multiple-choice, and text questions.
  • One optional conditional rule per question, using stable UUID references inside the create request.
  • Creator-only poll updates, deletion, and result access.
  • Authenticated respondent submissions with strict question and option scoping.
  • Conditional visibility and required-question validation before any answer is written.
  • One database-enforced submission per user and poll.
  • Transactional answer creation and aggregated choice/text results.
  • Automated checks for dependencies, Django configuration, migrations, and tests.

Technical decisions

Validate the complete submission before writing

The submission service resolves questions only from the requested poll and options only from their parent question. It rejects duplicate questions, duplicate options, hidden answers, missing required visible questions, and invalid answer shapes before creating a Submission or Answer.

Use an explicit submission aggregate

A Submission connects one user to one poll. Database constraints enforce one submission per user and one answer per question within that submission. The write path also uses transaction.atomic() and locks the poll row before validation and persistence.

Keep conditional references deterministic

Nested create requests may provide UUIDs for questions and options. A conditional question refers to those IDs, allowing all questions and options to be created first and conditions to be validated afterward in the same transaction. Self-dependencies, cross-poll references, mismatched trigger options, and dependency cycles are rejected.

Protect configuration by default

The application will not start without DJANGO_SECRET_KEY. Debug mode defaults to false, allowed hosts and CORS origins are explicit lists, and the current .gitignore excludes new environment files and local SQLite data. The development key removed from the original code must remain permanently unused.

Data model

User ── creates ──> Poll ── contains ──> Question ── offers ──> Option
  │                   │                      │
  └── submits ──> Submission ── contains ──> Answer

ConditionalLogic:
target question ── depends on ──> parent question + trigger option

API routes

Method Route Access Behavior
POST /api/auth/token/ Public Obtain JWT access and refresh tokens
POST /api/auth/token/refresh/ Public Obtain a new access token
GET /api/polls/ Public List polls with pagination
POST /api/polls/ Authenticated Create a poll with nested questions and options
GET /api/polls/{poll_id}/ Public Retrieve a poll definition
PUT / PATCH /api/polls/{poll_id}/ Creator Replace or partially update title and description
DELETE /api/polls/{poll_id}/ Creator Delete the poll
POST /api/polls/{poll_id}/answers/ Authenticated Submit one validated response
GET /api/polls/{poll_id}/results/ Creator Read aggregated results

Send authenticated requests with Authorization: Bearer <access_token>.

Run locally

The CI workflow tests Python 3.12. Local verification has also passed on Python 3.13.

git clone https://github.com/ahmed-elsayed-programmer/smart-polling.git
cd smart-polling
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r backend/requirements.txt

Generate a local secret, then export it together with the local development settings:

python -c "from secrets import token_urlsafe; print(token_urlsafe(50))"
export DJANGO_SECRET_KEY="paste-the-generated-value-here"
export DJANGO_DEBUG=true
export DJANGO_ALLOWED_HOSTS="localhost,127.0.0.1"
export DJANGO_CORS_ALLOWED_ORIGINS="http://localhost:3000,http://127.0.0.1:3000"

Prepare the database and start the API:

python backend/manage.py migrate
python backend/manage.py createsuperuser
python backend/manage.py runserver

The API is available at http://127.0.0.1:8000/api/.

Example requests

Obtain a token:

curl -X POST http://127.0.0.1:8000/api/auth/token/ \
  -H "Content-Type: application/json" \
  -d '{"username":"creator","password":"your-password"}'

Create a conditional poll. The client-generated IDs make the dependency references stable inside one request:

{
  "title": "Developer survey",
  "description": "A small conditional poll",
  "questions": [
    {
      "id": "11111111-1111-4111-8111-111111111111",
      "text": "Do you use Django?",
      "type": "single-choice",
      "required": true,
      "options": [
        {
          "id": "22222222-2222-4222-8222-222222222222",
          "text": "Yes"
        },
        {
          "id": "33333333-3333-4333-8333-333333333333",
          "text": "No"
        }
      ]
    },
    {
      "id": "44444444-4444-4444-8444-444444444444",
      "text": "What do you build with Django?",
      "type": "text",
      "required": true,
      "conditional_logic": {
        "depends_on_question": "11111111-1111-4111-8111-111111111111",
        "depends_on_option": "22222222-2222-4222-8222-222222222222"
      }
    }
  ]
}

Submit answers:

{
  "answers": [
    {
      "question_id": "11111111-1111-4111-8111-111111111111",
      "selected_options": ["22222222-2222-4222-8222-222222222222"]
    },
    {
      "question_id": "44444444-4444-4444-8444-444444444444",
      "text_value": "REST APIs and business platforms"
    }
  ]
}

Run validation

From the repository root with the virtual environment and DJANGO_SECRET_KEY set:

python -m pip check
cd backend
python manage.py check
python manage.py makemigrations --check --dry-run
python manage.py migrate --noinput
python manage.py test --verbosity 2

Current limitations

  • The repository contains the backend API only; it does not currently include a React or Next.js client.
  • SQLite is configured for local development. No production database or deployment is demonstrated here.
  • Result updates are REST-based; authenticated WebSocket delivery is not implemented.
  • Poll definitions are publicly readable, while results are restricted to the creator.
  • Conditional logic supports one option-triggered dependency per target question.
  • There are no measured usage, reliability, or performance results for this project.

Possible next steps

  • Add a React or Next.js client in a separately testable frontend workspace.
  • Define a production deployment using PostgreSQL and an environment-specific configuration.
  • Add an authenticated real-time result channel with an explicit authorization policy.
  • Add rate limiting, lifecycle controls, and export formats based on validated product requirements.

About

Django REST API for authenticated polls, conditional questions, validated responses, and creator-only results.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages