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.
- Features
- Architecture
- Application Modules
- Technology Stack
- Complexity and Scale
- Quick Start with Docker
- Environment Configuration
- Native Development Setup
- Database Migrations
- Reproducing CI Locally
- Testing and Quality Checks
- Project Structure
- API and Service URLs
- Deployment Notes
- Repository history and provenance
- Additional Documentation
- 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
- 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
- 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
- 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, andVIEWER - 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
- 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
- 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
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
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 │
└──────────┘ └───────────────┘ └───────────────┘ └────────────┘
- The browser calls a relative
/api/...URL. - Next.js proxies that request to
BACKEND_URL; browser code never needs to contact an internal container hostname. - FastAPI validates the request body with Pydantic.
- Authentication dependencies decode the JWT, load the user, enforce the role, and resolve the active organization.
- Domain services execute tenant-scoped SQLAlchemy queries.
- PostgreSQL persists operational data; Redis provides caching and Celery transport.
- Long-running or scheduled work is processed by Celery outside the API request.
organization_idis 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.
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 | 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 |
| 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 |
- Docker multi-stage builds
- Docker Compose for local and production service topology
- GitHub Actions CI/CD
- Trivy filesystem security scanning
- Uvicorn ASGI server
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.
- 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.
- 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
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.
Docker is the recommended setup because it starts the complete service topology and runs migrations automatically.
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 setupmake setup runs the idempotent bootstrap script and chains these steps:
cp .env.example .env(skipped when.envalready exists)docker compose up -d postgres redis(the Compose database services)alembic upgrade headinside a one-shot backend containerdocker 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.
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 dataThe script is idempotent and safe to re-run. make help lists the other developer shortcuts (make verify, make test, make seed, make logs).
- Git
- Docker Engine 24+ with Docker Compose v2
- Approximately 4 GB of free memory for all services
git clone https://github.com/Inkithai/Oyster360.git
cd Oyster360cp .env.example .envGenerate a local JWT secret and place it in .env:
openssl rand -hex 32For basic farm-management development, the default AI_PROVIDER=rule-based works without an AI key, and all Stripe variables may remain empty.
Start the core web stack:
docker compose up --buildDocker Compose will:
- Start PostgreSQL and Redis.
- Build the backend image.
- Apply
alembic upgrade headbefore FastAPI starts. - Build and start the Next.js frontend.
Enable the optional background worker and scheduler profile when developing Celery tasks:
docker compose --profile workers up --buildTo run the core stack in the background:
docker compose up --build -d
docker compose ps
docker compose logs -f backend frontendOpen 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.
# Stop containers but retain PostgreSQL data
docker compose down
# Stop containers and delete local database/Redis volumes
docker compose down -vOyster360 does not require real AI or Stripe credentials for basic local cultivation workflows. Production deployments must replace every placeholder and use a secrets manager.
| 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 |
| 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 |
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- Create recurring Stripe prices for Starter, Pro, and Enterprise.
- Put their
price_...IDs and a Stripe test secret key in.env. - Forward Stripe CLI events to the backend:
stripe listen --forward-to localhost:8000/api/webhooks/stripe- Copy the CLI's
whsec_...value toSTRIPE_WEBHOOK_SECRETand restart the backend.
Client requests select a plan, but the backend resolves the actual Stripe price from these server-side variables.
Use this mode when developing the frontend or backend outside containers.
- 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
docker compose up -d postgres rediscp 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 8000In separate terminals, background processing can be started with:
cd backend
source .venv/bin/activate
celery -A app.core.celery:celery_app worker --loglevel=infocd backend
source .venv/bin/activate
celery -A app.core.celery:celery_app beat --loglevel=infocd frontend
npm ci
cat > .env.local <<'EOF'
NEXT_PUBLIC_API_URL=
BACKEND_URL=http://localhost:8000
EOF
npm run dev -- --hostname 0.0.0.0The frontend is now available at http://localhost:3000.
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 headThe 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.
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-localmake 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| 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 |
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_socketsfails any non-integrationtest that opens a socket to anything other than loopback.block_external_servicesreplaces everyrequestsHTTP 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.
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.iniThe 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.
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 buildcd frontend
npx playwright install chromium
npm run test:e2eEvery 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.
cd frontend
npm audit --audit-level=highOyster360/
├── 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
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.
- Use
docker-compose.prod.ymlas 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_URLempty when the frontend proxies to an internal backend service. - Set
BACKEND_URLto the backend's private service URL, such ashttp://backend:8000. - Configure Stripe to send signed events to
/api/webhooks/stripe. - Back up PostgreSQL and test restoration procedures before production use.
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.
- 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.mdandpyproject.toml; those claims have been removed.
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.
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-localThat 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.
- Setup Guide
- Architecture
- API Documentation
- Deployment Guide
- Product Overview
- User Guide
- Roadmap Status
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.tomlis 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.tomldeclares the identical set for the backend package.backend/requirements.lockis the fully resolved set (direct + transitive) that CI, the Docker images andmake ci-localinstall.- Frontend installs always use
npm ciagainst the committedpackage-lock.json.
scripts/check_dependency_sync.py (run by make deps-check, make ci-local, and the CI lockfiles job) asserts that:
- the root and backend
pyproject.tomldeclare the same runtime and dev dependencies; - every declared direct dependency appears in
backend/requirements.lockat the exact declared version; requirements-runtime.txtandrequirements-dev.txtagree withpyproject.toml;package-lock.jsonmatchespackage.jsonname, 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.
# 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 installReview the resulting dependency diff and security scan before committing. Dependabot checks npm and pip dependencies weekly via .github/dependabot.yml.
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.
All rights reserved.
Built for commercial oyster mushroom farms.