diff --git a/README.md b/README.md index b1a88d5c..c25c4a9d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Thunderbird Appointment -**Note: Thunderbird Appointment is in a beta state, so be prepared to encounter bugs** +> [!IMPORTANT] +> Thunderbird Appointment is in a beta state, so be prepared to encounter bugs Invite others to grab times on your calendar. Choose a date. Make appointments as easy as it gets. diff --git a/backend/.env.example b/backend/.env.example index 437deb8a..ea39e848 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -86,8 +86,6 @@ SIGNED_SECRET= SENTRY_DSN= # -- TESTING -- -AUTH0_TEST_USER= -AUTH0_TEST_PASS= CALDAV_TEST_PRINCIPAL_URL= CALDAV_TEST_CALENDAR_URL= CALDAV_TEST_USER= diff --git a/backend/.env.test b/backend/.env.test index 86bf7db2..5061bf39 100644 --- a/backend/.env.test +++ b/backend/.env.test @@ -78,8 +78,6 @@ JWT_ALGO=HS256 JWT_EXPIRE_IN_MINS=10000 # -- TESTING -- -AUTH0_TEST_USER= -AUTH0_TEST_PASS= CALDAV_TEST_PRINCIPAL_URL=https://example.org CALDAV_TEST_CALENDAR_URL=https://example.org CALDAV_TEST_USER=hello-world diff --git a/backend/README.md b/backend/README.md index 28b630ea..bc659c1b 100644 --- a/backend/README.md +++ b/backend/README.md @@ -10,7 +10,7 @@ More information will be provided in the future. There is currently a docker fil In order to create a user with password authentication mode, you will need to set `APP_ALLOW_FIRST_TIME_REGISTER=True` in your `.env`. -After the first login you'll want to fill the `APP_ADMIN_ALLOW_LIST` env variable with your account's email to access the basic admin panel located at `/admin/subscribers`. +After the first login you'll want to fill the `APP_ADMIN_ALLOW_LIST` env variable with your account's email to access the basic admin panel located at `/admin/subscribers`. ### Configuration diff --git a/backend/src/appointment/controller/auth.py b/backend/src/appointment/controller/auth.py index ead5a3f7..ca17f7f3 100644 --- a/backend/src/appointment/controller/auth.py +++ b/backend/src/appointment/controller/auth.py @@ -1,6 +1,6 @@ """Module: auth -Handle authentification with Auth0 and get subscription data. +Handle authentification with FxA and get subscription data. """ import os diff --git a/docs/README.md b/docs/README.md index 5ca13c59..6b5256c2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,12 +16,15 @@ C4Component ContainerDb(c4, "Database", "MySQL", "Subscribers, calendars,
appointments, attendees, ...") Container(c1, "Frontend", "Vue3 / Tailwind", "Provides all Appointment
functionality to customers
via their web browser") Container_Boundary(b1, "Backend") { - Component(c3, "Subscriber Area", "FAstAPI, JWT auth", "Provides functionality related
to calendar connections,
appointments, general availability") - Component(c2, "Auth Controller", "FastAPI", "Redirects to Auth0 service,
authenticates subscriber,
gets subscription level") + Component(c3, "Subscriber Area", "FastAPI, JWT auth", "Provides functionality related
to calendar connections,
appointments, general availability") + Component(c2, "Auth Controller", "FastAPI", "Redirects to FxA service,
authenticates subscriber,
gets subscription level") Component(c5, "Public Link Area", "FastAPI", "Allows visitors to choose
slots in given
availability timeline.") - System_Ext(e3, "Google Server", "Allows to query and write
event data into calendars
using Google API") - System_Ext(e2, "CalDAV Server", "Allows to query and write
event data into calendars
using CalDAV format") - System_Ext(e1, "Auth0", "Allows users to register,
sign in and subscribe
to an Appointment tier") + Boundary(e1, "External Connections") { + System_Ext(e3, "Google", "Allows to query and write
event data into calendars
using Google API") + System_Ext(e2, "CalDAV", "Allows to query and write
event data into calendars
using CalDAV format") + System_Ext(e1, "FxA", "Allows users to register,
sign in and subscribe
to an Appointment tier") + System_Ext(e4, "Zoom", "Allows to create meeting links
and attach them to events
using Zoom integration") + } } BiRel(c1, c2, "Call Sign up / in", "HTTPS") Rel(c2, c3, "Authentication
succeeded", "Session") @@ -30,6 +33,7 @@ C4Component BiRel(c2, e1, "Authenticate Account", "OAuth2") BiRel(c3, e2, "Query event data", "JSON/HTTPS") BiRel(c3, e3, "Query event data", "JSON/HTTPS") + BiRel(c3, e4, "Meeting links", "JSON/HTTPS") UpdateRelStyle(c1, c2, $textColor="#999", $offsetY="-60", $offsetX="-110") UpdateRelStyle(c2, c3, $textColor="#999", $offsetY="20", $offsetX="-38") @@ -38,6 +42,7 @@ C4Component UpdateRelStyle(c2, e1, $textColor="#999", $offsetY="0", $offsetX="10") UpdateRelStyle(c3, e2, $textColor="#999", $offsetY="0", $offsetX="10") UpdateRelStyle(c3, e3, $textColor="#999", $offsetY="0", $offsetX="10") + UpdateRelStyle(c3, e4, $textColor="#999", $offsetY="150", $offsetX="20") UpdateElementStyle(c4, $fontColor="black", $bgColor="#eddcea", $borderColor="#a30086") UpdateElementStyle(c2, $bgColor="#456789") UpdateElementStyle(c3, $bgColor="#456789") @@ -51,17 +56,24 @@ The database contains the following tables and columns. ```mermaid erDiagram + ALEMBIC_VERSION { + string version_num PK "Unique hash indicating current db migration state" + } SUBSCRIBERS { int id PK "Unique user key" string username "URL-friendly username, format is restricted" - string email "Preferred email address (synced with Auth0)" + string email "FxA account email and email used for password auth" string name "Preferred display name" enum level "Subscription level [basic, plus, pro, admin]" int timezone "User selected home timezone, UTC offset" - string google_tkn "Google state token for calendar API authentication" - string google_state "Temp storage for verifying google state" - date google_state_expires_at "Google state expiration date" + string avatar_url "Public link to an avatar image" string short_link_hash "Hash for verifying user link" + string minimum_valid_iat_time "Minimum valid time to accept for JWT tokens" + date time_created "UTC timestamp of subscriber creation" + date time_updated "UTC timestamp of last subscriber modification" + string secondary_email "Secondary email address" + date time_deleted "UTC timestamp of deletion (soft delete)" + int ftue_level "Version of the FTUE the user has completed" } SUBSCRIBERS ||--o{ CALENDARS : own CALENDARS { @@ -75,6 +87,38 @@ erDiagram string password "Passphrase to access the calendar" bool connected "Flag indicating if calendar is actively used" date connected_at "Date calendar was connected" + date time_created "UTC timestamp of calendar creation" + date time_updated "UTC timestamp of last calendar modification" + } + SUBSCRIBERS ||--o{ EXTERNAL_CONNECTIONS : create + EXTERNAL_CONNECTIONS { + int id PK "Unique connection key" + int owner_id FK "Person who creates and owns this connection" + string name "Custom connection title" + enum type "Connection type [zoom, google, fxa, caldav]" + string type_id "Type specific user or unique identifier (e.g. FXA/Zoom/etc. user id)" + string token "Passphrase or passtoken for connecting" + date time_created "UTC timestamp of connection creation" + date time_updated "UTC timestamp of last connection modification" + } + SUBSCRIBERS ||--o{ INVITES : hold + INVITES { + int id PK "Unique invite key" + int subscriber_id FK "User created from this invite" + string code "Unique invitation code" + enum status "Invitation status [active, revoked]" + date time_created "UTC timestamp of invite creation" + date time_updated "UTC timestamp of last invite modification" + int owner_id FK "Used (admin) giving out this invitation" + } + INVITES ||--o{ WAITING_LIST : manage + WAITING_LIST { + int id PK "Unique waiting list entry key" + string email "Email address invited" + date email_verified "UTC timestamp of email verification" + int invite_id FK "Invited associated with this waiting list entry" + date time_created "UTC timestamp of waiting list entry creation" + date time_updated "UTC timestamp of last waiting list entry modification" } CALENDARS ||--o{ APPOINTMENTS : create_from APPOINTMENTS { @@ -94,11 +138,14 @@ erDiagram string slug "Generated random string to build share links for the appointment" bool keep_open "If true appointment accepts selection of multiple slots (future feature)" enum status "Appointment state [draft, ready, close]" + string meeting_link_provider "Name of the provider for meeting links (e.g. Zoom)" + uuid uuid "Binary field holding a universal unique identifier" } CALENDARS ||--|{ SCHEDULES : connected_to SCHEDULES { int id PK "Unique schedule key" int calendar_id FK "Calendar which events are created in for this schedule" + bool active "True if schedule is enabled" string name "Schedule title" enum location_type "[In person, online]" string location_url "URL events are held at" @@ -107,12 +154,16 @@ erDiagram date end_date "UTC end date of scheduled date range" date start_time "UTC start time on selected weekdays" date end_time "UTC end time on selected weekdays" - json weekdays "List of selected weekdays (1-7, ISO format)" int earliest_booking "Can't book if it's less than this many minutes before start time" int farthest_booking "Can't book if start time is more than this many minutes away" + json weekdays "List of selected weekdays (1-7, ISO format)" int slot_duration "Size of the Slot that can be booked in minutes" date time_created "UTC timestamp of schedule creation" date time_updated "UTC timestamp of last schedule modification" + string meeting_link_provider "Name of the provider for meeting links (e.g. Zoom)" + string slug "Random or customized url part" + bool booking_confirmation "True if booking requests need to be confirmed by owner" + string timezone "Configured timezone name (e.g. America/Vancouver, Europe/Berlin, etc)" } SCHEDULES ||--|{ AVAILABILITIES : hold_custom SCHEDULES ||--|{ SLOTS : provide_on_request @@ -137,9 +188,12 @@ erDiagram date time_updated "UTC timestamp of last slot modification" date start "UTC timestamp of slot starting time" int duration "Custom slot duration, number of minutes [10-600]" + string meeting_link_id "Meeting link identifier" + string meeting_link_url "Meeting link url" string booking_tkn "Temp storage for verifying booking slot" date booking_expires_at "Booking expiration date" enum booking_status "[none, requested, booked]" + date time_created "UTC timestamp of slot creation" } SUBSCRIBERS ||--o{ SLOTS : choose ATTENDEES ||--o{ SLOTS : select @@ -147,5 +201,8 @@ erDiagram int id PK "Unique key of attendee" string email "Email address of the attendee" string name "Name of the attendee" + date time_created "UTC timestamp of attendee creation" + date time_updated "UTC timestamp of last attendee modification" + string timezone "Detected timezone name" } ```