Arclet Boards
A little clarity for everything ahead. Arclet is a private Kanban workspace for teams, built on the official Dodil Boards Challenge starter. One FastAPI app serves a responsive web interface, an authenticated JSON API, and one action-oriented MCP endpoint. All three use the same authorized use cases.
- Public source
- Ignite application
- MCP:
https://arclet-boards-akif-8080.ignite.dodil.cloud/mcp
See STATUS.md and evidence/ for actual test results, deployed user isolation checks, browser evidence, and the latest remix status.
What it does
- Multiple workspaces and private boards, with board-specific owner/member/viewer roles. Workspace membership alone never reveals private boards.
- Create and edit boards; create, rename, reorder and mark lists as completed.
- Create, edit and drag cards across lists or reorder them within a list. Card details provide a keyboard/touch move control as well.
- Descriptions, board-member assignment, due dates, colored labels, manual checklists, and a readable activity trail with actor, time and before/after data.
- Owner-only invitations, role changes and removal. Removing someone clears their assignments in the same transaction, with history.
- My tasks and automatic overdue views. Dates are UTC calendar dates; cards in completed lists are excluded from overdue results.
- Conflicting edits return 409. Every mutation takes an idempotency key, so an interrupted request can be retried without creating duplicate cards or history.
- Same-board prerequisites with cycle prevention, clear blocking chains, and safe completion/reopening rules.
- Reviewable checklist drafts from saved card descriptions, using Dodil Kimi.
- Daily briefs with real counts and activity; AI focus is restricted to existing card IDs and rendered using their actual titles.
- Similar-card search using Dodil Jina embeddings and DataK3
VECTOR(512)cosine KNN. Editors explicitly build/refresh search; stale embeddings are excluded.
An invitation grants application access by email; it does not send an email or provision an AppID account. Share the board link. The invited person signs up or signs in through the attached pool using that address. The first accepted invitation binds to their immutable AppID subject.
Remix into your organization
Use CLI 0.1.91 or later and an organization where you have git.admin:
dodil auth login --web
dodil git remix plan akif/arclet-boards --to-org <your-org> --name arclet-boards
dodil git remix akif/arclet-boards --to-org <your-org> --name arclet-boards
Review the plan. It creates one bucket, one pool, one service account, and the repository; the generated credentials go directly to the new repository's CI secrets. No API keys need to be copied. Models access is granted for optional Dodil-only AI. Ordinary board editing does not call inference. AI buttons and semantic-index refresh consume the target organization's existing Dodil model allowance/credits; no outside model key is needed and the app buys no credits.
Keep the chosen repository name at 18 characters or fewer. The bucket name
is ${repo}-data, with a 25-character limit and space for a fork suffix.
Bucket and pool conflicts fail intentionally; they must never silently suffix
away from the names in deploy.yaml.
After the remix — required before inviting a team
dodil ignite app get arclet-boards -o json
dodil appid settings get arclet-boards-users -o json
dodil appid settings set arclet-boards-users --require-email-verification=true
The verification setting is required because pending invitations are addressed by email. Do not admit unverified email signups to a pool used for invitations. Admin-created users are verified by default; ordinary signups must verify their address before login. Retain existing pool settings and callback entries.
Current Dodil Git automatically registers the app's sign-in callback during
deployment (verified on the starter remix). Check the deploy log. If registration
was not performed, add the callback using the actual host from public_urls:
dodil appid settings set arclet-boards-users --redirect-uris https://<actual-host>/.dodil/auth/callback
Never construct the host from the org name; Dodil escapes some characters.
If signup is disabled, provision the first people with
dodil appid user create arclet-boards-users you@example.com --roles member;
they set their password through the pool's recovery flow. Passwords and tokens
must not be pasted into this repository or terminal logs.
Open the app in a private browser window, sign in, create a workspace and board, then grant members access. Each new account starts without anyone else's boards.
Optionally apply the included hosted sign-in theme:
dodil appid branding set arclet-boards-users @appid-branding.json
Check the template and its target plan with:
dodil git remix check <org>/arclet-boards
dodil git remix plan <org>/arclet-boards --to-org <another-org>
An actual fresh-organization remix is only verified when STATUS.md records it.
MCP: connect as yourself
Add the app's /mcp URL as a custom connector in Claude or ChatGPT. RFC 9728
discovery points at this copy's AppID pool. Sign in as your own pool user and
complete consent. A newly registered OAuth client may need approval by the pool
administrator: inspect it before approving it.
dodil appid client list arclet-boards-users
dodil appid client get arclet-boards-users <client-id>
dodil appid client approve arclet-boards-users <client-id>
Tools include list_boards, get_board, create_board, create_list,
list_my_cards, list_overdue, add_card, update_card, move_card,
assign_card, set_due_date, get_card_activity, invite_member,
change_member_role, and manual checklist actions. Mutation tools require a
unique request_id; reuse it for retries of that exact command. Read fresh
versions before edits. There is no raw SQL/table tool and no identity argument.
Extras tools: suggest_checklist (draft only), apply_checklist, daily_summary,
refresh_semantic_index, find_similar_cards, add_dependency,
remove_dependency, and get_blocking_chain. Read fresh board/card versions
before applying a draft, adding a dependency, or refreshing the semantic index.
The application MCP is separate from the infrastructure MCP used to build it. Platform and AppID service-client tokens are refused as end-user identities.
Architecture and security
app/domain entities, input rules, versions, roles, overdue semantics
app/application shared validated commands and authorized use cases
app/infrastructure DataK3 transactions, gateway identity, Dodil Models adapter
app/web thin API adapter and same-origin HTML/CSS/JavaScript
app/mcp action tools derived from the same command contracts
tests transactional double for unit/door tests only
schema.sql explicit primary keys for every runtime table
.dodil provision and deploy manifests
.github/workflows Dodil Git CI, image build/push, then CD
DataK3 is the sole persistent application store. arclet_* tables intentionally
leave a pre-existing starter's tables untouched. A fresh remix creates only the
Arclet schema. Atomic multi-table writes combine content, ordering, activity and
idempotency. Guarded reads and per-record versions prevent lost updates. The
repository retries SQLSTATE conflicts as whole transactions and uses parameter
binding for every value. Six connections per replica keep two replicas below
DataK3's documented per-bucket concurrent-read ceiling.
Ignite strips incoming identity headers, verifies the AppID session or bearer,
and injects identity. Arclet requires X-Dodil-Auth-Source: pool, matching user
and token claims, the configured pool, an unexpired token, and human amr.
Permissions live in the application layer and apply equally through MCP.
Outsiders receive the same 404 as missing resources. The app has no DEV_USER
fallback. Do not expose uvicorn directly to the public internet outside Ignite's
trusted gateway.
Browser state is fetched from the backend; there is no localStorage database, runtime memory repository, demo seed, external identity provider, or outside AI key. Assets use a strict same-origin CSP. User content is escaped, and browser API writes reject cross-origin requests. Tokens stay out of page JavaScript.
Local development and tests (Windows)
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r app/requirements.txt pytest==9.2.0 PyYAML==6.0.3
.\.venv\Scripts\python.exe -m pytest -q tests
Run commands from the repository root. The app/mcp directory must not be
placed at the top of sys.path where it would shadow the installed MCP package.
Python 3.12 is the CI/container runtime; the local suite also runs on 3.14.
To run against your own DataK3 test bucket, supply BUCKET, PG_HOST, PG_PORT,
DODIL_SERVICE_ACCOUNT_ID, DODIL_SERVICE_ACCOUNT_SECRET and DODIL_USER_POOL
through your environment, then python -m uvicorn app.main:app --port 8080.
Take connection targets from dodil data connect <bucket> and do not log its
credential-bearing DSN. The app uses TLS verify-full with public CA roots.
Local uvicorn has no login bypass; authenticated integration tests belong behind
an Ignite AppID gateway. Unit-test identities do not prove live isolation.
Deployment
Before pushing CI/CD changes, run dodil git ci verify --repo arclet-boards.
Push main to Dodil Git. Its own CI runs tests, builds the numeric non-root image,
pushes into the org's registry, then deploys with .dodil/deploy.yaml once checks
are green. Registry credentials are injected by Dodil; do not mint replacements.
Runtime environment:
| Variable | Source |
|---|---|
BUCKET | ${dodil.repo}-data |
PG_HOST, PG_PORT | verified DataK3 endpoint |
DODIL_USER_POOL | ${dodil.org}/${dodil.repo}-users |
DODIL_SERVICE_ACCOUNT_ID, DODIL_SERVICE_ACCOUNT_SECRET | generated repo CI secrets, passed by reference |
MODELS_BASE, CHAT_MODEL | Dodil Models configuration retained from the starter |
GET /healthz checks the process only. A platform-authenticated POST / runs a
credential/schema self-check and returns counts, never row contents. Platform
principals still cannot invoke end-user API/MCP actions. Verify browser and MCP
flows with actual pool users as well as the self-check.
Current limits and next work
See STATUS.md and DESIGN_DECISIONS.md. AI and dependency extras were added after the core's 33 real-user API/MCP and 15 real-browser checks passed. Their real Models/DataK3 integration has separate evidence; STATUS.md distinguishes that from deployed extras checks. Semantic indexing is bounded at 100 cards per board and the first 4,000 description characters per embedding. Summary focus selection considers up to 100 unfinished candidates; counts still include the whole board. Model availability, credits and response latency can affect AI actions; errors are shown without inventing results. Polling/realtime push, attachments, comments, board deletion, ownership transfer and email delivery are outside the current core. Board sizes are bounded at 100 lists and 5,000 cards; checklist items are bounded at 100 per card. Large-team performance requires a measured follow-up.
MIT license. Original starter attribution is preserved in LICENSE and Git history.