A minor wound on the arm of the absurd present.
Nameem is an Arabic-first, right-to-left article publishing platform. Writers publish long-form articles; readers follow authors and topics, like, bookmark, and discuss them in threaded comments.
- Rich article editor built on Lexical (images, video, embeds, dividers)
- Passwordless sign-in with emailed 6-digit codes
- Feeds: latest, trending, picked, and following
- Tags and topics, Arabic-aware search, related articles
- Follows, likes, bookmarks, threaded comments, notifications and email digests
- Per-article analytics for authors
- Admin backoffice for users, articles, comments and tags
- SEO metadata, structured data and sitemaps
- Ruby 4.0 / Rails 8.2 (edge)
- MySQL 8.0
- Hotwire (Turbo + Stimulus), ImportMap, no JS bundler
- Tailwind CSS 3
- Solid Queue for background jobs
- Kamal for deployment
- Ruby (see
.ruby-version); mise or rbenv work well - MySQL 8.0
- A Procfile runner such as Overmind or Foreman
git clone https://github.com/ahyield/nameem.git
cd nameem
cp .env.example .env.development # then fill in your MySQL credentials
bundle install
bin/rails db:prepare
bin/rails db:seed # optional: fake users and articles
bin/devThe app runs at http://localhost:3000.
In development, emails (including sign-in codes) are opened in your browser via letter_opener instead of being sent.
Third-party keys (Resend, AWS S3, Turnstile, digitup) are read from Rails encrypted credentials. The encrypted files in this repo belong to the hosted Nameem instance and can't be decrypted without its keys. To run your own instance, delete them and create your own:
rm config/credentials.yml.enc config/credentials/*.yml.enc
bin/rails credentials:edit --environment developmentExpected structure:
resend:
api_key: ...
webhook_secret: whsec_... # bounce/complaint webhook (see Email below)
mailer:
postal_address: ... # shown in marketing email footers
aws:
access_key_id: ...
secret_access_key: ...
turnstile: # production only; dev/test use Cloudflare test keys
site_key: ...
secret_key: ...
digitup: # optional, production only
rum_key: ...None of these are needed to run the app locally or to run the specs.
Mail goes through Resend. The email settings can also come from environment variables in .env.production, which scripts/deploy.sh loads and Kamal passes to the app (.kamal/secrets-common, env.secret in config/deploy*.yml). A variable that's set wins over the credential:
| Variable | Credential | What it's for |
|---|---|---|
RESEND_API_KEY |
resend.api_key |
Sending email |
RESEND_WEBHOOK_SECRET |
resend.webhook_secret |
Verifying the bounce/complaint webhook |
MAILER_POSTAL_ADDRESS |
mailer.postal_address |
Footer of marketing email (the weekly digest) |
In the Resend dashboard, add a webhook to https://<your host>/webhooks/resend for email.bounced and email.complained. Its signing secret (whsec_...) is RESEND_WEBHOOK_SECRET. Without it the endpoint rejects every call, and bounced addresses keep getting mail.
Preview every email at /rails/mailers in development.
bin/ci runs everything CI runs: RuboCop, ERB lint, ESLint, Brakeman, bundler-audit, the importmap audit, the JavaScript tests and the specs.
bin/ci # the full check, run it before opening a pull request
bundle exec rspec # specs
npm test # JavaScript unit tests (Vitest)Specs need a MySQL database; set MYSQL_USERNAME, MYSQL_ROOT_PASSWORD, DATABASE_HOST and DB_PORT as needed.
Nameem deploys with Kamal. config/deploy.yml holds the shared config and config/deploy.production.yml the production destination. Hosts and secrets are read from .env.production (see .env.example):
scripts/deploy.sh # build and deploy
scripts/migrate_db.sh # run migrations in production
scripts/kamal.sh # production Rails console, or any kamal command:
scripts/kamal.sh proxy reboot -d productionSee CONTRIBUTING.md. To report a security issue, see SECURITY.md.
Nameem is released under the MIT License.
