Chris TonjesandClaude Opus 4.7 913c69cc5e Phase 0 milestone 0.4: RBAC seed with 8 roles + permissions matrix
Data-driven RBAC. The matrix is the source of truth for who can do what;
runtime looks it up via security.rbac.can() (already in place from 0.2).
Refinements land as seed updates, not code changes.

Roles seeded (src/ypms/seed/roles.py):

- DOES_SYSTEM_ADMIN         Super-role. Bypasses via ADMIN_ROLE.
- OYP_STAFF                 General OYP program staff.
- ELIGIBILITY_EXAMINER      Certified eligibility staff — only non-admin
                            role with access to CFSA foster/ward and
                            OSSE FERPA records.
- PAYROLL_ADMIN             Approves payroll batches; banking access.
- REPORTING_ANALYST         Read-only across non-sensitive entities.
- HOST_USER                 External portal: host/employer.
- PARENT_USER               External portal: parent/guardian of under-18.
- YOUTH_USER                External portal: registrant.

Matrix (src/ypms/seed/permissions_matrix.json):

- Role-first grants map (nested role → entity → actions[]) rather than
  OWC's action-vs-entity cell matrix. Reason in permissions.py header:
  YPMS's 8 roles have very different scopes.
- 30 entities from ARCH §6.1 declared; 8 canonical actions.
- DOES_SYSTEM_ADMIN deliberately absent from grants — bypasses via the
  super-role.
- Row-level scoping ("HOST_USER edits only THEIR host") is service-layer,
  not RBAC-layer; Phase 0 is action×entity only, per ARCHITECTURE.md §4.2.

Loader (src/ypms/seed/permissions.py):

- Validates every referenced role / entity / action against the top-level
  declared sets — misspelled cells surface at seed time, not later.
- Idempotent: existing (role_id, entity, action) rows are skipped.
- Removals aren't propagated automatically — that's a Phase 8+ admin-UI
  responsibility per header note.

Runner (src/ypms/seed/run.py):

- `python -m ypms.seed.run` — idempotent runner. Seeds:
    1. Roles from ROLES (updates description drift)
    2. Bootstrap admin `chris` with DOES_SYSTEM_ADMIN role
       (password from SEED_ADMIN_PASSWORD env, default
       change-me-immediately)
    3. Permissions matrix
- docker-compose command now chains this after `alembic upgrade head`
  so a fresh container is usable.

Tests (53 passing, 92.20% coverage — up from 43 / 93.47%):

- tests/seed/test_seed.py    10 tests covering:
    * seed_roles idempotency + description-drift update
    * seed_bootstrap_admin creates + is idempotent
    * seed_permissions inserts + is idempotent
    * matrix declared actions/entities are self-consistent
    * matrix grants don't reference unseeded roles
    * ADMIN_ROLE NOT in grants (must bypass, not have rows)
    * unknown role in matrix raises at seed time
    * end-to-end can() decisions per role (~25 assertions):
      - OYP_STAFF sees registrants but not FERPA/CFSA/PayrollBatch
      - ELIGIBILITY_EXAMINER sees FERPA/CFSA but not banking
      - PAYROLL_ADMIN handles PayrollBatch but not FERPA/CFSA
      - REPORTING_ANALYST is strictly read-only
      - HOST_USER / PARENT_USER / YOUTH_USER can't touch admin surfaces
      - DOES_SYSTEM_ADMIN bypasses even sensitive entities

Advances YPMS-POAM-040. Unblocks milestone 0.5 (Registrant vertical slice)
and 0.6 (501-stub routers for the other entities in ARCH §6.1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-09-30 19:12:25 -04:00

YPMS — Youth Program Management System

DC Department of Employment Services / Office of Youth Programs — in-house build replacing seven legacy tools (MBSYEP intake, TMS timekeeping, PF3 admin, manual payroll scripts, MicroStrategy, and two supporting apps) with a single Python / FastAPI / Postgres system on Azure Government.

Status: Pre-development. Phase 0 (foundations) in flight. System owner + ISSO + AO: Chris Tonjes, DOES CIO. Full context: OVERVIEW.md, ARCHITECTURE.md, PHASE0_PLAN.md.

Quickstart (local)

Requires Docker Desktop (or equivalent). Ports 8000 (app), 5433 (Postgres), 8081 (Adminer) must be free.

cp .env.example .env
docker compose up --build

App at http://localhost:8000. OpenAPI docs at http://localhost:8000/docs.

curl http://localhost:8000/healthz    # → {"status":"ok"}
curl http://localhost:8000/readyz     # → {"status":"ok"} once db is up

Adminer (DB explorer) at http://localhost:8081. Connect with:

  • System: PostgreSQL
  • Server: db
  • Username / Password / Database: ypms / ypms / ypms

Stop with Ctrl+C; wipe local DB with docker compose down -v.

Tests

Local (no Docker required for the tests):

python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
pytest

Coverage:

pytest --cov=src/ypms --cov-report=term-missing

Tests use SQLite in-memory for speed. Postgres-specific behaviour gets its own Postgres-only fixture when a migration or query needs it (see ARCHITECTURE.md §4.8).

Repo shape

Full tree in ARCHITECTURE.md §5.1. High points:

  • src/ypms/main.py — FastAPI factory
  • src/ypms/settings.py — pydantic-settings config
  • src/ypms/db.py — SQLAlchemy engine, session, Base
  • src/ypms/logging.py — structlog + sensitive-field sanitizer
  • src/ypms/middleware.py — request id
  • src/ypms/framework/ — vendored from OWC, milestone 0.2
  • src/ypms/security/ — auth + RBAC + column encryption, milestones 0.3–0.4
  • src/ypms/youth/ — Registrant entity (vertical slice), milestone 0.5
  • Other entity packages — 501 stubs, milestone 0.6
  • migrations/ — Alembic, immutable-once-merged
  • tests/ — pytest, SQLite by default

Adding an entity

Once the framework lands in milestone 0.2, adding a new entity follows the OWC add-entity pattern (model → schemas → router → main.py registration → migration → permissions seed entry → test → coverage doc). Full instructions land here at milestone 0.2 completion.

Contributing

See CONTRIBUTING.md for the hard rules. Highlights: migrations are immutable once merged, every state-mutating route emits an audit row, framework/security modules must not carry domain logic, no --no-verify or # type: ignore without a written reason.

Compliance

License / usage

Internal DOES system. Not for external distribution.

S
Description
ypms build
Readme
497 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 99.3%
Dockerfile 0.4%
Mako 0.3%