diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..4c70c88 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,31 @@ +name: Bug report +description: Something is broken +labels: [bug] +body: + - type: input + id: repository + attributes: + label: Repository + placeholder: Ownima/owner-api + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened + description: Observed behavior and what you expected instead + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + validations: + required: true + - type: textarea + id: context + attributes: + label: Environment and context + description: Version, environment, logs, screenshots + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..481f54d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Security report + url: https://github.com/Ownima/.github/security/advisories/new + about: Report a vulnerability privately + - name: Support + url: https://github.com/Ownima/.github/blob/main/SUPPORT.md + about: Where to ask for help diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000..4b0a2e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,24 @@ +name: Feature request +description: Propose a capability +labels: [enhancement] +body: + - type: textarea + id: problem + attributes: + label: Problem + description: What user problem does this solve? + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposal + description: What should change? + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + validations: + required: false diff --git a/.github/workflows/profile-links.yml b/.github/workflows/profile-links.yml new file mode 100644 index 0000000..2e74c45 --- /dev/null +++ b/.github/workflows/profile-links.yml @@ -0,0 +1,55 @@ +name: profile-links + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "0 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: profile-links-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Detect app credentials + id: creds + env: + APP_ID: ${{ secrets.OWNIMA_BOT_APP_ID }} + APP_KEY: ${{ secrets.OWNIMA_BOT_PRIVATE_KEY }} + run: | + if [ -n "$APP_ID" ] && [ -n "$APP_KEY" ]; then + echo "mode=app" >> "$GITHUB_OUTPUT" + else + echo "mode=soft" >> "$GITHUB_OUTPUT" + fi + + - name: Create app token + id: app + if: steps.creds.outputs.mode == 'app' + uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 + with: + app-id: ${{ secrets.OWNIMA_BOT_APP_ID }} + private-key: ${{ secrets.OWNIMA_BOT_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + + - name: Check profile links + env: + GH_TOKEN: ${{ steps.app.outputs.token || github.token }} + run: | + if [ "${{ steps.creds.outputs.mode }}" = "app" ]; then + scripts/check-profile-links.sh --strict + else + echo "App credentials missing; private repository links are a warning" + scripts/check-profile-links.sh + fi diff --git a/.gitignore b/.gitignore index b7faf40..3bd5576 100644 --- a/.gitignore +++ b/.gitignore @@ -1,207 +1,5 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[codz] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py.cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock -#poetry.toml - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. -# https://pdm-project.org/en/latest/usage/project/#working-with-version-control -#pdm.lock -#pdm.toml -.pdm-python -.pdm-build/ - -# pixi -# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. -#pixi.lock -# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one -# in the .venv directory. It is recommended not to include this directory in version control. -.pixi - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.envrc -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# Abstra -# Abstra is an AI-powered process automation framework. -# Ignore directories containing user credentials, local state, and settings. -# Learn more at https://abstra.io/docs -.abstra/ - -# Visual Studio Code -# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore -# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore -# and can be added to the global gitignore or merged into this file. However, if you prefer, -# you could uncomment the following to ignore the entire vscode folder -# .vscode/ - -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc - -# Cursor -# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to -# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data -# refer to https://docs.cursor.com/context/ignore-files -.cursorignore -.cursorindexingignore - -# Marimo -marimo/_static/ -marimo/_lsp/ -__marimo__/ +.DS_Store +Thumbs.db +*.swp +.idea/ +.vscode/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f3b57a0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,83 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at contact@ownima.com. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..06e1bd2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Contributing + +## Branches + +Use `/-`, for example `fix/1219-time-slot-parse`. The default +branch is `main` in every repository. + +## Commits + +Conventional Commits: `type(scope): subject`. Types in use: `feat`, `fix`, +`refactor`, `chore`, `ci`, `test`, `docs`, `perf`, `style`, `build`, `revert`. + +## Pull requests + +- Keep a PR to one change. +- Link the issue when one exists. +- Make CI green before asking for review: tests, lint, typecheck and build for + the repository you touched. +- A backend request from a frontend repository is an issue on + `Ownima/owner-api`, not a task file in the frontend repository. +- Cross-repository references are full URLs. + +## Types and schemas + +Frontends generate their API types from the backend OpenAPI schema with +`bun run gen` (`owner-web`, `owner-admin`, `booking-web`, `rider-app`). Never +hand-edit generated directories (`gen`, `gen_types`). Regenerate and commit the +snapshot instead. + +## Where to ask + +See [SUPPORT.md](SUPPORT.md). diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..92c5edf --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## What + + + +## Verification + +- [ ] Tests, lint, typecheck and build run for the touched repository +- [ ] UI change applied to every surface of the entity (table view, card view, detail page) +- [ ] Cross-repository references are full URLs + +## Notes + + diff --git a/README.md b/README.md index a99831c..f8b6158 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,24 @@ # Ownima/.github -Org-wide defaults and documentation for the [Ownima](https://github.com/Ownima) GitHub organization. +Org-wide defaults and documentation for the [Ownima](https://github.com/Ownima) +GitHub organization. ## Contents -- [`profile/README.md`](profile/README.md) — Organization profile shown on [github.com/Ownima](https://github.com/Ownima) -- [`RELEASING.md`](RELEASING.md) — Release process, Release Please setup, conventional commit guide +- [`profile/README.md`](profile/README.md) — organization profile shown on + [github.com/Ownima](https://github.com/Ownima) +- [`RELEASING.md`](RELEASING.md) — release process and conventional commit guide +- [`CONTRIBUTING.md`](CONTRIBUTING.md) — branches, commits and PR rules +- [`SECURITY.md`](SECURITY.md) — how to report a vulnerability +- [`SUPPORT.md`](SUPPORT.md) — where to ask for help +- [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) — expected behavior + +## Changing the profile + +Open a pull request against `main`. The `profile-links` workflow checks repository +links, live domains and repository coverage on every PR and once a week. ## Issues -Cross-repo and backlog tasks are tracked here as [GitHub Issues](https://github.com/Ownima/.github/issues). +Cross-repo and backlog tasks are tracked here as +[GitHub Issues](https://github.com/Ownima/.github/issues). diff --git a/RELEASING.md b/RELEASING.md index 3e7c7af..400261d 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,30 +1,38 @@ # Releasing -Ownima uses [Release Please](https://github.com/googleapis/release-please) to automate versioning and changelog generation across all repos. +Ownima uses [Release Please](https://github.com/googleapis/release-please) to +automate versioning and changelog generation. ## How it works -Release Please watches commits on `main` and determines the next version from **conventional commit prefixes**: +Release Please watches commits on `main` and derives the next version from +conventional commit prefixes: | Commit prefix | Version bump | Example | -|---------------|-------------|---------| +|---|---|---| | `fix: ...` | patch | `0.2.28` → `0.2.29` | | `feat: ...` | minor | `0.2.28` → `0.3.0` | -| `feat!: ...` or `BREAKING CHANGE:` in body | major | `0.2.28` → `1.0.0` | -| `chore:`, `docs:`, `refactor:`, `ci:`, etc. | none | no release PR created | +| `feat!: ...` or `BREAKING CHANGE:` in the body | major | `0.2.28` → `1.0.0` | +| `chore:`, `docs:`, `refactor:`, `ci:`, … | none | no release PR on its own | On every push to `main` it either: -1. **Creates/updates a release PR** — titled `chore(main): release X.Y.Z` with an auto-generated CHANGELOG -2. **Tags and releases** — when the release PR is merged, it creates the git tag and GitHub Release -## Repos with Release Please +1. creates or updates a release PR titled `chore(main): release X.Y.Z` with an + autogenerated changelog, or +2. tags and releases when that PR is merged. -| Repo | Config | Current version | -|------|--------|----------------| -| `owner-api` | `release-please-config.json` + `.release-please-manifest.json` | see manifest | -| `rider-web` | `release-please-config.json` + `.release-please-manifest.json` | see manifest | +## Repositories -Both use a **GitHub App token** (`OWNIMA_BOT_APP_ID` + `OWNIMA_BOT_PRIVATE_KEY`) instead of `GITHUB_TOKEN` because the org restricts PR creation for Actions. +| Repository | Versioning | +|---|---| +| `owner-api` | `release-please-config.json` + `.release-please-manifest.json` (key `ownima-backend`) | +| `owner-web` | `release-please-config.json` + `.release-please-manifest.json` | +| `booking-web` | `release-please-config.json` + `.release-please-manifest.json` | +| `rider-app` | `release-please-config.json` + `.release-please-manifest.json` | + +They use a GitHub App token (`OWNIMA_BOT_APP_ID` + `OWNIMA_BOT_PRIVATE_KEY`) +instead of `GITHUB_TOKEN`, because the organization restricts PR creation for +Actions. `rider-app` builds and deploys on Vercel from `main`. ## Workflow @@ -41,7 +49,8 @@ push to main ## Tips -- **Force a specific version**: update `.release-please-manifest.json` manually and merge to main — Release Please will pick it up on the next run -- **Skip a release**: add `Release-As: skip` to the release PR description -- **Always patch bumps**: set `"versioning-strategy": "always-bump-patch"` in `release-please-config.json` -- **Non-releasable commits** (`chore:`, `ci:`, `docs:`) do not block a release PR from accumulating — they just don't trigger one on their own +- **Force a version**: put `Release-As: X.Y.Z` as a trailer in a commit on + `main`. Release Please picks it up on the next run. +- **Hold a release**: leave the release PR open; it keeps updating. +- **Non-releasable commits** (`chore:`, `ci:`, `docs:`) do not trigger a + release PR on their own, but they do not reset one that is already open. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..8f42e24 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## Reporting a vulnerability + +Report vulnerabilities through +[GitHub private advisories](https://github.com/Ownima/.github/security/advisories/new). +If you cannot use GitHub, email **contact@ownima.com**. + +Please include: + +- affected repository and version or commit; +- steps to reproduce; +- impact you believe it has; +- any suggested fix. + +Do not open a public issue for a vulnerability. We aim to acknowledge a report +within two working days and to keep you updated until it is resolved. + +## Supported versions + +Only the latest release of each released service is supported. Fixes land on +`main`; where Release Please is configured, they ship in the next release. diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..d66661d --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,28 @@ +# Support + +## Product questions + +Email **contact@ownima.com**. + +## Bugs and feature requests + +Open an issue in the repository that owns the behavior: + +| Area | Repository | +|---|---| +| API, workers, data | `Ownima/owner-api` | +| Owner dashboard | `Ownima/owner-web` | +| Internal admin panel | `Ownima/owner-admin` | +| Rider storefront | `Ownima/booking-web` | +| Rider marketplace | `Ownima/rider-app` | +| Support automation | `Ownima/support-agent` | +| Pricing oracle | `Ownima/pricing-oracle` | +| SEO site | `Ownima/ownima-blog` | +| Infrastructure and deploys | `Ownima/ansible` | +| Workspace guide and skills | `Ownima/ownima-workspace` | + +Use this repository only for cross-repo or organization-level issues. + +## Security + +See [SECURITY.md](SECURITY.md). diff --git a/profile/README.md b/profile/README.md index 599438f..a35a69e 100644 --- a/profile/README.md +++ b/profile/README.md @@ -1,68 +1,94 @@ # Ownima — Vehicle Rental Management Platform -**Empowering rental businesses through modern, scalable technology.** +**One platform for rental businesses and their riders: fleet, reservations, pricing and finance.** --- -## What We Build +## Live products -Ownima is a full-stack vehicle rental platform connecting rental businesses with their customers: +| Product | URL | Audience | +|---|---|---| +| Ownima | [ownima.com](https://ownima.com) | Public site | +| Rider marketplace | [rider.ownima.com](https://rider.ownima.com) | Riders across all owners | +| Booking storefront | [booking.ownima.com](https://booking.ownima.com) | Riders of one owner | +| Owner cabinet | [beta.ownima.com](https://beta.ownima.com) | Rental owners | -| Product | Description | Stack | -|---------|-------------|-------| -| [**Owner API**](https://github.com/Ownima/owner-api) | Backend powering all business logic, REST API, background workers | Python · FastAPI · PostgreSQL · OpenSearch | -| [**Owner Web**](https://github.com/Ownima/owner-web) | Owner dashboard — fleet management, reservations, finance | React 18 · TypeScript · Capacitor (mobile) | -| [**Rider Web**](https://github.com/Ownima/rider-web) | Customer-facing app — vehicle browsing, booking, multilingual | Vue 3 · TypeScript · i18n (EN/RU/TH/VI/ID) | -| [**Admin Panel**](https://github.com/Ownima/ownima-admin) | Internal admin — analytics, user management, operations | React 19 · TypeScript | +--- + +## Platform + +- Three roles: owner, rider, admin, with role-based access control. +- Fleet and vehicle management, images stored in MinIO. +- Reservations with real-time availability and a booking request flow. +- Pricing templates (seasonal, duration-based) and a market pricing oracle. +- Wallet, transactions and financial dashboards. +- Five locales in the rider apps: English, Russian, Thai, Indonesian, Vietnamese. +- Background jobs on a SAQ worker queue. +- AI support drafting and vehicle image recognition. --- -## Infrastructure +## Repositories -``` -PostgreSQL — transactional data (users, wallets, transactions) -OpenSearch — vehicle/reservation documents + event log -Redis — background job queue (SAQ) + metrics cache -MinIO — vehicle images and file uploads -``` +Most product repositories are private; `pricing-oracle` is public. Links work for Ownima members. -Deployed via **Docker + Ansible**. CI/CD on **GitHub Actions**. Releases automated with **Release Please**. +| Repository | Role | Stack | +|---|---|---| +| [owner-api](https://github.com/Ownima/owner-api) `(private)` | REST API, workers, Telegram bot, protobuf schema | Python 3.12 · FastAPI · PostgreSQL · OpenSearch · Redis · MinIO · SAQ | +| [owner-web](https://github.com/Ownima/owner-web) `(private)` | Owner dashboard, Capacitor mobile app | React 19 · TypeScript · TanStack · Tailwind 4 · Vite · bun | +| [owner-admin](https://github.com/Ownima/owner-admin) `(private)` | Internal admin panel | React 19 · TanStack Query · Radix · Tailwind 4 · Vitest · bun | +| [booking-web](https://github.com/Ownima/booking-web) `(private)` | Rider storefront for a single owner, embeddable widget | Nuxt 4 · Vue 3 · Pinia · TanStack Vue Query · Tailwind 4 · bun | +| [rider-app](https://github.com/Ownima/rider-app) `(private)` | Multi-owner rental marketplace | Nuxt 4 · Vue 3 · FSD · Pinia · Tailwind 4 · Vercel | +| [support-agent](https://github.com/Ownima/support-agent) `(private)` | AI support drafting, knowledge base, evals | Python 3.12 · Claude · n8n | +| [pricing-oracle](https://github.com/Ownima/pricing-oracle) | Rental pricing market intelligence | Python 3.12 · FastAPI · SQLModel · A2A · Fetch.ai | +| [ownima-blog](https://github.com/Ownima/ownima-blog) `(private)` | SEO site for the Thailand market | Astro 6 · TypeScript · pagefind · bun | +| [ansible](https://github.com/Ownima/ansible) `(private)` | Infrastructure, deployment, monitoring, runbooks | Ansible · Docker · Prometheus · Grafana · Loki | +| [ownima-workspace](https://github.com/Ownima/ownima-workspace) `(private)` | Workspace guide and shared agent skills | Bash · Markdown | --- -## Key Features - -- Multi-language support: English, Russian, Thai, Vietnamese, Indonesian -- Role-based access control (Owner / Rider / Admin) -- Flexible pricing templates (seasonal, duration-based) -- Real-time availability and reservation management -- Financial dashboards, wallet system, transaction history -- Web + native mobile (iOS/Android via Capacitor) -- Background processing via SAQ worker queue -- MCP server for vehicle image recognition +## Architecture + +```mermaid +flowchart LR + RA[rider-app] --> API[owner-api] + BW[booking-web] --> API + OW[owner-web] --> API + AD[owner-admin] --> API + API --> PG[(PostgreSQL)] + API --> OS[(OpenSearch)] + API --> RD[(Redis / SAQ)] + API --> MI[(MinIO)] + API --> REC[Recognition] + SA[support-agent] --> N8N[n8n] + PO[pricing-oracle] --> API +``` --- -## Development +## For AI agents -Each repo has a `CLAUDE.md` with detailed development guidance. Quick links: +Start at [ownima-workspace](https://github.com/Ownima/ownima-workspace): it holds the +workspace guide and the shared skills. Many repositories carry their own `AGENTS.md` or +`CLAUDE.md` with commands and rules; the workspace guide is the source of truth. + +--- -- **Backend**: `cd owner-api/ownima-backend && docker compose watch` -- **Owner Web**: `cd owner-web && bun dev` -- **Rider Web**: `cd rider-web && bun dev` +## Releasing -See [RELEASING.md](../RELEASING.md) for the release process and conventional commit conventions. +Release Please derives versions from conventional commits. See [RELEASING.md](https://github.com/Ownima/.github/blob/main/RELEASING.md). --- ## Team | Role | GitHub | -|------|--------| +|---|---| | Backend / Architecture | [@zaebee](https://github.com/zaebee) | | Product / QA | [@ownima-ivan](https://github.com/ownima-ivan) | -| Frontend | [@AlexandrovTLG](https://github.com/AlexandrovTLG) · [@ReD1KC](https://github.com/ReD1KC) | +| Frontend | [@ReD1KC](https://github.com/ReD1KC) | --- -🌐 [beta.ownima.com](https://beta.ownima.com) · 📧 support@ownima.com +Contact: **contact@ownima.com** +Security: [private advisories](https://github.com/Ownima/.github/security/advisories/new) diff --git a/scripts/check-profile-links.sh b/scripts/check-profile-links.sh new file mode 100755 index 0000000..ff2491d --- /dev/null +++ b/scripts/check-profile-links.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# Checks profile/README.md: repository links resolve, live domains answer, +# every non-archived org repository is mentioned. +# +# Usage: check-profile-links.sh [--strict] +# --strict a repository link that cannot be resolved is a failure +# (default: warn, because anonymous callers cannot see private repos) +# +# CI runs in soft mode unless OWNIMA_BOT_APP_ID / OWNIMA_BOT_PRIVATE_KEY are +# set on the repository: without an app token, private repositories are not +# visible and the coverage check only sees public repositories. +set -uo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +README="$ROOT/profile/README.md" +STRICT=0 +[ "${1:-}" = "--strict" ] && STRICT=1 + +[ -f "$README" ] || { echo "missing $README" >&2; exit 2; } + +for tool in gh curl; do + command -v "$tool" >/dev/null 2>&1 || { echo "missing required tool: $tool" >&2; exit 2; } +done + +# GET of a single byte, not HEAD: some servers and CDNs answer HEAD with 405. +probe() { + curl -s -o /dev/null -r 0-0 -w '%{http_code}' --max-time 20 "$1" +} + +fail=0 +warn=0 +ok=0 + +echo "== repository links ==" +for name in $(grep -oE 'https://github\.com/Ownima/[A-Za-z0-9._-]+' "$README" | sed 's#.*/##' | sort -u); do + if timeout 30 gh api "repos/Ownima/$name" >/dev/null 2>&1; then + echo " ok $name" + ok=$((ok + 1)) + elif [ "$STRICT" -eq 1 ]; then + echo " FAIL $name does not resolve" + fail=$((fail + 1)) + else + echo " warn $name not visible to this token" + warn=$((warn + 1)) + fi +done + +echo "== live domains ==" +for url in $(grep -oE 'https://([a-z0-9-]+\.)*ownima\.com' "$README" | sort -u); do + code="$(probe "$url")" || code=000 + if [ "$code" = "000" ]; then + sleep 2 + code="$(probe "$url")" || code=000 + fi + case "$code" in + 2*|3*) echo " ok $url $code"; ok=$((ok + 1)) ;; + *) echo " FAIL $url $code"; fail=$((fail + 1)) ;; + esac +done + +echo "== coverage ==" +listed="$(grep -oE 'https://github\.com/Ownima/[A-Za-z0-9._-]+' "$README" | sed 's#.*/##' | sort -u)" +repos="$(timeout 60 gh repo list Ownima --limit 100 --json name,isArchived \ + --jq '.[] | select(.isArchived == false) | .name' 2>/dev/null | sort)" +if [ -z "$repos" ]; then + echo " FAIL could not enumerate org repositories" + fail=$((fail + 1)) +else + for name in $repos; do + [ "$name" = ".github" ] && continue + if printf '%s\n' "$listed" | grep -qx "$name"; then + echo " ok $name" + ok=$((ok + 1)) + else + echo " FAIL $name is not mentioned in profile/README.md" + fail=$((fail + 1)) + fi + done +fi + +echo +echo "ok=$ok warn=$warn fail=$fail" +[ "$fail" -eq 0 ]