A production-minded API core for web and mobile products. Authentication, IAM, payments, access control, media, notifications, AI, real-time delivery, background work, administration, and observability stand ready—not as scattered trophies, but as one disciplined system.
Built under a simple creed: clear in thought, exact in structure, simple in use, and strong enough to endure what comes after launch.
API-first · Modular · Observable · Queue-aware · Built to grow
Explore the foundation · Ecosystem Architecture · Development Law · Production Deployment · Analytics Guide · Run it locally · Open the dashboards · Meet the architecture
Important
🏛️ Unified Ecosystem: For the complete cross-platform architecture, feature parity matrix, and communication protocols between Core, Web, and Mobile, see ECOSYSTEM.md.
📜 Constitutional Law: All development must strictly adhere to the architecture, service boundary, and API envelope laws in LAW.md. Zero exceptions.
Every product eventually meets the same old enemies: accounts, permissions, billing, uploads, jobs, notifications, dashboards, audit trails, failures, and the darkness between “it works” and “we know why it works.”. Especially, the real challenge is “it works on my machine.”
Rexone Core exists because this ground should not have to be conquered again for every product.
This is not a chest of disconnected examples wearing the armor of an architecture. It is a cohesive foundation whose parts answer to one another. Stripe payments grant access. Webhooks are durably recorded before background processing begins. Notifications divide into isolated delivery jobs. Asset cleanup retries without making the client wait. Administrators can inspect the realm, while performance, backend errors, frontend failures, queues, cache, and sockets each leave a trail.
The foundation is designed to bend around the product, never to make the product kneel before the framework.
Its boundaries are deliberate and provider-aware. Capabilities can be extended, replaced, or reforged as the product evolves without scattering vendor logic across the codebase.
And no—this was not vibe-coded into existence.
The boundaries were reasoned about. Failure paths were traced. Immediate work was separated from deferred work. Retries, idempotency, observability, security, and data lifecycle were treated as engineering concerns, not decorations added after the demo survived.
Rexone Core brings startup speed with battle-tested discipline—and fewer final-hour whispers of “we should probably build that before launch.”
Rexone Core follows a simple doctrine:
Clarity before cleverness. Precision before haste. Simplicity without weakness. Strength without spectacle.
Years of building software teach the same lesson as any long campaign: the first victory is easy to celebrate; surviving everything that follows is the true test.
The difficult part is rarely another controller or CRUD endpoint. It is preserving a system that remains understandable when the product grows, integrations multiply, failures arrive from unfamiliar directions, and the original developer is no longer the only one carrying the blade.
So the ambition was never to build the largest foundation possible.
It was to build a clear one—strong enough to carry ambitious products, flexible enough to surrender its shape to them, and disciplined enough that the next developer can enter the codebase without a map drawn in blood.
No prophecy. No magic. No shortcuts disguised as momentum.
Just deliberate engineering, tested boundaries, and a foundation built to remain standing.
| Foundation | What is ready | Details |
|---|---|---|
| Identity | Devise, JWT, confirmation, recovery, Google sign-in, platform sessions | Authentication & security |
| Authorization | Roles, permissions, user-role and role-permission assignments | IAM & access control |
| Commerce | Stripe Checkout, products, transactions, subscriptions, access grants | Payments & entitlements |
| Async work | Solid Queue, dedicated queues, retries, concurrency controls, recurring cleanup | Background processing |
| Notifications | Socket, push, and email coordination through OneSignal and Action Cable | Notifications & real time |
| Media | Garage S3/Cloudinary/local storage, underground silent compression (libvips/FFmpeg), optimal-first flow | Storage & assets |
| Speech | Synchronous & async TTS (MP3 binary stream), batch STT, live audio WebSocket streaming (Azure/Nova) | Speech capabilities |
| AI | Durable queued chat, persisted history, completion alerts, and language tools | AI capabilities |
| Localization | Request-scoped English and Myanmar responses with modular domain translations | Localization |
| Data lifecycle | PostgreSQL, global soft deletion, actor-aware auditing, JSON:API serialization | Data & API design |
| Operations | Performance, errors, client logs, queues, cache, cable, health checks | Observability |
| Administration | Administrate for Server plus Client Admin API for users, IAM, products, chat, assets, notifications | Administration |
| Delivery | Docker images, 5-container topology (API/waka/media/db/garage), graceful shutdown | Deployment |
| Quality | RSpec, factories, security scanning, dependency auditing, linting | Quality toolchain |
Rexone Core keeps framework concerns conventional and integrations replaceable.
Controllers own HTTP contracts, models own data rules, services own business and provider boundaries, jobs own deferred work, and serializers own response representation.
flowchart LR
Clients[Web & mobile clients] --> API[Rails API]
Clients <-->|Action Cable| Realtime[Solid Cable]
API --> Auth[Authentication & IAM]
API --> Domain[Product domain]
API --> Services[Service interfaces]
API --> Jobs[Solid Queue]
Domain --> PostgreSQL[(PostgreSQL)]
Auth --> PostgreSQL
Jobs --> PostgreSQL
Services --> Stripe[Stripe]
Services --> OneSignal[OneSignal]
Services --> Storage[Garage S3 · Cloudinary]
Services --> DeepSeek[DeepSeek]
Services --> Speech[Nova · Azure Speech]
Jobs --> Services
Jobs --> MediaWorker[Media Worker · libvips/FFmpeg]
API --> Observability[Pulse · RED · client logs]
Provider-facing code lives behind focused clients such as PaymentService::Client, StorageService::Client, AiService::Client, SpeechService::Client, and the notification delivery services.
Swapping or extending a provider does not require spreading vendor logic across controllers.
The same principle applies to product-specific functionality: the foundation provides the structure, while the product remains free to define its own domain, workflows, and experience.
Solid Queue is part of the application architecture, not an afterthought.
The foundation currently queues work where it benefits from durability, isolation, retries, or provider independence:
| Work | Queue | Why |
|---|---|---|
| Stripe webhook processing | payments |
Durable ingestion, idempotency, retries, and concurrency safety |
| Socket, push, and email delivery | notifications |
Provider latency must not delay the originating request |
| Image & video compression | media |
Dedicated worker (libvips/FFmpeg) isolating heavy media compute |
Production workers are separated by workload in config/queue.yml, and recurring maintenance lives in config/recurring.yml.
The queue architecture is intentionally extensible. As a product grows, new workloads can be introduced as dedicated queues with their own concurrency, retry, and execution policies rather than turning the background layer into one undifferentiated worker.
The exact queue structure can also be customized around the requirements of the product being built.
The API and worker run as separate services in Docker, keeping request handling and background execution independently scalable.
- Devise authentication with JWT issuance and revocation.
- Email/password registration, confirmation codes, password recovery, locking, tracking, and timeout support.
- Google sign-in with a challenge flow for completing account creation.
- Profile management and identity inspection supporting atomic name and username updates with validation.
- Platform-aware active sessions backed by the application cache.
- Rack Attack throttling for abusive or excessive requests.
- Configurable CORS and Rails security defaults.
- Consistent authentication failures and localized client-facing messages.
Authentication is ready for multiple clients without forcing browser-session assumptions onto an API product.
Authorization is modeled explicitly instead of being buried in controller conditionals:
- Users receive roles through
Iam::UserRole. - Roles receive resource/action permissions through
Iam::RolePermission. - Permissions cover operations such as
create,read,update, anddelete. - Three-Tier Administrative Hierarchy & Permission Scoping:
super_admin: Full, unrestricted authority across all resources, endpoints, and IAM governance.admin: Full operational authority across domain resources (feedbacks,payments,ai,assets,logs), strictly restricted from managingusersandiam.- Partial admins (
*_adminnaming convention): Roles named with the_adminsuffix (e.g.feedback_admin,payment_admin) granted to users with the baseuserrole. - Permission Provenance & Endpoint Scoping:
/v1/admin/*Endpoints: Require an admin role (a role whose name containsadmin) that explicitly grants the required CRUD permission. Permissions inside non-admin roles (such as the baseuserrole) cannot grant access to/v1/admin/*./v1/*Endpoints: Permissions in an admin role (e.g.read_usersinuser_admin) grant access to both/v1/usersand/v1/admin/users, whereas permissions in standard user roles only grant access to/v1/users.
- New users receive the default user role automatically.
This gives small products a sensible starting policy and growing products a clean path to granular authorization.
Stripe integration covers the full commercial loop:
- Product and price synchronization.
- Checkout Sessions for one-time purchases and subscriptions.
- Customer creation and reuse.
- Transactions, payment-method metadata, and subscription lifecycle state.
- Cancellation-at-period-end and subscription resumption.
- Access grants and revocation driven by payment state.
- Persisted webhook events with duplicate protection, processing state, attempts, errors, retention, and admin visibility.
- Background webhook processing with targeted retries and per-event concurrency control.
The important distinction is deliberate: customer-facing payment flows remain responsive, while webhook fulfillment is durable and asynchronous for the business.
NotificationService coordinates three independent delivery paths:
- Action Cable broadcasts for live in-product updates and persistent inbox storage.
- Push notifications (e.g. OneSignal).
- Transactional and marketing email delivery.
Each enabled channel receives its own Solid Queue job. A failed email therefore does not repeat a successful push, and a notification provider outage does not roll back a completed payment or authentication action.
-
Persistent In-App Notifications (
user_notifications):- In-app socket broadcasts are persisted to
user_notificationsas immutable historical receipts (title,message,link,data,read_at). - Subsequent admin template alterations never rewrite historical inbox receipts received by users.
- Endpoints:
-
GET /v1/notifications— Paginated inbox list (Pagy 20 items, supportsfilter=all|unread|read). -
GET /v1/notifications/unread_count— Total unread count for real-time badge counters without fetching full lists. -
PUT /v1/notifications/:id/read— Marks an individual notification as read. -
PUT /v1/notifications/read_all— Marks all unread notifications as read. -
DELETE /v1/notifications/:id— Soft-deletes an individual notification from the user inbox.
-
- In-app socket broadcasts are persisted to
-
Multi-Channel Notifications (
notifications):- Database-backed multi-channel notifications supporting dynamic variable interpolation (
{{user_name}},{{user_email}}, custom variables). - Provider-agnostic identifiers (
push_template_id,email_template_id) decouple notifications from external delivery vendors. - Admin management endpoints:
-
GET /v1/admin/notifications— List and filter notifications with pagination and search. -
GET /v1/admin/notifications/:id— Read single notification details. -
POST /v1/admin/notifications— Create custom marketing and broadcast notifications. -
PUT /v1/admin/notifications/:id— Update notification content across In-App, Push, and Email channels. -
DELETE /v1/admin/notifications/:id— Soft-delete notification. -
POST /v1/admin/notifications/:id/undiscard— Restore soft-deleted notification. -
POST /v1/admin/notifications/dispatch— Broadcast dispatch to confirmed users holding selected roles, specific user IDs, or the full confirmed audience.
-
- Database-backed multi-channel notifications supporting dynamic variable interpolation (
-
Automated Retention Cleanup (
Notification::CleanupJob):- Daily maintenance job scheduled at 2:30am via
config/recurring.yml:- Purges read notifications older than 30 days (
AppConfig::NOTIFICATION_READ_RETENTION_DAYS = 30). - Purges unread notifications older than 90 days (
AppConfig::NOTIFICATION_UNREAD_RETENTION_DAYS = 90). - Purges discarded notifications older than 7 days (
AppConfig::NOTIFICATION_DISCARDED_RETENTION_DAYS = 7).
- Purges read notifications older than 30 days (
- Daily maintenance job scheduled at 2:30am via
-
Cumulative Lifetime Notification Metrics:
-
UserNotificationmaintainssent_countandread_countcounters onNotificationatomically in real-time via transactional lifecycle callbacks on notification creation, individual reading, and bulk read-all operations. - Because
Notification::CleanupJobroutinely purges older inbox receipts, notification metrics are strictly cumulative lifetime telemetry and are intentionally decoupled from recount queries to prevent retention-induced data loss.
-
-
Data Synchronization Pipeline (
DataSyncService&DataSyncJob):- Provides an extensible background reconciliation framework (
DataSyncJob$\rightarrow$ DataSyncService.sync_all!) scheduled viaconfig/recurring.ymlusingDATA_SYNC_SCHEDULE(defaults to weekly:"at 3:00am every Sunday", configurable via environment) for periodic synchronization of non-lossy resources and caches.
- Provides an extensible background reconciliation framework (
The admin- and permission-protected POST /v1/admin/notifications/dispatch contract is ready for the dashboard to send custom content to confirmed users holding selected roles—or to the full confirmed audience—through any combination of socket, push, and email. Users with several selected roles are included only once. Audience fanout runs in the notifications queue, while each resulting channel delivery keeps its own retry boundary. Sensitive confirmation or password-reset workflows are never exposed as admin-selectable presets.
The storage abstraction defaults to Garage (self-hosted S3-compatible distributed object storage on port 3100) with full fallback support for Cloudinary and local filesystem storage. Read the complete Garage Guide for architecture, configuration, and UI tooling.
- Hierarchical S3 Key Structure:
- Admin uploads:
admin/{type}_{name}_{timestamp}.{ext} - User uploads:
user/{user_id}/{type}_{name}_{timestamp}.{ext} - Google avatar imports:
user/{user_id}/avatar_google_{timestamp}.{ext} - Environment Storage Partitions (
S3_FOLDER_PREFIX): Garage automatically partitions new storage keys by Rails environment—dev/for development,uat/for UAT/staging, andprod/for production—withS3_FOLDER_PREFIXavailable as an explicit override. Partition handling belongs exclusively to Garage; asset records and admin database queries remain environment-agnostic and cover the complete assets table.
- Admin uploads:
- Zero-Footprint Storage In-Place Rename: When an administrator updates an asset's
typevia the Admin Portal, the backend dynamically moves the storage object (StorageService::Client.move(old_key, new_key)) without creating duplicate or orphaned files in Garage. - Storage & VPS Capacity Monitoring: The super-admin-only
GET /v1/admin/assets/storage_statsendpoint polls the Garage Admin API (S3_ADMIN_ENDPOINT=http://garage:3101,S3_ADMIN_TOKEN=...) and reports bucket/VPS capacity, actual and database-tracked object/byte usage for eachdev/,uat/, andprod/Garage partition, plus complete database asset totals. It triggers proactive low-disk alerts when free disk space falls below 15%. - Automated Backup Scripts:
scripts/backup_db.sh: Automated PostgreSQL database dumps with 7-day rolling retention.scripts/backup_garage.sh: Automated Garage metadata & block backups with 7-day rolling retention.scripts/backup_all.sh: Unified single-command backup runner configured for cron automation.
- Empty Recycle Bin (
DELETE /v1/admin/assets/bin): Hard-purges all discarded assets (Asset.purge_and_destroy_all!) and immediately removes backing objects from Garage S3 / Cloudinary storage without orphaned files. - Batch Operations:
POST /v1/admin/assets/batch_discard: Multi-select soft-deletion (discards multiple active assets to recycle bin viadiscard_batch).POST /v1/admin/assets/batch_undiscard: Multi-select restoration (restores multiple discarded assets viaundiscard_batch).POST /v1/admin/assets/batch_destroy: Multi-select permanent purging (hard-deletes selected assets and immediately purges backing objects from Garage S3 viadestroy_batch).- All lifecycle actions map cleanly:
destroy_bin,destroy_batch,discard_batch, andundiscard_batchresolve uniformly under:deletepermission in authorization.
- Unified Asset Lifecycle: Uploads return the URL and metadata the client needs immediately while retaining provider identifiers, category, media type, extension, size, source, and ownership.
- Default Self-Hosted Storage:
STORAGE_PROVIDER=garageuses the officialaws-sdk-s3client connected to the local or production Garage daemon (http://garage:3100/http://localhost:3100). - Instant Clean Purge: Storage deletion executes directly (
StorageService::Client.delete) upon record destruction commit, ensuring storage objects are permanently cleaned without orphan drift. - Provider Switching: Easily switch between
garage(S3),cloudinary, orlocalviaSTORAGE_PROVIDERwithout code changes.
When the media container is enabled (MEDIA_CONTAINER_ENABLED=true), uploaded assets run through an isolated, background media optimization pipeline:
-
Isolated Worker (
mediacontainer): CPU- and memory-intensive media processing runs on a dedicated Solid Queue worker (config/queue.media.yml), completely isolating image/video compression from API requests and transactional jobs. -
Image Compression (
Media::CompressImageJob): Powered bylibvipswith smart palette quantization (palette: true, dynamic Q factor), dimension constraints (IMAGE_MAX_WIDTH,IMAGE_MAX_HEIGHT), and format-specific optimizations across JPEG, PNG, and WebP. -
Video Compression (
Media::CompressVideoJob): Powered byffmpeg(libx264,aac) with adaptive CRF tuning, dimension constraints, bitrate caps (VIDEO_MAX_BITRATE), and audio stream optimization. -
Optimal-First Flow:
- If initial compression yields no improvement or reduction is negligible (
< 3%), the pipeline immediately marks the asset asoptimalwithout incrementing cache counters or scheduling redundant passes. - If meaningful reduction is achieved, the pass counter increments with a fallback safety cap of 2 passes (
MAX_COMPRESSION_PASSES = 2).
- If initial compression yields no improvement or reduction is negligible (
-
Real-Time Cable Broadcasts: Status changes (
pending$\rightarrow$ processing$\rightarrow$ readyoroptimal), updated file sizes, and compression ratios broadcast in real-time over ActionCable (NotificationChannel) to connected clients. -
Upload Boundaries (
MAX_NON_VIDEO_SIZE_MB&MAX_VIDEO_SIZE_MB):- Dynamically conditioned on
MEDIA_CONTAINER_ENABLEDand configurable viaMEDIA_MAX_NON_VIDEO_SIZE_MBandMEDIA_MAX_VIDEO_SIZE_MB. -
With Media Container (
MEDIA_CONTAINER_ENABLED=true): Defaults to 10 MB for images/non-videos and 100 MB for videos. -
Without Media Container (
MEDIA_CONTAINER_ENABLED=false): Defaults to 1 MB for images/non-videos and 10 MB for videos. - Server-side validation cleanly returns a localized 422 error if files exceed configured limits.
- Dynamically conditioned on
The DeepSeek-backed AI layer provides:
- Durable conversational work through Solid Queue's dedicated
aiqueue. - Persisted rooms, user messages, processing state, and assistant responses—the browser never owns the lifetime of the work.
- Immediate acknowledgement while the AI continues in the background, with one in-flight request allowed per room.
- Safe retries, per-message concurrency control, idempotent completion, and visible failure state.
- Real-time completion and failure alerts through the existing notification socket channel.
- Optional push and email delivery through the same notification path by enabling the existing channel flags.
- Summarization.
- Translation.
- Sentiment, entity, keyword, and general analysis prompts.
- A provider-neutral client boundary for future AI backends.
- Safe client errors with detailed provider failures retained in server logs.
The user can leave the chat, browse elsewhere, close the browser, or shut down the device without interrupting generation. The completed assistant message is committed to conversation history before notification delivery begins, so it is already waiting when the user returns—even if no live socket was present to receive the alert.
The AI layer remains isolated behind its provider boundary so product-specific workflows can evolve without coupling the rest of the application to a single model provider.
The unified speech infrastructure provides both synchronous utilities and real-time streaming audio capabilities:
- Text-to-Speech (TTS):
- Synchronous binary audio streaming (
POST /v1/speech/tts) returning raw MP3 data without base64 wrapper overhead. - Asynchronous background TTS synthesis for chat messages (
POST /v1/speech/ttswithmessage_id). - Durable background processing via
Speech::ProcessTtsJobon the dedicated:aiqueue with retry logic and per-message concurrency limits. - Automated Cloudinary audio storage and polymorphic
Assetattachment to chat messages. - Real-time
tts_readyandtts_failedcompletion alerts broadcast over ActionCable (NotificationChannel).
- Synchronous binary audio streaming (
- Speech-to-Text (STT):
- Synchronous transcription (
POST /v1/speech/stt) accepting either multipart audio file uploads or remoteaudio_urlreferences. - Real-time live audio transcription over WebSocket via
SpeechLiveChannel, streaming PCM audio chunks directly to Azure Speech live recognition sessions.
- Synchronous transcription (
- Provider Architecture:
SpeechService::Clientexposes the generic domain interface while isolating provider specifics behindNovaSpeech(batch REST STT/TTS) andAzureSpeech(SSML REST TTS & live WebSocket STT).
- PostgreSQL with UUID primary keys for application records.
- Global soft deletion through Discard, with kept records as the default scope.
- Actor-aware creation, update, discard, and restore auditing through
Current.auditor. - JSON:API serializers for stable resource representation.
- A consistent response envelope (
status,message,data,error,meta.pagination) across all standard endpoints. - Pagy-backed offset pagination unified across all collection and list endpoints.
- Intentionally namespaced constants organized by domain in
app/constants/(AiConstants,PaymentConstants,AccessConstants,AssetConstants,AuthConstants,NotificationConstants). - Versioned client routes under
/v1and a separate admin API namespace. - Modular I18n-backed client messages, organized by product domain.
- OpenAPI documentation served through Rswag.
Client-facing messages are organized by domain through MessageService and Rails I18n instead of being collected in one global constants file. English (en) and Myanmar (my) are included, with English as the safe fallback.
The API selects a locale for each request in this order:
- Query parameter:
?locale=my - Explicit header:
X-Locale: my - Standard header:
Accept-Language: my-MM - Default:
en
Locale switching is request-scoped through I18n.with_locale, preventing one request's language from leaking into another under concurrent execution. Adding another language means mirroring the modular files in config/locales and registering its locale code.
Backend, frontend, synchronous, and asynchronous failures leave different clues. Rexone Core gives each one a proper home.
- Rails Pulse tracks request, query, and background-job performance with configurable thresholds.
- Rails Error Dashboard captures, groups, analyzes, and retains backend exceptions. Optional Slack, email, Discord, PagerDuty, and webhook alerts are supported but disabled by default.
- Client Logs accept structured errors from web and mobile clients, including stack traces, platform/device context, severity, occurrences, and resolution state.
- Solid Web UI exposes queue, cache, and cable operations.
- Health checks are available at
/upfor containers and load balancers.
That is full-stack visibility without requiring an external observability platform on day one.
The server-rendered Administrate workspace manages users, assets, access grants, IAM, payments, webhook events, chat data, and client logs.
Admin authentication uses application users over HTTP Basic and requires an admin or super_admin role.
A separate /v1/admin namespace supports the web admin client, exposing versioned endpoints for:
- User management: CRUD, search, discard/undiscard, role assignment, self-lifecycle protection, and last-super-admin guard.
- IAM management: Role management with permission matrix and permission CRUD with auto-generated names.
- Chat moderation: Chat rooms and messages CRUD operations.
- Product management: Stripe synchronized products with discard/undiscard operations.
- Notifications: Broadcast dispatch with template catalog, multi-channel dispatch, and audience targeting (by roles, users, or all).
- RSpec, FactoryBot, Shoulda Matchers, Faker, and Database Cleaner.
- RuboCop Rails Omakase for consistent Ruby and Rails style.
- Brakeman for Rails security analysis.
- Bundler Audit for dependency vulnerability checks.
- Guard RSpec for rapid local feedback.
- Rswag request specifications for OpenAPI generation.
Operational dashboards are mounted in the application and protected by admin authentication. API documentation and the health endpoint are listed alongside them for convenience.
| Path | Purpose |
|---|---|
/admin |
Administrate resource management |
/admin/pulse |
Request, query, and job performance |
/admin/red |
Backend errors and diagnostics |
/admin/queue |
Solid Queue inspection and control |
/admin/cache |
Solid Cache inspection |
/admin/cable |
Solid Cable inspection |
/api-docs |
Swagger/OpenAPI documentation |
/up |
Application health check |
Client-side errors are accepted at POST /v1/log/clients and managed from the admin area.
Docker is the quickest and most reproducible path.
- Docker with Docker Compose
- Git
For a native installation, use Ruby 4.0.4, PostgreSQL, libvips, and Bundler 4.0.16.
git clone https://github.com/rex-9/rexone-core.git
cd rexone-core
cp .env.example .envFill in the required database, JWT, Stripe, OneSignal, DeepSeek, and Cloudinary values in .env.
Development placeholders are fine for providers you are not exercising, but never ship placeholder secrets.
docker compose -f docker-compose.dev.yaml up --buildThis starts the 5-container ecosystem:
api— Rails API on http://localhost:3000waka— General Solid Queue background worker (payments, notifications, AI, speech)db— PostgreSQL 18 on port 5432media— Dedicated Solid Queue worker for:mediaqueue (libvips / FFmpeg compression)garage— Self-hosted S3-compatible object storage on http://localhost:3100 (Admin on port 3101)
The development entrypoint runs db:prepare when the API starts.
If you prefer separate terminals, the repository includes dedicated scripts:
./scripts/dev_db.sh # PostgreSQL database container
./scripts/dev_api.sh # Rails API server
./scripts/dev_waka.sh # General background worker
./scripts/dev_media.sh # Dedicated media compression worker
./scripts/dev_garage.sh # Garage S3 storage servicedocker compose -f docker-compose.dev.yaml exec api bin/rails db:seedThe seed file creates the default roles, permissions, assignments, and development admin accounts.
Review and replace seeded credentials before using them outside local development.
# Rails console
./scripts/console.sh
# Generate OpenAPI output
./scripts/rswag.sh
# Run the repository test script (RSpec)
./scripts/test.sh
# Continuous Integration (GitHub Actions)
# Automated PR workflow (.github/workflows/test.yml) executes:
# 1. Syntax & autoload verification: bin/rails zeitwerk:check
# 2. Test database preparation: bin/rails db:test:prepare
# 3. RSpec test suite (excluding system/e2e specs): bundle exec rspec --tag ~type:system --tag ~e2e
# Automated Backups
./scripts/backup_all.sh # Backs up both PostgreSQL and Garage S3 storage
./scripts/backup_db.sh # Backs up PostgreSQL database (.sql.gz)
./scripts/backup_garage.sh # Backs up Garage S3 metadata and data volumes (.tar.gz)
# Watch specs
./scripts/test_watch.sh
# Run Rails security analysis
bin/brakeman
# Run linting
bin/rubocopThe checked-in .env.example documents the available settings.
The important groups are:
- Centralized Application Configuration: All environment variables are validated, given safe defaults, and mapped to constants in
config/app_config.rb(AppConfig::*), preventing string typos and runtime drift across environments. - Rails environment, URLs, logging, threads, ports, and secrets (
PORT,RAILS_SECRET_KEY_BASE,RAILS_MASTER_KEY). - PostgreSQL connection, connection pools (
DB_POOL,API_DB_POOL,WAKA_DB_POOL,MEDIA_DB_POOL), and Docker service names. - JWT/session, confirmation, and password-reset lifetimes.
- Stripe credentials, webhook secret, and redirect URLs.
- OneSignal application, API key, sender, and sound configuration.
- DeepSeek AI API URL, key, and model.
- Speech services: Azure Speech (key, region) and Nova Speech (key, endpoint) for TTS/STT.
- Storage & S3:
STORAGE_PROVIDER(garage,cloudinary,local), S3 endpoints, credentials, and bucket. - Media compression:
MEDIA_CONTAINER_ENABLED, upload size limits (MEDIA_MAX_VIDEO_SIZE_MB,MEDIA_MAX_NON_VIDEO_SIZE_MB), video profile (CRF, preset, bitrate, resolution), and image profile (JPEG/PNG/WebP quality, compression). - Solid Queue process, supervisors (
SOLID_QUEUE_IN_PUMA), and shutdown settings (SOLID_QUEUE_SHUTDOWN_TIMEOUT). - Observability & Error Dashboard:
DASHBOARD_BASE_URL,APP_VERSION,GIT_SHA.
Keep real credentials in your deployment platform or encrypted secret store—not in Git.
The API is broader than a starter CRUD demo. Its main route families are:
| Area | Representative routes |
|---|---|
| Authentication | /signup, /signin, /signin/google, /confirmation/*, /password/* |
| Users | /v1/users/* |
| IAM | /v1/iam/* |
| Admin API | /v1/admin/* |
| Payments | /v1/payment/*, /webhooks/stripe |
| Entitlements | /v1/access/* |
| Media | /v1/media/upload |
| Notifications | /v1/admin/notifications |
| AI | /v1/ai/* |
| Speech | /v1/speech/*, SpeechLiveChannel (WS) |
| Client telemetry | /v1/log/clients |
Use /api-docs for the interactive OpenAPI view and config/routes.rb for the authoritative route map.
The production image is multi-stage, runs as a non-root user, precompiles Bootsnap, includes health-check dependencies, and prepares the database when the API container starts.
docker-compose.yaml separates the API, Solid Queue worker, and PostgreSQL services with health checks and restart policies.
The same image can also be deployed through Kamal or another container platform.
Before production:
- Supply real secrets through the deployment environment.
- Use strong, unique admin credentials and remove development seed accounts.
- Configure Stripe webhook signing and provider callback URLs.
- Run the API and
bin/jobsworker as separate processes. - Confirm database pool sizing against API threads and queue concurrency.
- Put TLS and a trusted reverse proxy in front of the application.
- Review retention, throttling, alerting, and backup policies for your product.
- Rexone Web — web client
- Rexone Mobile — mobile client
Rexone Core serves as the master rebranding engine for the entire ecosystem:
# 1. Rebrand all 3 repositories from rexone-core:
./scripts/rebrand.sh brand.config.json
# 2. Local environment variables in .env:
APP_NAME="My New App Name"
DEFAULT_MAIL_SENDER="no-reply@mynewapp.com"This API core is built on top of the Rexone Ecosystem (rex-9). When creating derivative products or white-label backends:
- Developers and creators are warmly encouraged to preserve ecosystem credit in documentation to support the project.
- All development must strictly adhere to the constitutional engineering standards in LAW.md and ECOSYSTEM.md.
If Rexone Core saves you a few weeks—or saves you from one memorable production incident—consider giving it a star. 🌟
Built with Clarity & Simplicity Driven Development, by Rex (Rex9).
A software engineer, full-stack architect, and long-time practitioner of meditation.
I build systems the same way I approach the path itself: with a clear mind, deliberate steps, and no unnecessary weight.
Built with ❤️ by Rex9 on Rexone Ecosystem