contest/orbit-boards

Orbit Boards, a private, remixable team task board built with FastAPI, DataK3, AppID, Models and MCP.

A remix template · 0 remixes · Remix contest/orbit-boards

README.md

Orbit Boards

Orbit Boards is a remixable team task board for moving work from To do to Doing to Done. The source repository is public; each organization's board data remains private to its own Dodil DataK3 bucket. The interface and product identity are original and do not use Trello branding.

What works

  • Create boards and invite board members as either member or viewer.
  • Owners can manage board membership. Members can add and edit work. Viewers can read boards but cannot change cards or membership.
  • Create cards with a title, description, assignee, due date and labels.
  • Drag cards between columns and reorder cards within a column. The updated order is stored in DataK3.
  • Search cards and filter by label, assignee or due date. Past-due, unfinished cards are marked and can be filtered. Cards without a due date are not overdue; completed cards are excluded from overdue results.
  • Review a board activity timeline. Card edits are attributed to the signed-in person and include the field and old/new values where applicable.
  • Use the same board operations through the web API and the application's /mcp endpoint.
  • Request a suggested checklist for an existing card using Dodil Models. Suggestions do not modify the card.

Roles and privacy

Each board has one owner. Memberships are scoped to a board. Every read and mutation resolves the board or card through the signed-in identity and checks access in the application layer. A board the caller cannot see is returned as not found, including when a caller guesses its ID. Viewer restrictions are checked by the shared use cases, not only by the interface. MCP actions use those same use cases and do not accept an actor identity as an argument.

The deployed app expects the Dodil gateway to authenticate people through the remixed AppID user pool and supply the trusted X-Dodil-User identity header. The gateway must strip caller-supplied copies of that header, as described by the starter. The DEV_USER identity shortcut is for local work only and is disabled when DODIL_USER_POOL is configured.

Architecture

The FastAPI application follows the official starter's light Domain-Driven Design structure:

  • app/boards/domain/model.py defines board roles, cards, lists and validation rules.
  • app/boards/application/use_cases.py owns board access, card operations, assignments, ordering, overdue queries, activity and membership behavior.
  • app/boards/application/ports.py defines the repository and assistant contracts.
  • app/boards/infrastructure/repository.py persists boards, memberships, cards and activity to DataK3 over its Postgres-compatible interface.
  • app/boards/infrastructure/dodil.py obtains a service-account token and connects to DataK3 and Dodil Models.
  • app/boards/doors/web.py serves the web API and UI. app/boards/doors/mcp.py exposes typed, action-oriented MCP tools. Both call the same Boards use cases.
  • app/boards/static/index.html contains the responsive browser interface.
  • schema.sql defines tables, constraints and indexes provisioned during a fresh remix.
  • migrations/001_starter_schema_alignment.sql adds the runtime columns required when upgrading a bucket created from the original challenge starter. It is idempotent and additive.
  • .dodil/remix.yaml, .dodil/deploy.yaml and .github/workflows/ci.yml retain the Dodil provisioning and CI deployment pattern.

A card mutation and its activity records are written in one database transaction. The activity actor comes from the gateway identity, not from client input. Lists are intentionally fixed to To do, Doing and Done to match the starter's supported domain.

/healthz is a lightweight liveness endpoint. /readyz opens the configured DataK3 bucket and checks the repository's required columns; Ignite uses /readyz so an app with a missing or unreachable data store is not reported as ready. Errors returned to callers are sanitized and include a short reference that can be matched to server logs.

MCP tools

The application exposes one MCP endpoint at https://<ignite-host>/mcp. Its tools are actions rather than direct table access:

list_boards, show_board, list_my_cards, list_overdue, create_board, add_card, update_card, move_card, assign_card, get_activity, add_member and suggest_checklist.

The gateway handles sign-in for the attached AppID pool. After deployment, add the app as a custom connector in Claude or ChatGPT using the /mcp URL. If client approval is required, use the documented Dodil commands:

dodil appid client list <repo>-users
dodil appid client approve <repo>-users <client-id>

Run and test locally

Python 3.12 is used by the container and CI workflow. From the repository root:

python3 -m venv .venv
. .venv/bin/activate
pip install -r app/requirements.txt pytest
cd app
python -m pytest -q ../tests

Tests use an in-memory repository and AI fakes and do not require a Dodil account. The web and MCP tests exercise shared rules, role boundaries, board isolation, board creation, sanitized dependency failures and readiness behavior.

To run the app locally against a DataK3 bucket, set BUCKET, DODIL_SERVICE_ACCOUNT_ID and DODIL_SERVICE_ACCOUNT_SECRET. Set DEV_USER=you@example.com only for local gateway-free development. The PG_HOST, MODELS_BASE and CHAT_MODEL defaults match the current starter configuration. From app/, run:

uvicorn boards.main:app --host 127.0.0.1 --port 8080

A DataK3 integration test needs valid credentials and writes to the selected bucket. Do not run it against production data without explicit authorization.

Remix and deploy on Dodil

Use a repository name of 18 characters or fewer so <repo>-data stays within the challenge's bucket-name limit. The repository should be public, use the MIT license and have the topics dodil-challenge and dodil-challenge-boards.

With the Dodil CLI authenticated to the organization that will own the entry, update the CLI and remix the official starter before pushing this implementation:

dodil update
dodil git remix dodil/boards-challenge --to-org <your-org> --name <your-repo> \
  --visibility public --topics dodil-challenge,dodil-challenge-boards

This implementation is deployed to contest/orbit-boards. Its generated service-account access, CI secrets and organization-scoped resources are attached to that remix. The repository is public and carries the required challenge topics.

The remix command sets the requested public visibility and topics after deployment succeeds, so a failed first deploy is not published. Validate a remix configuration with:

dodil git remix check <your-org>/<your-repo>

Push to main to invoke Dodil Git CI. The test job runs the Python suite; the build job builds the image, and Ignite deployment is gated on the ci/build check. .dodil/deploy.yaml configures the app to use its own bucket, user pool and generated service-account secrets.

Current Dodil Git automatically registers the deployed app's AppID callback URL in its pool. Check the deploy log. If it says the callback was not registered, run the command printed there once. If public signup is disabled, invite at least one user to the new pool. Run dodil guide remix and follow After the remix: let people sign in; never reuse a callback URL or service account from another organization.

Data model and schema upgrades

DataK3 is the authoritative store. The schema contains boards, memberships, cards and activity; identifiers are generated by the application. Fresh remixes use the foreign keys, role/list/position constraints and indexes in schema.sql. The shared application use cases also validate board/card relationships and membership permissions before every write. Labels are stored as JSON text so the repository can use the starter's Postgres wire adapter without introducing another database.

A code deployment does not rerun schema.sql against an existing bucket. For a bucket created from the original challenge starter, apply each statement in migrations/001_starter_schema_alignment.sql to <repo>-data using the authenticated CLI, for example:

dodil data pg --bucket <repo>-data "ALTER TABLE activity ADD COLUMN IF NOT EXISTS field TEXT"

Run the remaining statements from that file the same way. The statements are additive and can be re-run. The existing live contest/orbit-boards-data bucket has been aligned and its rows preserved.

The remix config provisions one <repo>-data bucket from schema.sql, one <repo>-users AppID pool, and a service account granted access to the bucket and Dodil Models. The deploy config passes generated credentials through CI secrets. No external database, sign-in provider or AI provider is used.

Known limits and verification

The board currently uses the starter's three fixed lists. There is no workspace hierarchy above boards, no member-removal interface and no notification delivery for new members. AI checklist generation is a suggestion only. CI covers the local application rules and web/MCP routes; live /readyz checks DataK3 connectivity and schema, while end-to-end sign-in and a real user's board creation still need verification through the authenticated AppID browser session.

License

MIT. See LICENSE.