Files in the top-level directory of check-in trunk
- .build.yml
- .coffeedb
- .gitignore
- .nvmrc
- bin
- etc
- src
- Dockerfile
- LICENSE.md
- owasp-suppressions.xml
- package-lock.json
- package.json
- pom.xml
- README.md
- tsconfig.json
- webpack.config.js
Coffee Time
A service for scheduling, hosting, and participating in a Lean Coffee conversation.
Requirements
Java 17 or higher.
NVM (see .nvmrc for version)
How to run
bin/run-server
Fast development
Set env var COFFEE_RESOURCE_TYPE=disk
This causes the following files to load directly from disk instead of using the classloader (see ResourceType for more):
resources/templates (ResourceType#configureVelocity)
target/classes/* (ResourceType#chooseResourceFetcher)
Run CoffeeTime using the method above. This causes NPM to install and so on.
Then, run: bin/run-dev-watch
This causes a bunch of folders to be watched for changes in parallel and recompiled / deployed on-the-spot.
All at once (Easy Button™)
(requires screen: brew install screen
)
If you want a super simple way to do everything at once, properly, simply
run bin/dev
To shut it all down (the easy way):
bin/stop-dev
To kill everything in the screen (the hard way):
- CTRL+c (kill the first side process)
- CTRL+a, <tab> (switch to the second side)
- CTRL+c (kill the second side process)
Using Podman
You can get a clean podman image tagged as coffeetime
by using bin/package
Then you can run the image using something like the command you see
in bin/start-coffeetime
Recommended tooling for local 12-factor
https://12factor.net/ : "In the modern era, software is commonly delivered as a service: called web apps, or software-as-a-service. The twelve-factor app is a methodology for building software-as-a-service apps..."
https://direnv.net/ : "direnv is an extension for your shell. It augments existing shells with a new feature that can load and unload environment variables depending on the current directory."
Configuration
Regenerate this section by running bin/docs
The following environment variables can be used to configure the server:
COFFEE_AUTH0_CALLBACK_URI
: URI to return to after Auth0 authentication
: Defaults to http://127.0.0.1:3000/auth0
COFFEE_AUTH0_CLIENT_ID : Which app in Auth0 to authenticate against
COFFEE_AUTH0_CLIENT_SECRET : Proof we are allowed to retrieve user info from Auth0
COFFEE_AUTH0_DOMAIN : Which Auth0 tenant our app is in
COFFEE_AUTH0_MGMT_CLIENT_ID : Used to perform Auth0 management functions like creating a new user
COFFEE_AUTH0_MGMT_CLIENT_SECRET : Proof we are allowed to perform Auth0 management functions
COFFEE_AUTO_WRAPUP_SCHEDULE
: Schedule to use to automatically wrap up finished events
: Defaults to 0 0 0 * * ?
COFFEE_BASE_URL
: The base url that we append to when generating links for activation, opt out, etc.
: Defaults to http://localhost:3000
COFFEE_CONTACT_EMAIL_SCHEDULE
: Schedule to use to send emails to contacts
: Defaults to 0 0 * ? * *
COFFEE_DB_LOC
: Location of our database
: Defaults to coffeetime.db
COFFEE_EVENT_HOST_EMAIL_SCHEDULE
: Schedule to use to send emails to hosts or individual participants
: Defaults to 0 0 * ? * *
COFFEE_EVENT_NOTIFICATION_ENABLED
: Does the server support event notifications?
: Defaults to true
COFFEE_EVENT_NOTIFICATION_SCHEDULE
: Schedule to use to send upcoming event notifications
: Defaults to 0 0 0 ? * 1
COFFEE_EVENT_PARTICIPANT_EMAIL_SCHEDULE
: Schedule to use to send mass participant emails
: Defaults to 0 0 10 ? * *
COFFEE_JOB_THREADS
: How many threads can be allocated to running background jobs
: Defaults to 4
COFFEE_LINKEDIN_CLIENT_ID : Used to enable LinkedIn authentication
COFFEE_LINKEDIN_CLIENT_SECRET : Proof we are allowed to authenticate LinkedIn users
COFFEE_LIVEKIT_DOMAIN : Domain name to find LiveKit Server at
COFFEE_LIVEKIT_KEY : Name of the key to use to authenticate against the LiveKit server
COFFEE_LIVEKIT_SECRET : Value of the key to authenticate against the LiveKit server
COFFEE_LOG_FILE
: If logging to a file, which file to log to
: Defaults to ./coffeetime.log
COFFEE_LOG_LEVEL
: What level of log messages to emit
: Defaults to INFO
COFFEE_LOG_TYPE
: What type of logging to perform. 'file' means log to the given log location, otherwise console
: Defaults to console
COFFEE_NOTIFICATION
: Notification style. You can use print
or email
. If you use anythingelse, it will default to print
.
: Defaults to print
COFFEE_PORT
: Port to listen on
: Defaults to 3000
COFFEE_RESOURCE_TYPE : Where to fetch static resources from. Value values: disk, classloader
COFFEE_SEARCH_LOC
: Location of the search index
: Defaults to search
COFFEE_SECURE_COOKIES
: Should we set cookies securely? Set to 'false' if you are testing locally without SSL
: Defaults to true
COFFEE_SENTRY_DSN : Authentication token for www.sentry.io
COFFEE_SENTRY_ENV
: Value of environment in Sentry
: Defaults to prod
COFFEE_SMTP_FROM : Email address for the 'from' address of emails we send
COFFEE_SMTP_PASSWORD : SMTP user's password
COFFEE_SMTP_PORT
: What port the SMTP server listens on
: Defaults to 465
COFFEE_SMTP_SERVER : Where to send emails to. Used for email notifications
COFFEE_SMTP_USER : User to authenticate against the SMTP server with
COFFEE_SUPPORT_EMAIL
: Email address users should email when they need help
: Defaults to support@example.com
COFFEE_WS_URL
: The url we use to connect via WebSocket
: Defaults to ws://localhost:3000/
Feature Flags
Sometimes features need to be put onto mainline but disabled so we can continue
development work and ensure quality simultaneously. You can add a feature flag
by setting an environment variable: COFFEE_FF_<NAME>
Then, refer to <NAME>
in template files:
${flags.is(<NAME>, <VALUE>)}
or in regular code: Env.flagIs(<NAME>, <VALUE>)
One flag that is permanently used in the codebase is COFFEE_FF_MODE
.
If you set this to dev
you'll get fancy links at the bottom of the page
to do naughty things like approve all events and move a bunch of them
around, etc.
Protocol Buffers
Coffee Time communicates large data using Protocol Buffers. Especially Event information, which can get quite large. This saves a lot of CPU time on encoding and decoding on both the client and server.
Our implementation of Protocol Buffers is ... special. It relies on automatically generated protocol files from annotated Java classes. There are a few gotchas to pay attention to.
First: all fields are marked as optional. This means that any value can be serialized as null across the wire.
Second: the implementation of protocol buffers we are using for JavaScript has a strange quirk. If a field isn't present, it is set to its default value. For strings, that value is '', and for numbers, it's 0. So, in order to tell the difference between 0 and not-present (which usually translates to null), you have to:
v.hasOwnProperty("key") ? v.key : null
instead of just:
v.key
Technical Goals
We are attempting to evolve the system toward greater simplicity. To that end:
- We should move towards server-side rendering. This will eventually remove our dependence on node for compiling javascript, lit components, protocol buffers, etc.
- Nothing else yet. I'm sure we'll come up with something!
Maintaining your own fork of the software
We have included a link to the source code of this project in
src/main/resources/templates/web/page.vm
-- you can find the link
near a comment that says "LICENSE NOTE"
Copyright
(c) 2024, Stephen Starkey. All Rights Reserved.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published by the
Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.