DEVSA is the central platform connecting San Antonio's tech community. We bridge the gap between passionate builders, local partners, and the growing tech ecosystem.
🌐 Live Site: www.devsa.community
DEVSA started with a simple question: "Where is the tech community in San Antonio?"
We found 20+ tech-focused organizations scattered across the city, not collaborating and living in their own bubbles. So we built DEVSA to bring them together—a platform where you can discover tech communities that match your interests and where these groups can collaborate, share resources, and grow stronger together.
- Framework: Next.js 16 with App Router (Turbopack)
- Language: TypeScript
- Styling: Tailwind CSS v4
- Animation: Motion, Three.js, Paper shaders
- Database: Google Firestore
- Auth: Firebase Authentication — Google OAuth + email/password
- Email: Resend
- Bot protection: Vercel BotID
- Payments: Stripe
- Merch fulfillment: Printify
- Storage: Vercel Blob
- Deployment: Vercel
git clone https://github.com/devsanantonio/next-devsa.git
cd next-devsa
pnpm install
cp .env.example .env.local # then fill in your keys
pnpm devThe app runs at http://localhost:3000. See .env.example for which variables are required versus optional — most features fail soft when their keys are absent, so you can run the site with just the Firebase and Resend blocks filled in.
After deploying, bootstrap the first admin account. This only works once, while no admins exist:
curl -X POST https://your-domain.com/api/admin/setup \
-H "Content-Type: application/json" \
-d '{"email": "your-email@example.com", "secret": "your_admin_setup_secret"}'Standard Next.js App Router layout — routes in app/, UI in components/, server helpers and third-party clients in lib/, and static seed data in data/.
One thing worth knowing before you start:
Firestore is the source of truth for communities, partners and events, and nothing shadows it. Add or delete one in the admin and every surface follows. data/ holds types and a couple of small seed arrays — no records.
This used to say data/ was a fallback you had to write to as well. It was not a fallback: every surface imported it at module scope and none of them called the API, so the static list was the primary and Firestore was the copy nobody read. The two drifted, and a partner deleted in the admin kept rendering for weeks. Read partners through lib/partners.ts on the server or /api/partners on the client.
Event listings aggregated across member communities, with RSVP capture, calendar feeds (/api/events/feed), and per-event Open Graph images. The primary front door for the community.
A record, not an offer. The room Geekdom hosted closed on 19 September 2026; the page was rewritten in past tense and unlinked from the nav, and its "ping an admin" form and live Discord presence check were removed with it. What is left is the volunteer wall and the thanks to Geekdom, which is why the URL still exists.
Discover 20+ local tech communities and partner organizations.
DEVSA merch, checked out through Stripe and fulfilled by Printify.
Protected dashboard for community organizers — manage events, communities, and admin users. Requires approved admin access recorded in Firestore.
pnpm dev # Dev server (Turbopack)
pnpm build # Production build — the main correctness gate, since there is no broad test suite
pnpm lint # ESLint
pnpm lint:fix # ESLint with autofix
pnpm test:feed # Vitest: events feed contract testWe welcome contributions from the San Antonio tech community.
- Fork the repository on GitHub and clone your fork
- Branch:
git checkout -b feature/your-feature-name - Install:
pnpm install - Develop:
pnpm dev - Check your work:
pnpm lint && pnpm build - Commit with a clear message and push to your fork
- Open a Pull Request against the main repository
Both are managed through the Admin Dashboard, but the static fallback lives in data/communities.ts and data/partners.ts. Add your entry there too, matching the shape of the existing records — the fallback is what renders if Firestore is unreachable.