Skip to content

Latest commit

 

History

383 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Internal Operations Platform

A full-stack internal operations system for a software consulting business, built to demonstrate production-oriented engineering decisions across authentication, authorization, lifecycle management, persistence, reporting, auditability, and automated testing.

V1 is feature-complete and is currently undergoing final release validation and demo preparation. The application runs locally; this repository does not claim a cloud deployment or production hosting environment.

Application Demo

Why This Project Exists

Internal tools often begin as simple CRUD applications, but the difficult engineering work appears when business rules start interacting:

  • users should see different data based on both role and ownership;
  • deactivated clients must stop accepting new work without erasing history;
  • completed and archived projects need explicit, auditable transitions;
  • deleted operational records must disappear from normal workflows while historical reporting remains meaningful;
  • browser controls should reflect permissions, but the server must remain the authorization boundary.

The Internal Operations Platform explores those concerns in a maintainable, explainable codebase. It is also an engineering mentorship simulation, so the implementation favors explicit domain behavior, layered responsibilities, and focused tests over unnecessary abstraction.

Product Capabilities

The V1 browser application and REST API support:

  • user administration, profile updates, role assignment, and soft deletion;
  • client creation, editing, deactivation, reactivation, and soft deletion;
  • project creation, editing, completion, archival, restoration, and soft deletion;
  • personal and administrator-managed time entries in quarter-hour increments;
  • personal-hours reports for every role;
  • organization-wide project, client, and user hours reports for administrators;
  • immutable audit events for significant create, update, lifecycle, role, and delete operations;
  • project status history with the actor and timestamp for each transition.

These workflows are intentionally connected. For example, an inactive client remains available to historical reads but cannot accept a new project or new/changed time entry.

Projects Dashboard

Architecture

flowchart LR
    Browser["React + TypeScript SPA"]
    API["Spring Boot REST API"]
    Security["Spring Security<br/>session + CSRF"]
    Service["Application services<br/>authorization + domain rules"]
    Data["Spring Data JPA"]
    DB[("PostgreSQL")]
    Flyway["Flyway migrations"]

    Browser -->|"JSON over /api<br/>session cookie"| API
    API --> Security
    Security --> Service
    Service --> Data
    Data --> DB
    Flyway --> DB
Loading

Frontend

The React single-page application uses route-level authentication, role-aware navigation, typed API modules, and a shared client that handles cookies and CSRF tokens. UI permissions improve usability by hiding inaccessible controls; they are never treated as a security boundary.

Vite serves the local frontend on http://localhost:5173 and proxies /api requests to the backend on port 8080.

Backend

The backend preserves a conventional dependency direction:

Controller → Service → Repository → PostgreSQL
  • Controllers own HTTP mapping and DTO conversion.
  • Services own authorization, application behavior, and lifecycle rules.
  • Repositories own persistence queries and soft-delete visibility.
  • Entities are not returned directly over HTTP.

Request and response DTOs keep the public contract separate from persistence state, particularly password hashes and internal relationships. Validation, application exceptions, and Spring Security failures use consistent JSON Problem Details without exposing stack traces.

Database

PostgreSQL is the system of record. Flyway applies versioned SQL migrations, while Hibernate runs with ddl-auto: validate; the application verifies the schema instead of silently generating or changing it.

Soft deletion preserves relational history. Normal operational queries exclude deleted records, while administrator project and client reports can still aggregate retained, non-deleted historical time entries for a deleted subject.

Engineering Highlights

Trusted Session Authentication

Authentication uses local email/password credentials, adaptive password hashing through Spring Security, server-managed HTTP sessions, and CSRF protection for state-changing requests.

The server derives identity from the authenticated principal rather than accepting an acting-user identifier from the client. This prevents callers from selecting another identity in a request and keeps authorization decisions tied to verified credentials.

The following endpoints are intentionally public:

  • POST /api/auth/login
  • GET /api/auth/csrf
  • GET /actuator/health

All business endpoints require authentication. Only the Actuator health endpoint is exposed for operational checks.

Authorization at the Service Boundary

The application defines USER, MANAGER, and ADMIN roles. V1 deliberately keeps USER and MANAGER permissions equivalent for most workflows; manager assignment, approvals, and delegated ownership are post-V1 concerns.

Capability USER / MANAGER ADMIN
Users View the active directory, view/update own profile Create, view, update, assign roles, and soft-delete other users
Clients View active clients Manage all non-deleted clients and lifecycle actions
Projects View active projects and their status history Manage all non-deleted projects and lifecycle actions
Time entries Create, view, and update own entries View and manage any non-deleted entry
Reports View own hours View own hours and organization-wide reports
Audit history No centralized access View audit history

Administrative safeguards prevent self-demotion, self-deletion, and removal or demotion of the final active administrator. The complete rules are documented in the authorization matrix.

User Management

Explicit Lifecycle Rules

Lifecycle changes are modeled as business operations rather than arbitrary status edits:

  • Clients move between ACTIVE and INACTIVE; deletion is soft.
  • Projects can move from ACTIVE to COMPLETED or ARCHIVED.
  • Completed projects may be archived.
  • Archived projects may be restored to ACTIVE.
  • Completed projects do not have a direct reactivation transition.
  • Time entries can be added or changed only while their project and client are active.
  • Explicitly deleted time entries are excluded from report totals.

Project status history answers what changed and when. Audit events answer who performed the operation. Keeping these concepts separate makes lifecycle presentation useful without weakening the broader audit trail.

Project Status History

Historical Reporting

Reports aggregate hours by project, client, or user. Regular users and managers can view only their own hours; administrators can access organization-wide report routes.

Historical reporting is designed around retained business activity:

  • soft-deleted projects and clients disappear from ordinary operational lists;
  • administrator reports for those project or client identifiers remain available;
  • retained time entries continue contributing to those reports;
  • explicitly deleted time entries do not contribute.

Reporting

Observable, Narrow Operational Surface

Spring Boot Actuator exposes only GET /actuator/health, which is accessible without authentication. Docker Compose also uses pg_isready to report PostgreSQL health. Metrics, dashboards, cloud probes, and deployment-specific monitoring are intentionally outside V1.

Technology Stack

Area Technology
Frontend React 19, TypeScript, React Router, Vite
Frontend testing Vitest, React Testing Library, MSW, Playwright
Backend Java 21, Spring Boot 4, Maven
Security Spring Security, server-managed sessions, CSRF
Persistence PostgreSQL 17, Spring Data JPA, Flyway
API documentation Springdoc OpenAPI and Swagger UI
Backend testing JUnit 5, AssertJ, MockMvc, Testcontainers
Local infrastructure Docker Compose
CI GitHub Actions, Temurin Java 21, Node.js 22

Testing Strategy

Tests are placed at the narrowest useful boundary while retaining real PostgreSQL and HTTP confidence where those integrations matter.

Layer Purpose
Backend unit Entity invariants, service permissions, lifecycle branches, reporting orchestration, and security configuration
Repository integration JPA mappings, PostgreSQL queries, constraints, and soft-delete behavior
Service integration Transactional behavior and relationship rules that benefit from real persistence
Controller integration Sessions, CSRF, validation, authorization, JSON contracts, persistence, reporting, and error responses through MockMvc
Frontend component User-visible rendering and interaction with React Testing Library and MSW at the HTTP boundary
Browser E2E Representative workflows through the real frontend and backend with Playwright

The latest verified backend run passed 356 tests. The frontend component suite contains 307 tests across 30 files. Playwright defines 8 tests across 6 specifications for login, users, clients, projects, time entries, and reports.

GitHub Actions runs:

  • the Maven suite on Java 21;
  • frontend lint, all component tests, and a production build on Node.js 22.

Playwright is currently a locally orchestrated release check because CI does not provision its backend, PostgreSQL, credentials, and test data.

See the complete testing strategy.

Local Setup

Prerequisites

  • Java 21
  • Docker with Docker Compose
  • Node.js 22 and npm

1. Start PostgreSQL

From the repository root:

docker compose up -d
docker compose ps

Docker Compose starts PostgreSQL 17 on localhost:5432, persists data in a named volume, and waits on a pg_isready health check.

2. Start the Backend

cd backend
./mvnw spring-boot:run

Flyway applies the schema migrations at startup. The backend is available at:

  • API: http://localhost:8080/api
  • Authenticated Swagger UI: http://localhost:8080/swagger-ui.html
  • Authenticated OpenAPI JSON: http://localhost:8080/v3/api-docs
  • Health: http://localhost:8080/actuator/health

3. Start the Frontend

In a separate terminal:

cd frontend
npm ci
npm run dev

Open http://localhost:5173.

4. Run Verification

Backend tests require Docker because they start PostgreSQL with Testcontainers:

cd backend
./mvnw test

Run the frontend CI-equivalent checks:

cd frontend
npm run lint
npm run test:run
npm run build

For the locally orchestrated browser suite, start PostgreSQL and the backend first, provide valid administrator credentials, and ensure an active client exists:

cd frontend
npx playwright install chromium
E2E_ADMIN_EMAIL=admin@iop.local \
E2E_ADMIN_PASSWORD="<local-demo-password>" \
npm run test:e2e

Environment Variables

The backend reads datasource settings from environment variables and supplies explicit local-development defaults:

Variable Local default Purpose
DB_URL jdbc:postgresql://localhost:5432/iop JDBC connection URL
DB_USERNAME postgres Database username
DB_PASSWORD postgres Database password

Environment values take precedence over these defaults. The defaults align with docker-compose.yml and are not production credentials.

Playwright also accepts:

Variable Purpose
E2E_ADMIN_EMAIL Administrator email used by business workflow tests
E2E_ADMIN_PASSWORD Password for that administrator

No secrets file or cloud-specific configuration is included.

Reset Demo Data

With the PostgreSQL container running, reset the local database to the canonical demo dataset from the repository root:

backend/scripts/reset-demo-data.sh

The script requires typing RESET before it proceeds. For a non-interactive local reset:

backend/scripts/reset-demo-data.sh --yes

This is a destructive local/demo-only operation. It replaces all application data, preserves the Flyway migration history and the bootstrap administrator admin@iop.local, and gives every seeded @iop-demo.local user the demo password fake-password.

Demo Workflow

Flyway seeds admin@iop.local with the local demo password fake-password as a bootstrap administrator. The seed exists only for development and demonstrations, is not suitable for production operation, and is not automatically retired in new databases.

A representative demo:

  1. Sign in with admin@iop.local / fake-password.
  2. Create a replacement administrator with a new password.
  3. Use the replacement account for normal administration.
  4. Create an active client.
  5. Create a project for that client.
  6. Create a regular user and record time against the active project.
  7. Review the user, project, and client hours reports.
  8. Complete, archive, and restore the project while reviewing status and audit history.
  9. Deactivate the client and observe that new work is blocked while historical information remains available.

Any real deployment procedure must verify the replacement administrator and then explicitly disable or remove the bootstrap account.

Example Demo Dataset

Client Projects

Repository Structure

.
├── backend/
│   ├── http/                  # Manual API request examples
│   ├── scripts/               # Local password-hash helper
│   └── src/
│       ├── main/
│       │   ├── java/          # Controllers, services, repositories, entities, DTOs
│       │   └── resources/     # Application configuration and Flyway migrations
│       └── test/              # Unit and PostgreSQL-backed integration tests
├── frontend/
│   ├── e2e/                   # Playwright browser workflows
│   └── src/
│       ├── api/               # Typed API modules and shared client
│       ├── auth/              # Session state, protected routes, UI permissions
│       ├── components/        # Reusable business and request-state components
│       ├── pages/             # Route-level workflows
│       └── test/              # MSW and component-test support
├── docs/
│   ├── architecture/          # Backend and domain architecture
│   ├── database/              # Schema and persistence design
│   ├── decisions/             # Architecture decision records
│   └── sprints/               # Preserved historical planning records
├── .github/workflows/         # Backend and frontend CI
└── docker-compose.yml         # Local PostgreSQL

Architecture Decisions

The ADRs capture why foundational choices were made and which alternatives were rejected:

  1. Use Spring Boot
  2. Use PostgreSQL
  3. Use Flyway
  4. Use Docker Compose for local PostgreSQL
  5. Backend testing strategy
  6. Continuous integration strategy
  7. API documentation strategy
  8. Session-based authentication with Spring Security
  9. Frontend architecture

For current behavior, see the requirements, project state, and release checklist. Historical sprint and log documents provide context but do not override the implementation or current living documentation.

Known Limitations

  • There is no cloud deployment, production hosting target, or automated deployment pipeline.
  • Playwright business workflows require a separately running backend, PostgreSQL database, valid credentials, and suitable test data; they are not run in CI.
  • The bootstrap administrator is seeded into every newly migrated database and requires a manual handoff and retirement procedure.
  • Local datasource credentials are development defaults, not a production secret-management design.
  • Backup, rollback, migration-recovery, HTTPS/reverse-proxy, and production session-topology procedures are not defined without a deployment target.
  • MANAGER is a reserved role with no assignment, approval, or delegated-ownership workflow in V1.
  • Completed projects cannot be directly reactivated; only archived projects can be restored to ACTIVE.
  • Soft-deleted entities do not have a general restoration workflow or deleted-record browser.

Future Roadmap

Post-V1 work is intentionally separated from the completed release scope. Candidate directions include:

  • manager-owned clients, project assignments, approvals, and delegated workflows;
  • billing rates, invoice preparation, and richer utilization reporting;
  • deployment-target selection, automated environment provisioning, and CI-driven browser tests;
  • production logging, metrics, alerting, backup, rollback, and migration-recovery procedures;
  • production-specific session, proxy, HTTPS, and secret-management design.

These are ideas, not claims of current functionality. See the roadmap for the broader staged product direction.

Acknowledgements

This project is built on the Spring, React, PostgreSQL, Flyway, Testcontainers, Vitest, Testing Library, MSW, and Playwright ecosystems.

It was developed as both a portfolio application and an engineering mentorship exercise, with an emphasis on making architectural reasoning, tradeoffs, and verification visible to reviewers.

About

Full-stack internal operations platform demonstrating authentication, lifecycle management, auditability, historical reporting, and production-oriented engineering practices.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages