# Tour Voting App Tour Voting App is a full-stack web application for planning tours, proposing ideas, and voting on those ideas. It consists of: * **Backend API** built with FastAPI * **Data persistence** using per-tour JSON files in a configurable directory, with concurrency safety via file locks * **Frontend**: Single-page HTML/JavaScript application that consumes the API * **Helper scripts** for local development or Supervisor-based deployment ## Table of Contents 1. Features 2. Tech Stack 3. Prerequisites 4. Installation 5. Configuration 6. Development 7. Running in Production 8. Frontend Usage 9. API Reference * Models * Endpoints 10. Directory Structure 11. Contributing 12. License ## Features * Create and manage tours with metadata (name, start/end dates, description) * Add multiple ideas per tour, each with its own name, description, and optional time window * Vote on ideas by recording unique voter names * No external database: JSON file–based persistence * Concurrency-safe via file locking * Minimal static HTML/JavaScript frontend for user interaction * Helper scripts for local development or Supervisor deployment ## Tech Stack * **Backend**: Python 3.10+, FastAPI, Uvicorn, Pydantic, filelock * **Frontend**: HTML, CSS, JavaScript (Fetch API) * **Process Control (optional)**: Supervisor * **Data storage**: JSON files, one per tour ## Prerequisites * Python 3.10 or higher * pip (Python package installer) * (Optional) Supervisor for process management ## Installation 1. **Clone the repository** git clone [https://github.com/your-organization/tour-voting-app.git](https://github.com/your-organization/tour-voting-app.git) cd tour-voting-app 2. **Create virtual environment and install dependencies** python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt If `requirements.txt` is not provided, install directly: pip install fastapi uvicorn pydantic filelock ## Configuration Configure via environment variables or command-line flags: * **DATA\_DIR**: directory to store tour JSON files (default: `./data`) * **HOST**: address to bind the API (default: `0.0.0.0`) * **PORT**: port for the API (default: `8000`) Example using environment variables: ``` export DATA_DIR=./data export HOST=0.0.0.0 export PORT=8000 ``` Or via flags: ``` python server.py --data-dir ./data --host 0.0.0.0 --port 8000 ``` ## Development 1. Activate your virtual environment. 2. Start the server in reload mode: ``` uvicorn server:app --reload --host 0.0.0.0 --port 8000 ``` 3. Open `index.html` in your browser (or serve it via a local HTTP server to avoid CORS issues). ## Running in Production Use the provided `service.sh` script and Supervisor config: **service.sh** ```bash #!/usr/bin/env bash cd /path/to/tour-voting-app || exit 1 exec uvicorn server:app \ --host 0.0.0.0 \ --port 3002 \ --loop uvloop \ --workers 2 \ --access-log \ --log-level info ``` **tour.ini** (Supervisor) ```ini [program:tour_voting_app] command=/path/to/service.sh directory=/path/to/tour-voting-app autostart=true autorestart=true stderr_logfile=/var/log/tour_voting_app.err.log stdout_logfile=/var/log/tour_voting_app.out.log ``` ## Frontend Usage The frontend is a single `index.html` file that interacts with the API. By default, `API_URL` is set to `http://localhost:8000/tour/v1`. To point it at a remote server, edit the `API_URL` constant near the top of `index.html`. ## API Reference Base path: `/tour/v1` ### Models **Tour** ```json { "id": "string", "name": "string", "description": "string", "startDate": "ISO-8601 timestamp", "endDate": "ISO-8601 timestamp", "createdAt": "ISO-8601 timestamp", "ideas": [ Idea ] } ``` **Idea** ```json { "id": "string", "name": "string", "description": "string", "startTime": "ISO-8601 timestamp | null", "endTime": "ISO-8601 timestamp | null", "voters": [ "string" ] } ``` ### Endpoints #### 1. List Tours * **Method**: GET * **URL**: `/tours` * **Response**: `200 OK` ```json [ { Tour }, ... ] ``` #### 2. Create a Tour * **Method**: POST * **URL**: `/tours` * **Request Body**: ```json { "name": "Europe Explorer", "description": "A tour across Europe", "startDate": "2025-07-01T00:00:00Z", "endDate": "2025-07-15T00:00:00Z" } ``` * **Response**: `201 Created` ```json { Tour } ``` #### 3. Get Tour Details * **Method**: GET * **URL**: `/tours/{tour_id}` * **Path Parameters**: * `tour_id` (string): ID of the tour * **Response**: `200 OK` ```json { Tour } ``` * **Error**: `404 Not Found` if tour does not exist. #### 4. Add an Idea to a Tour * **Method**: POST * **URL**: `/tours/{tour_id}/ideas` * **Path Parameters**: * `tour_id` (string): ID of the tour * **Request Body**: ```json { "name": "Visit the Louvre", "description": "Guided museum tour", "startTime": "2025-07-03T10:00:00Z", "endTime": "2025-07-03T14:00:00Z" } ``` * **Response**: `201 Created` ```json { Idea } ``` * **Error**: `404 Not Found` if tour does not exist. #### 5. Vote for an Idea * **Method**: POST * **URL**: `/tours/{tour_id}/ideas/{idea_id}/vote` * **Path Parameters**: * `tour_id` (string): ID of the tour * `idea_id` (string): ID of the idea * **Request Body**: ```json { "voterName": "alice@example.com" } ``` * **Response**: `200 OK` ```json { Idea } // Updated idea with new voter ``` * **Errors**: * `404 Not Found` if tour or idea does not exist. * `400 Bad Request` if voter name is missing or already voted. ## Directory Structure ``` tour-voting-app/ ├── server.py # FastAPI application ├── index.html # Static frontend ├── service.sh # Startup helper script ├── tour.ini # Supervisor config ├── data/ # JSON files for tours (runtime) ├── requirements.txt # Python dependencies (optional) └── README.md # Project documentation ``` ## Contributing 1. Fork the repository. 2. Create a feature branch: git checkout -b feature/my-feature 3. Commit your changes: git commit -m "Add my feature" 4. Push to your branch: git push origin feature/my-feature 5. Open a pull request. ## License This project is licensed under the WTFPL License. --- .gitignore # Byte-compiled files **pycache**/ \*.py\[cod] \*\$py.class # Virtual environments .env/ .venv/ env/ venv/ # Distribution build/ dist/ \*.egg-info/ \*.egg # Installer logs pip-log.txt pip-delete-this-directory.txt # Python coverage htmlcov/ .tox/ .coverage .pytest\_cache/ .nox/ # Logs \*.log # IDEs .vscode/ .idea/ # macOS .DS\_Store # Linux \*\~ # Data files and locks data/ \*.json \*.lock