GET /
Returns a simple welcome message.
Response:
{
"Hello": "World"
}
Fetches a list of all users in the database.
Response:
- Returns a list of users, each with the following attributes:
id
: User IDname
: Name of the useremail
: Email addressphone
: Phone number (if provided)badge_code
: Badge code (if provided)updated_at
: Timestamp of the last update
Example Response:
[
{
"id": "1",
"name": "Alice",
"email": "alice@example.com",
"phone": "+1 (555) 123 4567",
"badge_code": "ABC123",
"updated_at": "2025-01-01 12:34:56"
}
]
Updates a user's information.
Request: Provide the user ID and any fields to update (name
, phone
, email
, badge_code
).
Example Request Body:
{
"name": "Updated Name",
"phone": "+1 (555) 765 4321"
}
Response:
Returns the updated user information.
Records a new scan for a user.
Request: Provide the user ID and activity details.
Example Request Body:
{
"activity_name": "Visited Booth",
"activity_category": "Event"
}
Response:
Returns the scan details.
{
"message": "Scan added successfully",
"user_id": "1",
"activity": "Visited Booth",
"scanned_at": "2025-02-08T12:00:00Z"
}
Fetches the frequency of activity scans, with optional filtering by activity category or frequency range.
Query Parameters:
min_frequency
(default = 0): Minimum scan frequency to includemax_frequency
: Maximum scan frequency to includeactivity_category
: Filter by a specific activity category
Response:
Returns a list of activities and their corresponding scan frequencies.
[
{
"activity_name": "Visited Booth",
"activity_category": "Event",
"frequency": 15
}
]
Clusters scans by activity name and time periods (hourly or per minute).
Query Parameters:
activity_name
(required)time_unit
(default = "hour"; options: "hour" or "minute")start_time
(optional): ISO 8601 format (e.g., "2025-02-01T10:00:00")end_time
(optional): ISO 8601 format
Response:
Returns the activity clusters grouped by time period.
[
{
"activity_name": "Visited Booth",
"time_period": "2025-02-01 12",
"scan_count": 5
}
]
The SQLite database is initialized through the init_db()
function, and it is accessed via the get_db_connection()
utility. Ensure that the database is created and initialized before running the API.
The application can be run using Docker Compose. The provided docker-compose.yml
file defines two services:
- api: The main FastAPI application running on port 3000.
- tests: A container for running the test suite using
pytest
.
-
Build and start the services:
docker-compose up --build
-
Access the API:
- The API will be available at: http://localhost:3000
-
Run tests:
docker-compose run tests
The application uses the following environment variables in the docker-compose.yml
file:
DB_FILE
: Path to the SQLite database fileREMOTE_USER_DATA
: Remote JSON user data for initialization (if needed)
You can customize these values based on your environment.
.
├── Dockerfile
├── docker-compose.yml
├── main.py # FastAPI application code
├── db.py # Database connection and initialization
├── models.py # Pydantic models
├── test.py # Test cases
├── data/
│ └── hackathon.db # SQLite database (created at runtime)
-
Get all users:
curl -X GET http://localhost:3000/users
-
Update a user:
curl -X PUT http://localhost:3000/users/1 \ -H "Content-Type: application/json" \ -d '{"name": "New Name", "phone": "+1 (555) 999 9999"}'
-
Add a new scan:
curl -X POST http://localhost:3000/scan/1 \ -H "Content-Type: application/json" \ -d '{"activity_name": "Visited Booth", "activity_category": "Event"}'
-
Normalized Database Design: The API uses a relational SQLite database with well-structured tables for
users
andscans
, ensuring efficient data retrieval and minimizing redundancy. Theusers
table includes constraints likeUUID
as the primary key andemail
/badge_code
uniqueness to maintain data integrity. -
Dynamic Query Building: Many endpoints (e.g.,
/scans
and/scans/clusters
) allow dynamic filtering based on optional query parameters like frequency, time periods, and categories, promoting flexibility for different use cases without overloading the database. -
Safety and Validation: All user inputs are validated using Pydantic models (e.g., custom phone number validation) and SQL parameterized queries to prevent SQL injection and ensure data consistency.
-
Idempotent Initialization: The database initialization (
init_db
) ensures that tables are created only if they do not already exist, and partial failures result in clean rollbacks, preventing data corruption.