Skip to content

Latest commit

 

History

329 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Oyster360

AI-powered, multi-tenant farm management and intelligence for commercial oyster mushroom cultivation.

Oyster360 combines cultivation operations, environmental records, inventory, purchasing, harvest quality, analytics, AI assistance, subscription billing, and platform administration in one SaaS application. Each farm operates inside an isolated organization, and API authorization is enforced by both role and tenant.

Project status: Active development. Core workflows, tenant isolation, authentication, billing infrastructure, background jobs, dashboards, Docker deployment, and automated tests are implemented. See Roadmap Status for the current completion breakdown.

Table of Contents

Features

Farm and Cultivation Operations

  • Organization and farm onboarding during user registration
  • Multi-stage batch lifecycle: preparation, inoculation, colonization, fruiting, harvest, and completion
  • Room and grow-space management
  • Strain catalogue and cultivation metadata
  • Versioned substrate recipes and recipe performance data
  • Growth logs, health scores, images, and batch timelines
  • Environmental temperature, humidity, and CO2 records
  • Harvest recording, grading, quality scores, and revenue calculations

Inventory and Purchasing

  • Tenant-isolated inventory items and stock levels
  • IN, OUT, and ADJUSTMENT transactions
  • Low-stock detection and reorder thresholds
  • Tenant-isolated suppliers and purchase orders
  • Purchase order line items, totals, expected dates, and status tracking

AI and Analytics

  • Rule-based cultivation assistant that works without an external AI key
  • Optional external AI provider integration
  • Retrieval-augmented generation over user-owned knowledge documents
  • Image inspection and contamination findings
  • Yield prediction and expected harvest estimates
  • Farm dashboards for production, success rate, environment, strains, and recipes
  • SaaS analytics for growth, revenue, retention, usage, and AI activity

Authentication and Security

  • JWT access tokens and rotating refresh tokens
  • Refresh-token revocation on logout, password change, and password reset
  • Separate email-verification and password-reset token flows
  • Password hashing with Argon2
  • Multi-factor authentication service using TOTP and QR codes
  • Role-based access control: ADMIN, FARM_MANAGER, WORKER, and VIEWER
  • Organization-level query enforcement across tenant-owned resources
  • Rate limiting, request IDs, CORS configuration, and security headers
  • Audit-log and feature-flag models for platform administration

Billing and Platform Operations

  • Stripe customer and checkout session creation
  • Server-controlled Stripe price IDs, preventing client-side plan/price substitution
  • Verified Stripe webhooks with idempotent subscription synchronization
  • Subscription lifecycle states and cancellation-at-period-end support
  • Admin and SaaS analytics endpoints
  • GDPR data export and account-data deletion endpoints

Background Work and Deployment

  • Redis caching
  • Celery workers and Celery Beat scheduled jobs
  • Background email, AI-analysis, token-cleanup, and report tasks
  • Alembic database migrations
  • Multi-stage, non-root Docker images
  • Docker Compose services for frontend, API, PostgreSQL, Redis, migration, worker, and scheduler
  • GitHub Actions checks for backend, frontend, Docker, and security scanning

Architecture

Oyster360 is a modular monolith with independently deployable frontend and backend containers. Business domains are separated into API, service, schema, and persistence modules, while sharing one PostgreSQL database and one Redis deployment.

flowchart LR
    U[Browser / Farm User]
    S[Stripe]
    AI[External AI Provider]

    subgraph FE[Frontend Container]
        N[Next.js 16 App Router]
        Q[TanStack Query]
        UI[React 19 + Tailwind UI]
        N --- Q
        N --- UI
    end

    subgraph BE[Backend Container]
        F[FastAPI Routers]
        AUTH[Auth + RBAC + Tenant Enforcement]
        SV[Domain Services]
        RAG[AI / RAG / Analytics]
        ORM[SQLAlchemy Models]
        F --> AUTH
        AUTH --> SV
        SV --> RAG
        SV --> ORM
    end

    subgraph JOBS[Background Processing]
        CW[Celery Worker]
        CB[Celery Beat]
    end

    DB[(PostgreSQL / pgvector)]
    REDIS[(Redis Cache + Broker)]

    U -->|HTTPS| N
    N -->|same-origin /api proxy| F
    S -->|signed webhooks| F
    RAG -. optional API calls .-> AI
    ORM --> DB
    SV --> REDIS
    CB --> REDIS
    REDIS --> CW
    CW --> DB
Loading

Layered View

The same system as a request-path stack, for readers who want the layering rather than the container topology:

                      ┌───────────────────────────┐
                      │   Browser / Farm User     │
                      └─────────────┬─────────────┘
                                    │ HTTPS
                      ┌─────────────▼─────────────┐
                      │  Next.js 16 App Router    │
                      │  React 19 · TanStack      │
                      └─────────────┬─────────────┘
                                    │ same-origin /api proxy
                      ┌─────────────▼─────────────┐
                      │     FastAPI Routers       │
                      │  Pydantic request models  │
                      └─────────────┬─────────────┘
                                    │
                      ┌─────────────▼─────────────┐
                      │  Auth · RBAC · Tenancy    │
                      │  JWT + organization scope │
                      └─────────────┬─────────────┘
                                    │
                      ┌─────────────▼─────────────┐
                      │      Domain Services      │
                      │ batches · billing · AI ·  │
                      │ inventory · analytics     │
                      └─────────────┬─────────────┘
                                    │
                      ┌─────────────▼─────────────┐
                      │ Repositories / SQLAlchemy │
                      └─────────────┬─────────────┘
                                    │
                      ┌─────────────▼─────────────┐
                      │        PostgreSQL         │
                      └───────────────────────────┘

  External dependencies (all stubbed in the default test lane):

  ┌──────────┐  ┌───────────────┐  ┌───────────────┐  ┌────────────┐
  │  Stripe  │  │  AI providers │  │ Redis (cache  │  │  Celery    │
  │ billing  │  │ OpenAI/Gemini │  │ + broker)     │  │  workers   │
  └──────────┘  └───────────────┘  └───────────────┘  └────────────┘

Request Flow

  1. The browser calls a relative /api/... URL.
  2. Next.js proxies that request to BACKEND_URL; browser code never needs to contact an internal container hostname.
  3. FastAPI validates the request body with Pydantic.
  4. Authentication dependencies decode the JWT, load the user, enforce the role, and resolve the active organization.
  5. Domain services execute tenant-scoped SQLAlchemy queries.
  6. PostgreSQL persists operational data; Redis provides caching and Celery transport.
  7. Long-running or scheduled work is processed by Celery outside the API request.

Data and Security Boundaries

  • organization_id is the primary tenant boundary for farm-owned data.
  • Parent resources are verified before nested resources such as inspections, logs, grades, and AI operations are accessed.
  • The frontend role guard improves navigation and presentation, but the backend remains the authoritative security boundary.
  • Stripe webhook payloads are accepted only after signature verification.
  • RAG retrieval is restricted to documents owned by the authenticated user.

Application Modules

The backend currently contains 24 API router modules, 27 model modules, and 28 service modules. The frontend exposes 28 App Router pages.

Domain Main backend modules Main frontend areas Responsibility
Authentication api/auth.py, core/security.py, core/dependencies.py /login, /register, /forgot-password, /reset-password Accounts, JWTs, refresh rotation, password and verification flows
Organizations api/organizations.py, core/tenant.py, core/tenant_enforcer.py Organization-aware navigation Tenant membership, active organization, query isolation
Cultivation api/batches.py, api/rooms.py, api/strains.py, batch services /batches, /strains Batch lifecycle, rooms, strains, stage transitions
Recipes api/recipes.py, services/recipe_service.py /recipes Substrate recipes, versions, and performance
Farm records api/growth_logs.py, api/environment.py, api/harvests.py Growth, environment, and harvest forms Observations, sensor-style records, harvest completion
Quality api/inspections.py, api/harvest_grades.py /analysis, /grading Image inspections, findings, grades, quality control
Inventory api/inventory.py, services/inventory_service.py /inventory Stock, transactions, and low-stock reporting
Purchasing api/purchases.py, services/purchase_service.py /purchases Suppliers, orders, line items, and totals
AI and RAG api/ai.py, api/assistant.py, services/ai/, rag_service.py /ai, /assistant, /analysis Cultivation advice, document retrieval, image and yield analysis
Analytics api/analytics.py, api/saas_analytics.py /dashboard, /analytics, /admin/analytics Farm KPIs and SaaS business metrics
Billing api/billing.py, api/webhooks.py, Stripe and billing services /settings/subscription Checkout, subscriptions, webhook synchronization, cancellation
Administration api/admin.py, services/admin_service.py /admin/dashboard System statistics, users, organizations, flags, and audit logs
Compliance api/compliance.py, retention services API-driven GDPR export, deletion, and retention support
Background jobs core/celery.py, tasks/ Status endpoint Async analysis, email tasks, cleanup, and reports

Technology Stack

Frontend

Technology Use
Next.js 16 App Router, server rendering, production server, API proxy
React 19 + TypeScript UI and type-safe application code
Tailwind CSS 4 Styling and responsive layouts
Radix UI primitives Accessible dialog, label, and select behavior
TanStack Query Server-state fetching, caching, and mutations
React Hook Form + Zod Form state and client-side validation
Chart.js + react-chartjs-2 Analytics visualization
Zustand Lightweight client-state support
Vitest + Testing Library Component tests and coverage
Playwright Browser-level end-to-end tests
ESLint Static frontend checks

Backend

Technology Use
FastAPI HTTP API and dependency injection
Pydantic v2 Request, response, and settings validation
SQLAlchemy 2 ORM and query layer
Alembic Versioned database schema migrations
PostgreSQL 16 + pgvector Relational storage and future vector search
PyJWT Access-token creation and verification
Argon2 Password hashing
Stripe SDK Billing and webhook verification
Redis Cache, Celery broker, and result backend
Celery Background and scheduled task execution
PyOTP + QRCode TOTP multi-factor authentication
Pytest + pytest-cov Backend tests and coverage

Infrastructure

  • Docker multi-stage builds
  • Docker Compose for local and production service topology
  • GitHub Actions CI/CD
  • Trivy filesystem security scanning
  • Uvicorn ASGI server

Complexity and Scale

Oyster360 is medium-to-high complexity for a web application. It is more involved than a CRUD dashboard but intentionally less operationally complex than a distributed microservice system.

Why the complexity is higher

  • Every tenant-owned query must enforce organization boundaries.
  • Four roles require different authorization levels.
  • Authentication includes access tokens, refresh rotation, revocation, reset, verification, and MFA foundations.
  • Stripe state must remain synchronized despite duplicate or out-of-order webhook delivery.
  • Celery introduces asynchronous execution, retries, scheduling, and Redis dependencies.
  • AI features combine farm data, user documents, optional external providers, and deterministic fallbacks.
  • Production startup requires database migration ordering before API and worker startup.

Current size indicators

  • 24 FastAPI router modules
  • 27 SQLAlchemy model modules
  • 28 backend service modules
  • 28 frontend page routes
  • 22 backend/frontend unit-test files, plus Playwright specifications
  • Up to 7 Docker Compose service roles: frontend, backend, migration, PostgreSQL, Redis, Celery worker, and Celery Beat

Architectural trade-off

The modular-monolith design keeps transactions, development, and deployment understandable while preserving clear domain boundaries. If usage grows substantially, Celery workers, analytics, AI processing, and webhook ingestion are the most natural candidates to scale or extract independently.

Quick Start with Docker

Docker is the recommended setup because it starts the complete service topology and runs migrations automatically.

Fastest path: make setup

On a machine that has never seen this repository, one target copies the env file, starts the databases, applies migrations, and brings up the API and web app:

git clone https://github.com/Inkithai/Oyster360.git
cd Oyster360
make setup

make setup runs the idempotent bootstrap script and chains these steps:

  1. cp .env.example .env (skipped when .env already exists)
  2. docker compose up -d postgres redis (the Compose database services)
  3. alembic upgrade head inside a one-shot backend container
  4. docker compose up -d backend frontend

When startup succeeds the backend log contains:

Uvicorn running on 0.0.0.0:8000

Confirm with docker compose logs backend | grep -i uvicorn, then open http://localhost:3000 and http://localhost:8000/health. Stop the stack with make down.

make bootstrap (or ./scripts/bootstrap.sh) is the same idea plus an optional --seed flag and a health-check wait loop.

One-command bootstrap

From a fresh clone, scripts/bootstrap.sh (or make bootstrap) performs every setup step below in one shot: it creates .env from .env.example, generates a random JWT_SECRET when the placeholder is still in place, builds and starts the stack (which applies alembic upgrade head before the API boots), and waits for the API health check before printing the URLs.

./scripts/bootstrap.sh          # or: make bootstrap
./scripts/bootstrap.sh --seed   # additionally seed demo farm data

The script is idempotent and safe to re-run. make help lists the other developer shortcuts (make verify, make test, make seed, make logs).

Prerequisites

  • Git
  • Docker Engine 24+ with Docker Compose v2
  • Approximately 4 GB of free memory for all services

1. Clone the repository

git clone https://github.com/Inkithai/Oyster360.git
cd Oyster360

2. Create the environment file

cp .env.example .env

Generate a local JWT secret and place it in .env:

openssl rand -hex 32

For basic farm-management development, the default AI_PROVIDER=rule-based works without an AI key, and all Stripe variables may remain empty.

3. Build and start the application

Start the core web stack:

docker compose up --build

Docker Compose will:

  1. Start PostgreSQL and Redis.
  2. Build the backend image.
  3. Apply alembic upgrade head before FastAPI starts.
  4. Build and start the Next.js frontend.

Enable the optional background worker and scheduler profile when developing Celery tasks:

docker compose --profile workers up --build

To run the core stack in the background:

docker compose up --build -d
docker compose ps
docker compose logs -f backend frontend

4. Create the first account

Open http://localhost:3000/register. Registration creates:

  • a farm-manager user;
  • an organization owned by that user; and
  • the user's first farm.

Then sign in at http://localhost:3000/login.

5. Stop or reset the stack

# Stop containers but retain PostgreSQL data
docker compose down

# Stop containers and delete local database/Redis volumes
docker compose down -v

Environment Configuration

Oyster360 does not require real AI or Stripe credentials for basic local cultivation workflows. Production deployments must replace every placeholder and use a secrets manager.

Environment-file locations

Run mode File/location Notes
Docker Compose repository-root .env Compose loads this automatically
Native backend backend/.env Pydantic Settings loads it when the backend runs from backend/
Native frontend frontend/.env.local Next.js loads it for development
Production platform secrets or an external secrets manager Never commit .env.production or .env.local files, even with placeholder values; keep production configuration in your platform secrets manager

Variables

Variable Required Example Purpose
DB_USER Docker oyster360 PostgreSQL container user
DB_PASSWORD Docker oyster360_secure_pass PostgreSQL container password; replace outside local development
DB_NAME Docker oyster360 PostgreSQL database name
DATABASE_URL Backend postgresql://oyster360:...@localhost:5432/oyster360 SQLAlchemy/Alembic connection URL
JWT_SECRET Yes output of openssl rand -hex 32 JWT signing key; minimum 32 characters
JWT_ALGORITHM No HS256 JWT signing algorithm
ACCESS_TOKEN_EXPIRE_MINUTES No 10080 Access-token lifetime
CORS_ORIGINS Yes in production https://app.example.com Comma-separated browser origins allowed by FastAPI
REDIS_URL Yes redis://localhost:6379/0 Cache and Celery connection
AI_PROVIDER No rule-based rule-based, openai, or another implemented provider
OPENAI_API_KEY Only for OpenAI sk-... External AI access
STRIPE_SECRET_KEY Only for billing sk_test_... Stripe server SDK key
STRIPE_WEBHOOK_SECRET Only for billing whsec_... Stripe webhook signature secret
STRIPE_PRICE_STARTER Only for billing price_... Server-approved Starter recurring price
STRIPE_PRICE_PRO Only for billing price_... Server-approved Pro recurring price
STRIPE_PRICE_ENTERPRISE Only for billing price_... Server-approved Enterprise recurring price
NEXT_PUBLIC_API_URL No empty Empty uses the recommended same-origin /api proxy
BACKEND_URL Frontend server http://localhost:8000 Backend target used by the Next.js server

Minimal native backend .env

DATABASE_URL=postgresql://oyster360:oyster360_secure_pass@localhost:5432/oyster360
JWT_SECRET=replace-with-at-least-32-random-characters
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=10080
CORS_ORIGINS=http://localhost:3000
REDIS_URL=redis://localhost:6379/0
AI_PROVIDER=rule-based

Enabling Stripe locally

  1. Create recurring Stripe prices for Starter, Pro, and Enterprise.
  2. Put their price_... IDs and a Stripe test secret key in .env.
  3. Forward Stripe CLI events to the backend:
stripe listen --forward-to localhost:8000/api/webhooks/stripe
  1. Copy the CLI's whsec_... value to STRIPE_WEBHOOK_SECRET and restart the backend.

Client requests select a plan, but the backend resolves the actual Stripe price from these server-side variables.

Native Development Setup

Use this mode when developing the frontend or backend outside containers.

Prerequisites

  • Node.js 20.9+
  • npm 10+
  • Python 3.11+ (Python 3.12 is used by CI and Docker)
  • PostgreSQL 16 and Redis 7, or Docker for those dependencies

1. Start PostgreSQL and Redis

docker compose up -d postgres redis

2. Configure and run the backend

cp backend/.env.example backend/.env
cd backend

python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.lock

alembic upgrade head
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

In separate terminals, background processing can be started with:

cd backend
source .venv/bin/activate
celery -A app.core.celery:celery_app worker --loglevel=info
cd backend
source .venv/bin/activate
celery -A app.core.celery:celery_app beat --loglevel=info

3. Configure and run the frontend

cd frontend
npm ci

cat > .env.local <<'EOF'
NEXT_PUBLIC_API_URL=
BACKEND_URL=http://localhost:8000
EOF

npm run dev -- --hostname 0.0.0.0

The frontend is now available at http://localhost:3000.

Database Migrations

Alembic is the source of truth for production schema changes.

cd backend

# Apply all migrations
alembic upgrade head

# Show the current revision
alembic current

# Create a migration after changing SQLAlchemy models
alembic revision --autogenerate -m "describe the schema change"

# Review generated migration code before applying it
alembic upgrade head

The local backend container applies migrations before starting FastAPI. The production Compose topology uses a dedicated one-time migrate service before API and worker replicas start.

Reproducing CI Locally

Every gate GitHub Actions enforces can be reproduced on a fresh clone with a single command. It needs only Python 3.11+ and Node 20+ — no Docker, no PostgreSQL, no Redis, and no API keys.

git clone https://github.com/Inkithai/Oyster360.git
cd Oyster360
make ci-local

make ci-local runs scripts/ci-local.sh, which performs the following and exits non-zero on the first failure:

make ci-local
     │
     ├── 1. .env from .env.example (if missing)
     ├── 2. backend deps  -> .venv from backend/requirements.lock
     ├── 3. frontend deps -> npm ci from package-lock.json
     ├── 4. dependency sync check (manifests <-> lockfiles)
     ├── 5. backend lint      flake8
     ├── 6. backend typecheck mypy
     ├── 7. backend tests     pytest -m "not integration" + coverage >= 80%
     ├── 8. frontend lint     eslint
     ├── 9. frontend typecheck tsc --noEmit
     └── 10. frontend tests   vitest + coverage

Useful variants:

SKIP_INSTALL=1 make ci-local   # reuse an existing .venv / node_modules
make verify                    # same checks, assumes dependencies are installed
make deps-check                # dependency manifest/lockfile consistency only
make test-integration          # the Docker lane: PostgreSQL + Redis + full suite

What CI checks

Job Checks
lint flake8 (backend), eslint --max-warnings=0 (frontend)
typecheck mypy app (blocking, config in backend/mypy.ini), tsc --noEmit
test pytest with coverage gate, offline pytest -m "not integration" lane, vitest + coverage
lockfiles uv lock --check (root and backend), scripts/check_dependency_sync.py, npm ci --dry-run
security committed-.env guard, pip-audit, npm audit, Trivy filesystem scan
docker-integration Compose config validation, both image builds, full suite incl. integration tests
deploy builds and publishes images to GHCR on main and v* tags

Testing and Quality Checks

Test isolation guarantees

The default lane is completely self-contained. backend/tests/conftest.py installs two autouse fixtures that make this a property of the suite rather than a convention:

  • block_outbound_sockets fails any non-integration test that opens a socket to anything other than loopback.
  • block_external_services replaces every requests HTTP verb and every Stripe client call with in-process stubs.
pytest -m "not integration"
   │
   ├── PostgreSQL ──── in-memory SQLite, fresh schema per test
   ├── Redis ───────── in-process fake client
   ├── Stripe ──────── stubbed client + stubbed webhook signature verification
   ├── OpenAI/Gemini ─ stubbed; services fall back to rule-based output
   └── outbound TCP ── blocked, raises AssertionError

tests/test_offline_isolation.py asserts these guarantees directly, and the whole lane is verified to pass inside a network-disabled namespace (unshare -rn). Tests that genuinely need infrastructure are marked @pytest.mark.integration and run only in the Compose lane.

Backend

cd backend
pip install -r requirements.lock
pytest -m "not integration"                      # fast offline lane, no services needed
pytest --cov=app --cov-report=term-missing       # full suite with coverage (gate: 80%)
flake8 app tests --count --show-source --statistics --exclude=.venv,__pycache__,alembic/versions
mypy app                                         # config: backend/mypy.ini

The backend suite uses an isolated in-memory SQLite database for API, authentication, model-registry, integration, and tenant-security tests. pytest needs no running PostgreSQL, Redis, external account, or manually-created environment file: conftest.py blocks outbound HTTP, stubs every Stripe client call, and builds a fresh schema per test. The end-to-end lifecycle tests in tests/test_integration.py are marked integration, so pytest -m "not integration" gives a seconds-long feedback loop; CI runs that lane first and the compose stack still exercises the full suite.

Frontend

cd frontend
npm ci
npm run lint
npm run typecheck
npm test
npm run test:coverage    # Vitest with lines/statements/functions >= 70%, branches >= 60%
npm run build

Browser tests

cd frontend
npx playwright install chromium
npm run test:e2e

Every browser spec fulfills its API routes at the network level with page.route (login, dashboard analytics), so the Playwright suite runs against the Next.js development server without a live backend or seeded database.

Dependency security

cd frontend
npm audit --audit-level=high

Project Structure

Oyster360/
├── backend/
│   ├── alembic/                 # Migration environment and revisions
│   ├── app/
│   │   ├── api/                 # FastAPI route modules
│   │   ├── core/                # Settings, auth, tenancy, Celery, middleware
│   │   ├── database/            # Engine, sessions, optional seed helpers
│   │   ├── models/              # SQLAlchemy entities
│   │   ├── repositories/        # Tenant-aware repository helpers
│   │   ├── schemas/             # Pydantic request/response DTOs
│   │   ├── services/            # Domain, billing, AI, analytics logic
│   │   └── tasks/               # Celery tasks
│   ├── tests/                   # Pytest suite
│   ├── Dockerfile
│   ├── mypy.ini                 # Static type-checking policy (CI gate)
│   ├── pyproject.toml           # Backend PEP 621 manifest
│   ├── requirements-runtime.txt # Runtime-only container dependencies
│   ├── requirements-dev.txt     # Development/CI-only dependencies
│   └── requirements.lock        # Fully resolved install set (CI + Docker)
├── frontend/
│   ├── src/
│   │   ├── app/                 # Next.js pages and layouts
│   │   ├── components/          # Layout, guards, and reusable UI
│   │   └── lib/                 # API client, validation, utilities
│   ├── tests/e2e/               # Playwright specifications
│   ├── Dockerfile
│   ├── eslint.config.mjs
│   ├── playwright.config.ts
│   └── vitest.config.ts
├── docs/                        # Product, API, setup, architecture, deployment docs
├── scripts/                     # bootstrap.sh, ci-local.sh, check_dependency_sync.py, deploy, backup
├── Makefile                     # Developer shortcuts (make help)
├── docker-compose.yml           # Local complete stack
├── docker-compose.prod.yml      # Production-oriented stack
└── .env.example                 # Safe configuration template

API and Service URLs

After local startup:

Service URL
Web application http://localhost:3000
FastAPI root http://localhost:8000
Swagger UI http://localhost:8000/docs
OpenAPI JSON http://localhost:8000/openapi.json
Health http://localhost:8000/health
Readiness http://localhost:8000/ready
Liveness http://localhost:8000/live
Celery status http://localhost:8000/celery-status

Main API families are mounted under /api/auth, /api/batches, /api/recipes, /api/inventory, /api/purchases, /api/analytics, /api/assistant, /api/billing, /api/admin, and /api/compliance.

Deployment Notes

  • Use docker-compose.prod.yml as a reference, not as a substitute for environment-specific infrastructure review.
  • Store database, JWT, Stripe, email, AI, and cloud credentials in a secrets manager.
  • Terminate TLS at a trusted reverse proxy or managed load balancer.
  • Run the Alembic migration job once before rolling out new API/worker replicas.
  • Keep NEXT_PUBLIC_API_URL empty when the frontend proxies to an internal backend service.
  • Set BACKEND_URL to the backend's private service URL, such as http://backend:8000.
  • Configure Stripe to send signed events to /api/webhooks/stripe.
  • Back up PostgreSQL and test restoration procedures before production use.

Repository history and provenance

Summary: Oyster360 is the work of a single author. The Git commit history does not accurately reflect how or when the code was written, and should not be relied on as a development record.

This section exists so that anyone auditing, forking, or evaluating this repository has an accurate picture. The code is real and works; the history around it is not trustworthy, and pretending otherwise would be worse than saying so.

What is verifiable

  • The GitHub repository was created on 2026-07-07.
  • The commit graph contains four unrelated root (parentless) commits, which is not possible in a single continuous project history.
  • Two pairs of those roots have byte-identical file trees (identical Git tree hashes) but different authors and dates more than seven months apart.
  • The earliest root commit is authored "Priya Nair", dated 2025-01-14 — roughly eighteen months before the repository existed.
  • Another root commit is authored Your Name <youremail@example.com> with the message "copied from my gitlab", which is the most plausible account of where the codebase actually came from.
  • 98 commits dated before 2026-04-08 occur at only three distinct times of day (09:00, 12:00, 15:00), never on a weekend, with author and committer timestamps identical to the second and gaps of only 3–6 days.
  • Five commits share the exact same timestamp (2026-08-24 04:12:50) under five different author identities.
  • Twelve author identities in the history — Priya Nair, Marcus Lee, Sofia Ramirez, Daniel Cho, Elena Vasquez, James Wright, Aisha Rahman, Thomas Okonkwo, Maya Chen and variants — have no GitHub accounts and never contributed. They were previously listed in AUTHORS.md and pyproject.toml; those claims have been removed.

What this means

The genuine contributors are @Inkithai plus automated tooling (an AI coding agent, Dependabot, and GitHub Actions). Any metric derived from contributor count, commit cadence, or project age will be misleading for this repository.

The commit timestamps have deliberately not been rewritten. Rewriting them would replace one provenance problem with another and destroy the evidence above. The history is left as-is and documented instead.

What is trustworthy

The current state of the codebase stands on its own and can be verified directly rather than taken on trust:

git clone https://github.com/Inkithai/Oyster360.git
cd Oyster360
make ci-local

That runs lint, type checking, the full offline test suite with an enforced coverage gate, and dependency-consistency checks from a clean checkout. See Reproducing CI Locally.

Additional Documentation

Reproducible Dependencies

Each ecosystem has exactly one dependency story, and CI fails if any part of it drifts.

Python                                  Node
├── pyproject.toml            (root)    ├── frontend/package.json
├── backend/pyproject.toml              └── frontend/package-lock.json
├── backend/requirements-runtime.txt
├── backend/requirements-dev.txt
├── backend/requirements.lock  <- installed by CI, Docker and make ci-local
├── uv.lock                    (root)
└── backend/uv.lock
  • The root pyproject.toml is the canonical PEP 621 manifest, so scanners that only inspect the repository root see every direct runtime dependency pinned to an exact version.
  • backend/pyproject.toml declares the identical set for the backend package.
  • backend/requirements.lock is the fully resolved set (direct + transitive) that CI, the Docker images and make ci-local install.
  • Frontend installs always use npm ci against the committed package-lock.json.

Consistency enforcement

scripts/check_dependency_sync.py (run by make deps-check, make ci-local, and the CI lockfiles job) asserts that:

  1. the root and backend pyproject.toml declare the same runtime and dev dependencies;
  2. every declared direct dependency appears in backend/requirements.lock at the exact declared version;
  3. requirements-runtime.txt and requirements-dev.txt agree with pyproject.toml;
  4. package-lock.json matches package.json name, version and every declared range, with a resolved entry per package.

CI additionally runs uv lock --check on both uv.lock files, pip install --dry-run -r requirements.lock, and npm ci --dry-run.

Refreshing the locks

# Automatic: synchronize manifests across the repo and regenerate all lockfiles
make deps-sync
make deps-check

# Or manually:
# Python: after editing pyproject.toml dependency pins
uv pip compile pyproject.toml --extra dev --output-file backend/requirements.lock
uv lock && (cd backend && uv lock)
make deps-check

# Node
cd frontend && npm install

Review the resulting dependency diff and security scan before committing. Dependabot checks npm and pip dependencies weekly via .github/dependabot.yml.

Contributing

See CONTRIBUTING.md for setup, test gates, commit conventions, and the pull-request checklist. User-visible changes are recorded in CHANGELOG.md. Keep each feature or fix in a focused Conventional Commit together with the tests that prove it.

License

All rights reserved.


Built for commercial oyster mushroom farms.

About

Oyster360 combines cultivation operations, environmental records, inventory, purchasing, harvest quality, analytics, AI assistance, subscription billing, and platform administration in one SaaS application. Each farm operates inside an isolated organization, and API authorization is enforced by both role and tenant.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages