Skip to content

iDaneSchilling/sample

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

Repository files navigation

Patient Management Sample Apps

This repository hosts six small, production-grade sample applications that all implement the same simple Patient Management tool. Each sample demonstrates vertical-slice architecture and testable code while using SQLite for persistence and a single OAuth provider for authentication.

Goals

  • Showcase identical business capabilities implemented across different stacks
  • Emphasize vertical slices (feature-first structure) and clear testing boundaries
  • Keep the domain intentionally small but realistic

Core User Stories (identical across all samples)

  • As a logged-in user, I can create patients
  • Patients have the following properties:
    • id: a 7-digit number starting with a non-zero digit (regex: ^[1-9][0-9]{6}$)
    • name: string, maximum 50 characters
  • A logged-in user can search for patients by id or name
  • A logged-in user may edit a patient’s name
  • A logged-in user may archive a patient
  • A logged-in user may toggle whether archived patients are included in search
  • The search should indicate if an archived patient matches the query, but must not return the archived patient in the list when the toggle is off
  • A logged-in user can add a note to a patient
  • A logged-in user can see who created a note and when
  • A logged-in user can edit and delete notes
  • Deleted notes cannot be restored
  • Notes have audit histories; history stores previous text
  • History cannot be edited, but is deleted with the note
  • A logged-in user can search a patient’s notes

Shared Technical Requirements

  • Database: SQLite for all samples
  • Authentication: Single OAuth provider across all samples
    • Recommended: Auth0 (broad language support, good quickstarts)
    • Alternatives: Okta, Azure AD B2C, or GitHub OAuth for simple dev/testing
    • Minimum claims: stable user identifier (e.g., sub) used to attribute created/updated-by fields
  • Validation:
    • Patient id must match ^[1-9][0-9]{6}$
    • Patient name required, <= 50 characters
    • Notes text required and non-empty
  • Archival behavior:
    • Archived patients are excluded by default
    • When excluded, the search should display a message like “1 archived match hidden” instead of listing the patient
    • When included, archived patients appear and are clearly marked

Domain Model (shared intent)

  • Patients
    • patient_id (TEXT or INTEGER), name (TEXT), archived (BOOLEAN/INTEGER), timestamps
  • Notes
    • note_id, patient_id (FK), text, created_by_user_id, created_at, updated_at, soft delete flag or hard delete per stack implementation
  • Note History
    • note_history_id, note_id (FK), previous_text, changed_at, changed_by_user_id

SQLite reference schema (illustrative; each stack may implement via its own migration tooling):

-- Patients
CREATE TABLE patients (
  patient_id TEXT PRIMARY KEY CHECK (patient_id GLOB '[1-9][0-9][0-9][0-9][0-9][0-9][0-9]'),
  name TEXT NOT NULL CHECK (length(name) <= 50),
  archived INTEGER NOT NULL DEFAULT 0,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_patients_name ON patients(name);

-- Notes
CREATE TABLE notes (
  note_id INTEGER PRIMARY KEY AUTOINCREMENT,
  patient_id TEXT NOT NULL REFERENCES patients(patient_id) ON DELETE CASCADE,
  text TEXT NOT NULL,
  created_by_user_id TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now')),
  deleted INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX idx_notes_patient ON notes(patient_id);
CREATE INDEX idx_notes_text ON notes(text);

-- Note History (append-only; removed when note is hard-deleted)
CREATE TABLE note_history (
  note_history_id INTEGER PRIMARY KEY AUTOINCREMENT,
  note_id INTEGER NOT NULL REFERENCES notes(note_id) ON DELETE CASCADE,
  previous_text TEXT NOT NULL,
  changed_at TEXT NOT NULL DEFAULT (datetime('now')),
  changed_by_user_id TEXT NOT NULL
);

Search Behavior (consistent UX)

  • Query by patient_id or partial name
  • Toggle: “Include archived” (default: off)
  • When toggle is off and matches exist only among archived patients, show a non-intrusive notice like: “N archived matches hidden”
  • Notes search is scoped to a specific patient

Vertical Slices and Testability

Each sample organizes code by feature (vertical slices) rather than layers:

  • Feature folders: patients, notes, auth
  • Each feature includes its own handlers/controllers, validation, data access, and tests
  • End-to-end tests cover critical flows: create/search/edit/archive patients; add/edit/delete notes; history behavior; archived toggle behavior

Planned Samples (folders in repo root)

  • .net + razor pagesdotnet-razor-pages/
  • .net api + vue.jsdotnet-api-vue/
  • .net + blazordotnet-blazor/
  • laravel + reactlaravel-react/
  • rust + angularrust-angular/
  • go + reactgo-react/

Each sample will provide:

  • Local run instructions (SQLite setup, environment variables for OAuth)
  • Seed script for demo data
  • Migrations (EF Core / Laravel migrations / sqlx/SeaORM/Diesel/etc.)
  • Unit, integration, and minimal E2E tests

Authentication Setup (recommended defaults)

  • Use Auth0 with a single tenant and one Application per sample
  • Configure callback/logout URLs per sample’s dev server
  • Map the provider sub claim to the app’s created_by_user_id

Contributing

  • Start by creating the folder for your chosen stack (see names above)
  • Implement the schema and stories exactly as specified to preserve comparability
  • Keep feature code vertically sliced; keep tests close to features
  • Use SQLite and the shared validation rules

License

This repository is licensed under the terms of the LICENSE file in the root.

About

My Sample Apps

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published