Online Booking Application

Cliff Hill's Coding Project

This is a full-stack application simulating an online booking system for conference rooms.


Design Decisions

  • Backend:
    • Uses Python 3.13 for modern syntax and improved debugging.
    • FastAPI, SQLAlchemy, asyncpg
    • Follows a modular structure: routers, services, schemas, and models are separated for maintainability.
    • Dataclasses and type hints improve readability and reliability.
    • Async SQLAlchemy for scalable database access.
    • Robust testing with Nox and Pytest.
  • Frontend:
    • React with TypeScript for type safety and maintainability.
    • Material-UI for a modern, responsive UI.
    • Centralized logging
    • Clear separation of concerns.
  • Containerization:
    • Docker Compose for both production and development, with hot-reload and volume mounts for rapid iteration.
    • Production environment is run with a simple docker compose up from the root directory.
    • Development environment is run with docker compose -f compose.dev.yml up from the root directory.
    • Development compose extends the production compose, allowing for changes in the production compose to be reflected in the development compose as well.
  • Security:
    • No authentication in this demo, but structure allows for easy integration of OpenID/JWT.
    • Environment variables for secrets; in production, use a secrets manager.
    • Backend dependencies are validated using security and other tests inside nox.

AI Use

I used AI to stub out a couple of files:

  • The backend/Dockerfile and frontend/Dockerfile - to speed up the process of getting docker loaded efficiently for the project.
  • The compose.yml file - getting the different images gathered together quickly.
  • The compose.dev.yml file - used to get a further understanding of how to hook up an extension to the previous file.
  • The mermaid diagrams used in this file.
  • I have the CodeGPT plugin in VSCode, and it has helped with docstrings, logging messages, and sometimes reducing the time it takes me to write out the code.
  • I used AI to rapidly set up tests for each users component (router, service), then adapted it to the others independently. I believe AI is great for getting reasonable tests written quickly, and then I simply refined it, and replicated the kinds of tests across the different components.
  • I was experimenting with some AI edits for debugging the tests.
  • My frontend skills are less polished than my backend skills. I've been using AI along the lines of how I would use StackOverflow, answering questions to help me get the code written.
  • I used AI to help clean up and better structure the CSS for the frontend project, as well as get some code documentation in place.
  • AI was used to refactor code a few times to make it cleaner and better organized.

Development Environment Setup

Follow these steps to get your local development environment running:

1. Clone the repository

You can use either HTTPS or SSH:

HTTPS:

git clone https://github.com/xlorepdarkhelm/numinar-coding-project.git
cd numinar-coding-project

SSH:

git clone git@github.com:xlorepdarkhelm/numinar-coding-project.git
cd numinar-coding-project

2. Copy environment variables

cp .env.example .env
# Or, if present:
cp .env.sample .env

3. Install backend dependencies

cd backend
poetry install
pre-commit install

5. Install frontend dependencies

cd ../frontend
yarn install

6. Start Docker Compose in development mode (in a separate terminal)

From the project root:

docker compose -f compose.dev.yml up

This will start the backend (port 8000), frontend (port 3000), and Postgres (port 5432) with hot-reload enabled for rapid development.

7. Run tests (backend & frontend)

Backend tests

cd backend
nox           # Run all tests and checks (also builds API docs)
# or run only unit tests:
nox --session=tests
API Documentation
  • The nox command above will also build the backend API documentation.
  • View the API docs in development mode: Open http://localhost:8000/docs in your browser (when running dev Docker Compose).
  • Generated static docs (after running nox): See backend/docs/build/index.html relative to the project root.

Frontend tests

cd frontend
yarn run jest

Further improvements

Integration testing, and end-to-end tests really would make this robust. Having all of the tests run in CICD before allowing code to be merged/commited to the main branch would be a mechanism to help ensure code quality. I would have set up the github project to have "feature branches" be made, to add whatever feature that a work item/issue had, and then Peer Reviews - typically set up with 2 peers reviewing 1 PR and approving it, aswell as all CICD checks/tests needing to pass before allowing the branch to be merged.

I would have templates in place for creating a PR, with a set of instructions that would give the "definition of done" - a checklist that would need to be completed before the issue could be marked as completed and a PR could then be reviewed.

Diagrams

Docker Compose Components

graph TD
  subgraph Docker_Network
    B[Frontend]
    C[Backend]
    D[PostgreSQL]
    C -- "SQL: 5432" --> D
  end
  Client[Client] -- "HTTP: 3000" --> B
  Client -- "HTTP/REST: 8000" --> C

Database Schema Diagram

classDiagram
  class User {
    string email
    string name
  }
  class Room {
    int id
    string name
    string location
    string equipment
    int capacity
  }
  class Booking {
    int id
    int room_id
    datetime start_time
    datetime end_time
    string title
  }
  class Invitee {
    int id
    int booking_id
    string user_email
  }

  User "1" <|-- "*" Invitee : user_email
  Room "1" <|-- "*" Booking : room_id
  Booking "1" <|-- "*" Invitee : booking_id

Component Diagram

graph TD
    subgraph Frontend
        F1[Pages] --> F2[Components]
        F2 --> F3[API Calls]
    end
    subgraph Backend
        B1[FastAPI Routers] --> B2[Pydantic Schemas]
        B1 --> B3[Service Layer]
        B3 --> B4[SQLAlchemy Models]
        B4 --> B5[PostgreSQL]
    end
    F3 -->|REST| B1

Backend Request Data Path

sequenceDiagram
  participant Frontend
  participant FastAPI_Router as FastAPI Router
  participant API_Endpoint as API Endpoint
  participant Pydantic_Schema as Pydantic Schema
  participant Service_Layer as Service Layer
  participant DB_Model as DB Model
  participant Database

  Frontend->>FastAPI_Router: HTTP Request (REST)
  FastAPI_Router->>API_Endpoint: Route Match
  API_Endpoint->>Pydantic_Schema: Validate & Parse Input
  Pydantic_Schema-->>API_Endpoint: Validated Data
  API_Endpoint->>Service_Layer: Pass Data
  Service_Layer->>DB_Model: Business Logic
  DB_Model->>Database: DB Query/Update
  Database-->>DB_Model: Query Result
  DB_Model-->>Service_Layer: Data
  Service_Layer-->>API_Endpoint: Response Data
  API_Endpoint-->>Frontend: HTTP Response (JSON)

SSE Update Flow (Real-Time Room Availability)

sequenceDiagram
  participant Frontend
  participant FastAPI_Router as FastAPI Router
  participant SSE_Endpoint as SSE Endpoint
  participant Event_Generator as Event Generator
  participant Publisher as Publisher

  Frontend->>SSE_Endpoint: Open EventSource /availability/stream
  SSE_Endpoint->>Event_Generator: Start Async Event Loop
  loop While Connected
    Event_Generator->>Publisher: Wait for Event or Timeout
    Publisher-->>Event_Generator: Room Availability Event | Keep-Alive
    Event_Generator-->>Frontend: Send SSE Event (data: ...)
  end
  Frontend-->>SSE_Endpoint: Disconnect (close EventSource)
  SSE_Endpoint-->>Event_Generator: Cleanup Subscriber
Description
The code I used for a coding challenge.
Readme 50 MiB
Languages
Python 54.2%
TypeScript 39%
CSS 5.3%
JavaScript 1%
HTML 0.4%
Other 0.1%