The teammate repo is based on a fork of gph-site, with many changes made to support the needs of past Teammate Hunts. The largest change is changing the site from pure Django to a Next.js + Django hybrid, with a React-based frontend. As such, it is largely incompatible with gph-site architecture and unfortunately cannot be merged upstream.
If you are not familiar with React, we suggest using gph-site to get started. However, if you would like more control over your frontend, especially around interactive components, this repo is for you.
For setup and development instructions, read on.
For detailed overviews of the backend and frontend, check the server and client READMEs respectively.
For a high-level overview of how this repo works, or more advanced features, check the doc directory.
For additional features added for Mystery Hunt 2023, see Mystery Hunt.
Developing in the repository requires git
, docker
, and docker-compose
.
git
: Install as part of Xcode or can be installed withbrew install git
if you have homebrew.docker
: Install Docker Desktop for Macdocker-compose
: Comes with Docker Desktop for Mac
If your Windows is relatively up-to-date, the easiest way to develop on windows is via the Windows Subsystem for Linux (WSL).
- WSL: In command prompt or powershell, run
wsl --install
if supported or else follow the Microsoft documentation).- This should work with any selection of linux distro, but Ubuntu is known to work.
git
: Comes pre-installed with Ubuntudocker
: Install Docker Desktop for Windowsdocker-compose
: Comes with Docker Desktop for Windows
For all the commands in the rest of this readme, use the WSL or Ubuntu terminal.
If you don't want to or can't install these, an alternative is to start a Ubuntu virtual machine and follow the linux instructions.
git
: Use your package manager to installgit
docker
: Use your package manager (apt-get install docker.io
on Ubuntu) or follow one of the official installation methods- It is recommended to add yourself to the docker
group (
sudo usermod -aG docker $USER
and then log out and log back in) so you can run without needingsudo
.
- It is recommended to add yourself to the docker
group (
docker-compose
: Depending on your installation source,docker
may have come withdocker-compose
. (Test withdocker-compose --version
.) If not, if you havepython
andpip
, the easiest way to install is withpip install --user docker-compose
. Otherwise, follow one of these methods.
Enter your github username and password when prompted.
# FIXME
git clone https://github.com/teammatehunt/tph-site.git
cd tph-site
If you have ssh keys set up, you can clone with git clone [email protected]:teammatehunt/tph-site.git
(FIXME)
instead for passwordless authentication.
This will install git pre-commit hooks and build the development environment.
./initialize_dev
Next, load the fixtures (puzzle, round, and other metadata imported from PuzzUp):
./scripts/load_fixtures
Open a browser and go to https://localhost:8081/
. There will probably be a
"Not Secure" / certificates warning (because running locally uses a self-signed
certificate). Proceed anyways (in Chrome, click "Advanced" and then "Proceed
anyway (unsafe)").
You should now see a development version of the site! In the dev environment, a
testsolving team has been created with username dev
and password dev
. If
you need to access the admin panel, there is also an admin account with
username admin
and password admin
.
If you have multiple domains enabled, you can go to https://localhost:8082
.
./scripts/tail_tph_logs
./teardown
You can also display docker level logs with ./scripts/tail_docker_logs
but it
is less likely you will need them.
While running, persistent server data is mounted under a docker volume (on
linux it is probably /var/lib/docker/volumes/tph-site_srv_dev
). (FIXME)
Postproduction is integrated with PuzzUp. You can use the autopostprod feature on PuzzUp to scaffold a new puzzle (see the Guide here).
This will automatically create a new branch you can checkout on Git. Make sure to
run ./scripts/load_fixtures
to load the puzzle metadata into your database.
To scaffold a puzzle manually, run this script and follow the command line prompts to enter the puzzle title, answer, etc. This will automatically create the puzzle in the database and the proper frontend files.
./scripts/create_new_puzzle
Edit client/pages/puzzles/[INSERT_SLUG].tsx
to your liking. You can
login (username dev
, password dev
) and see your puzzle at
https://localhost:8081/puzzles/[INSERT_SLUG]
. (Static information can be viewed in
the development environment without logging in, but login is needed to
authenticate puzzle data from the server side.)
If you need to edit server side puzzle model information, you can go to
https://localhost:8081/admin
(username admin
, password admin
).
We use the black Python formatter and
prettier for Typescript files.
pre-commit will enforce formatting (as well as run
some other basic checks like ensuring we do not commit directly to staging or
main). This gets installed to your git hooks on the first instantiation of
./initialize_dev
.
If you have a section of code that you don't want to be touched by our
formatters, you can add a comment to ignore. For example, in .tsx
files,
inserting {/* prettier-ignore */}
will cause the entire HTML/JSX node
following the comment to not be reformatted. This can be useful for pasting in
generated code, such as a table produced from an external script (though we
would encourage storing generated data as intermediary json assets and
importing them instead).
If you need to commit and bypass style checks (eg, code is a broken
work-in-progress and you are trying to share with someone), you can run git commit --no-verify
to not run git hooks.
Changes to the site are version controlled by git. We use pull requests (PRs) to review the changes before they are merged into the production branch.
- Make sure you have added the puzzle to the fixtures. Either add it via
https://localhost:8081/admin
and then run./scripts/save_fixtures
OR editserver/tph/fixtures/puzzles/<slug>.yaml
directly.- Set the puzzle name, slug, and emoji.
- If the puzzle has already been testsolved, you can set the
meta
andround
fields accordingly.
- Format, commit, and push changes to Github.
git checkout -b postprod/[INSERT_SLUG] # postprodding should be done on a new branch
git add :/ # add all changes to the staging index
git commit -m '[INSERT POSTPROD MESSAGE]' # commit changes
git push -u origin postprod/[INSERT_SLUG] # push branch to github (might ask you to authenticate)
- Then if you go to , you
will be able to create a PR with your changes.
- When the PR is created, a pipeline will start which verifies type checks and static code generation for typescript/React.
- If it fails, you can make changes to fix it and push again. If you want to run the full build locally, read "Running as in prod".
Build and push steps are configured via Github CI/CD workflows in
.github/workflows
. Build and tests will automatically run on every commit.
After pushing a commit, the frontend will be deployed to
[YOUR-BRANCH-SLUG].branch.teammatehunt.com
. The basicauth username / password
are the same as the ones for the staging site.
You can manually trigger the deploy step via the [GitHub Actions
UI](FIXME repo-url /actions/workflows/deploy-staging.yml)
in order to deploy to staging or production (by clicking "Run Workflow"). Note
that deploys to prod will fail if you pick something other than the main
branch.
The development environment is built to allow for hot reloading of typescript and python files. There are occasionally subtle differences between how a puzzle could operate in the development environment and in staging/production. The other reason you could be interested in building the prod version is that Next.js will compile the typescript files with strict type checks.
This will build and start the staging site environment (except with the domain pointing to localhost). Note that this will use a separate database from the dev environment.
./scripts/initialize_staging_localhost
No users or teams are created by default for the staging environment.
Google Drive is the source of truth for round art and puzzle icons. We use
./scripts/sync_media
to sync these to a machine and generate a unique mapping
of hashed filenames to serve from. To fetch these locally, you can put the
service account credentials FIXME
in the root of this repo and run ./scripts/sync_media [DEST_DIRECTORY]
.
To fetch them into the development container, in the root of this repo run ./scripts/sync_media dev
.
The asset map is loaded into each process' memory during startup automatically.
If you already have a server running, either restart your server or hot reload
Django (by editing/saving a Python file) to see the new assets.
To resolve a path to its hashed name, use puzzles.assets.get_hashed_url
.
After adding a dependency to server/poetry/pyproject.toml
, running
./scripts/update_poetry_lock
(while the dev container is running), and
rebuilding the docker container should work smoothly. Also see
the backend documentation.
After adding a dependency to client/package.json
, running
./scripts/update_yarn_lock
(while the dev container is running), and
rebuilding the docker container should work smoothly.
To dump the database, run:
docker-compose exec -T -u postgres db pg_dump postgres > ~/{staging,prod}-{date}.dump
To load the database (after putting the file on another machine), shut down the
existing containers, delete the tph_pgdata
volume, start the postgres server,
load the database, and refresh the container.
./teardown
docker volume rm tph_pgdata
docker-compose up -d db
docker-compose exec -T -u postgres db psql postgres < ~/staging-{date}.dump
./initialize_dev
Use the --reg
arg (ie, ./initialize_dev --reg
or
./scripts/initialize_staging_localhost --reg
) to also run the registration site
on https://localhost:8083
.
The frontend for the registration site uses reg-client/
instead of client/
,
though files and directories that should be the same can be symlinked.
This section is outdated. Docker handles all of these together. But if you're interested in the components that work together, you can read on.
The front-end is a full web application written in React, with the Next.js
framework. Run yarn start
to start the development server. It will
automatically re-build any changes you make to the code.
The back-end is a Django application that primarily serves as an API to power
the front-end. Run ./manage.py runserver
to start the development server. It
will automatically re-build any changes you make to the code.
Some requests should go to the front-end's development server, and some to the
back-end's. To route the requests appropriately, we're using caddy
as a
reverse proxy.