Cliff Hill b4b47efe23 More fixes.
Signed-off-by: Cliff Hill <xlorep@darkhelm.org>
2025-10-06 15:57:14 -04:00
2025-10-06 15:57:14 -04:00
2025-10-06 15:57:14 -04:00
2025-08-26 23:40:47 -04:00
2025-10-06 15:57:14 -04:00
2025-10-02 16:33:41 -04:00
2025-10-02 23:31:17 -04:00
2025-10-02 22:37:45 -04:00
2025-10-02 23:24:44 -04:00

Online Booking Application

Cliff Hill's Coding Project

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


Design Decisions

React Contexts for State Management

  • Global state for rooms, bookings, and users via context providers.
  • Real-time updates using SSE in context.

Modular Component Architecture

  • Reusable, focused components (e.g., BookingForm, RoomList, RoomSelect, CalendarView).
  • Shared UI logic abstracted into dedicated components.

TypeScript for Safety and Documentation

  • Strong typing for all props, state, and data models.
  • Centralized type/interface definitions.

Unified Color and Style Logic

  • Room/event colors assigned by room id modulo, using CSS custom properties.
  • Consistent visual theming across lists, dropdowns, and calendar.

Separation of Concerns

  • Business logic and API calls abstracted into helpers and service modules.
  • Thin UI components focused on rendering and interaction.

Robust Error Handling and Validation

  • Field-level validation and user-friendly error messages in forms.
  • Backend errors formatted for clarity.

Centralized Logging

  • Logging utility used throughout frontend and backend for analytics and debugging.
  • Key actions and lifecycle events are logged.

JSDoc and Docstrings for Documentation

  • File-level and component-level documentation in both frontend and backend.
  • TypeScript interfaces and Python models are documented.

React Router for Navigation

  • Page routing and programmatic navigation after booking actions.

Accessibility and User Experience

  • Disabled states, error messages, and skeleton loaders for better UX.
  • Visual distinction for selected/unavailable rooms.

FastAPI Backend with SQLAlchemy ORM

  • Async API endpoints grouped by resource (rooms, bookings, users).
  • Database models with relationships and constraints.

Pydantic Schemas for Validation

  • Separate schemas for create, update, and response objects.

Service Layer Abstraction in Backend

  • Business logic separated from HTTP routing.

Testing and Code Quality

  • Pytest, coverage, pre-commit hooks, and code style enforcement for backend; run pytest from the backend folder.
  • Jest and React Testing Library, code style enforcement and additional pre-commit hooks for frontend; run yarn run jest from the frontend folder.
  • All tests can be run from thenox command in the root directory, or for tests specific to each part of the project, run nox in either frontend or backend respectively.
    • nox frontend tests include: pre-commit, coverage, audit, storybook, and jest.
    • nox backend tests include: pre-commit, safety, mypy, tests, typeguard, xdoctest, and docs-build.

nox could very easily be integrated into a CICD pipeline for full validation of the code to be done before anything could be merged into main.

Docker Compose for Orchestration

  • Multi-service setup: backend (FastAPI), frontend (React), and Postgres database.
  • Custom network, healthchecks, and persistent volumes.
  • Environment variables managed via .env files.

Extensibility and Maintainability

  • Modular design for easy feature addition and refactoring.
  • Generated from Hypermodern Python Cookiecutter for best practices.

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.
    • AI was very helpful in getting the frontend to do what I wanted quickly.
  • 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.
  • AI was used for debugging the tests to quickly correct them, for frontend and backend.

Documentation & Storybook

Backend API Documentation

To build and view the backend API documentation:

  1. Navigate to the backend directory:
cd backend
  1. Run the Nox docs session (live-reloading server):
nox -s docs

This will build and serve the docs with live reloading. Your browser should open automatically to the docs at: http://localhost:8000/docs

Alternative (static build):

If you want to build the static HTML docs only:

cd backend
nox -s docs-build
xdg-open docs/_build/index.html  # Linux
open docs/_build/index.html      # macOS
start docs/_build/index.html     # Windows

Or manually open docs/_build/index.html in your browser.

Frontend Storybook

To run Storybook for the frontend using Nox:

  1. Navigate to the frontend directory:
cd frontend
  1. Run the Nox storybook session:
nox -s storybook

This will start Storybook and open your browser to: http://localhost:6006

Alternative (static build):

If you want to build the static Storybook docs only:

cd frontend
nox -s storybook-build
xdg-open storybook-static/index.html  # Linux
open storybook-static/index.html      # macOS
start storybook-static/index.html     # Windows

Or manually open storybook-static/index.html in your browser.


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
nox
# or run only nox tests:
nox --session=jest

All tests

from the project root

nox

Note - you can use any of the sessions from frontend or backend here to isolate just that test.

Nox and Pre-commit Integration

This project uses Nox for orchestrating development, testing, and code quality sessions across both frontend and backend. Pre-commit hooks are managed via pre-commit and are integrated into the Nox workflow for consistent linting and formatting.

  • Nox sessions are defined in both the project root and in the frontend and backend directories. You can run all sessions from the root, or target frontend/backend specifically.
  • Pre-commit is run as a Nox session (nox -s pre-commit) and also as a git hook. Both use pinned tool versions and shared config files for consistency.
  • Typical usage:
    • Run all checks: nox (from root)
    • Run only frontend checks: cd frontend && nox
    • Run only backend checks: cd backend && nox
    • Run pre-commit manually: nox -s pre-commit or pre-commit run --all-files

Troubleshooting & FAQ

Q: Why does isort or black change files differently in Nox vs pre-commit? A: Make sure both Nox and pre-commit are using the same pinned tool versions and config files. See .isort.cfg and .pre-commit-config.yaml for details.

Q: Why does Storybook open the browser or not exit when run in CI/Nox? A: Use yarn build-storybook for static builds (exits automatically). For dev server, use yarn storybook dev --ci to prevent browser opening.

Q: Why do pre-commit hooks modify files after a commit or behave differently in CI? A: Pre-commit runs in its own environment. Always run pre-commit run --all-files locally to reproduce CI behavior. Ensure your config files are up to date and tool versions are pinned.

Q: How do I run only frontend or backend tests? A: Use Nox in the respective directory (cd frontend && nox, cd backend && nox).

Q: How do I fix environment or dependency issues? A: Delete .venv or node_modules and reinstall dependencies (poetry install for backend, yarn install for frontend). Check for version mismatches in config files.

Q: Where are config files for formatting and type checking? A: See .isort.cfg, .coveragerc, and mypy.ini in the project root. These are derived from backend settings for consistency.


Diagrams

Docker Compose Components

%% Docker Compose Architecture
graph TD
  subgraph docker_network
    B[Frontend<br/>Port: 3000]
    C[Backend<br/>Port: 8000]
    D[PostgreSQL<br/>Port: 5432]
    C -- "SQL: 5432" --> D
  end
  Client[Client] -- "HTTP: 3000" --> B
  Client -- "HTTP/REST: 8000" --> C

Database Schema Diagram

%% Database Schema with Types and Keys
classDiagram
  class User {
    string email [PK]
    string name
  }
  class Room {
    int id [PK]
    string name
    string location
    string equipment
    int capacity
  }
  class Booking {
    int id [PK]
    int room_id [FK]
    datetime start_time
    datetime end_time
    string title
  }
  class Invitee {
    int id [PK]
    int booking_id [FK]
    string user_email [FK]
  }

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

Component Diagram

%% Component Relationships and Data Flow
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
    B5 -.->|External| PG[PostgreSQL Service]

Backend Request Data Path

%% Backend Request Data Path with Error Handling
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
  alt Validation Error
    Pydantic_Schema-->>Frontend: HTTP 422 Unprocessable Entity
  else Validated
    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)
  end

SSE Update Flow

%% SSE Update Flow with Event Types
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: {type: "availability" | "keep-alive"})
    note over Publisher,Frontend: Trigger: Booking created/updated/deleted
  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%