Skip to content
oliverdozsaPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

37 Commits

Folders and files

Repository files navigation

chorahost

Backend API for a gamified household chore tracker. Teams (a household, a flat share) post chores as cards with a rarity, XP and gold rewards. Members claim cards, complete them, and an admin verifies the work, which pays out the rewards and levels the member up.

Built with Quarkus 3 (Java 21), PostgreSQL, Flyway and Google OIDC.

Concepts

  • Teams and roles. A user can belong to many teams, with an independent role in each: USER, ADMIN or TEAM_ADMIN (the team creator). Level, XP and gold are tracked per team membership, not globally.
  • Invitation-only joining. An ADMIN or TEAM_ADMIN invites an email address and gets back a one-time invite code (the API returns it; delivery is up to the caller). The invitee must be signed in with that same email to accept, by code or by invitation id. Invites expire after 7 days, and re-inviting an email revokes the earlier invite.
  • Chore cards. Cards have a rarity (COMMON, RARE, EPIC, LEGENDARY), XP and gold rewards, an optional due date and an optional image. Lifecycle: AVAILABLE → CLAIMED → COMPLETED → VERIFIED. A claimed card can be unclaimed, and claimed cards past their due date are handled by a background job.
  • Templates and recurrence. Card templates let admins respawn cards automatically, either on a schedule (daily, weekly, monthly, or every N minutes) or N minutes after the previous card was verified.
  • Levelling. Reaching the next level takes level × 1000 XP, with overflow carried into the following level.
  • Seasons. Each team runs back-to-back seasons (default 30 days; admins can set 7-365 days for future seasons). When one ends, a background job archives every member's final rank, level, XP, gold and verified-card count as season results, then resets level, XP and gold to start fresh. Rewards are paid at verification time into whichever season is running. Admins can end a season early or extend the running one. Cards and templates are never reset.
  • Shop. Each team has its own shop. Admins list items with a name, a gold price, an optional image URL and a stock (leave it out for unlimited). Members spend the gold of their membership in that team, any time, on one or more units of an item. Purchases are recorded with the name and price paid, and admins mark them fulfilled once handed over. The shop stays open across seasons (only the gold is reset). Deleting an item just hides it, so history is kept. There are no refunds.

Getting started

Requirements: JDK 21 and Docker (Quarkus Dev Services starts a throwaway PostgreSQL container for dev and tests, so no local database is needed).

./mvnw quarkus:dev

Dev mode seeds two teams with members and cards (alice, bob, carol, dave and emily at @example.com).

Authenticating

All /api/* endpoints require a bearer token, either a Google-issued ID token or a chorahost session token. Google ID tokens only last an hour, so clients sign in with Google once, trade the ID token for a session token with POST /api/v1/auth/session, and send that from then on. The response is {token, expiresAt, name, email, picture}. Session tokens start with chs_, last 30 days and slide forward as they are used, so a client that is opened now and then stays signed in. DELETE /api/v1/auth/session revokes the one in use. A session token cannot mint another session; renewal goes back through Google.

In dev mode you can skip Google entirely and impersonate any user with a header:

curl -H 'X-Dev-User: alice@example.com' http://localhost:8080/api/v1/users/me

The header is only honored under the dev profile.

API overview

Everything is under /api/v1 and returns JSON. An OpenAPI description is served by the SmallRye OpenAPI extension at /q/openapi.

Area Endpoints
Auth POST /auth/session (Google ID token in, session token out), DELETE /auth/session
Users GET /users/me, GET /users/{id}, GET /users/{id}/hand
Teams POST /teams, GET /teams/{id}/leaderboard, GET /teams/{id}/cards, GET /teams/{id}/card-templates, POST /teams/{id}/role, PUT /teams/{id}/members/{userId}/gold
Seasons GET /teams/{id}/seasons, GET /teams/{id}/seasons/current, GET /teams/{id}/seasons/{seasonId}/results, PUT /teams/{id}/season-length, POST /teams/{id}/seasons/end, POST /teams/{id}/seasons/extend
Invitations (admin side) POST/GET /teams/{id}/invitations, DELETE /teams/{id}/invitations/{invitationId}
Invitations (invitee side) GET /invitations, POST /invitations/accept (body {"code": "..."}), POST /invitations/{id}/accept
Shop GET/POST /teams/{id}/shop/items, PUT/DELETE /teams/{id}/shop/items/{itemId}, POST /teams/{id}/shop/items/{itemId}/purchase (body {"quantity": 1}), GET /teams/{id}/shop/purchases (?all=true for admins), PUT /teams/{id}/shop/purchases/{purchaseId}/fulfilled
Cards POST /cards, PUT/DELETE /cards/{id}, POST /cards/{id}/claim, /unclaim, /complete, /acknowledge-reward, /verify
Card templates POST /card-templates, PUT/DELETE /card-templates/{id}

Creating, editing, deleting and verifying cards, managing invitations, managing seasons (length, end, extend) and managing shop items and fulfilment, require ADMIN or TEAM_ADMIN in the card's team. Assigning roles requires TEAM_ADMIN.

Example: invite someone and accept as them.

curl -X POST -H 'X-Dev-User: alice@example.com' -H 'Content-Type: application/json' \
  -d '{"email":"frank@example.com"}' \
  http://localhost:8080/api/v1/teams/<teamId>/invitations
# -> {"id": "...", "code": "<invite code>", ...}

curl -X POST -H 'X-Dev-User: frank@example.com' -H 'Content-Type: application/json' \
  -d '{"code":"<invite code>"}' \
  http://localhost:8080/api/v1/invitations/accept

Configuration

Set these for production (%prod profile); see application.properties for the full list.

Variable Purpose Default
DB_URL JDBC URL jdbc:postgresql://localhost:5432/chorahost
DB_USERNAME / DB_PASSWORD Database credentials chorahost / chorahost
CHORAHOST_OIDC_CLIENT_ID Google OAuth client id the tokens are issued for (empty)
CHORAHOST_OIDC_CLIENT_SECRET Google OAuth client secret (empty)
CORS_ORIGINS Allowed browser origins http://localhost:4200
MAIL_USERNAME / MAIL_PASSWORD Brevo SMTP login and SMTP key, used to email invitations (empty)
MAIL_FROM Sender address, must be verified in Brevo noreply@chorahost.local

The schema is owned by Flyway (src/main/resources/db/migration) and applied at startup. Hibernate only validates it.

Testing

./mvnw test

Tests are @QuarkusTest integration tests against a real PostgreSQL started by Dev Services, so Docker must be running. Within a test class, methods run in a fixed order and share state, and the database is wiped once per class.

Packaging

./mvnw package                                   # target/quarkus-app/quarkus-run.jar
./mvnw package -Dquarkus.package.jar.type=uber-jar
./mvnw package -Dnative                          # native executable (needs GraalVM)
./mvnw package -Dnative -Dquarkus.native.container-build=true

Run the default build with java -jar target/quarkus-app/quarkus-run.jar. Dockerfiles for JVM and native images are in src/main/docker.

Project layout

src/main/java/pub/galactic/chorahost/
  resource/    JAX-RS endpoints
  service/     business logic (teams, invitations, cards, recurrence, gamification, shop)
  repository/  Panache repositories
  entity/      JPA entities
  dto/         request/response records
  security/    current-user resolution from the OIDC token
  dev/         dev-only data seeding and header auth

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages