- JavaScript 82.2%
- CSS 16.9%
- Shell 0.6%
- Dockerfile 0.2%
| android | ||
| client | ||
| data | ||
| deploy | ||
| docker | ||
| docs | ||
| scripts | ||
| server | ||
| shared | ||
| tests | ||
| tools/scenario-sim | ||
| .dockerignore | ||
| .gitignore | ||
| capacitor.config.json | ||
| docker-compose.proxy.yml | ||
| docker-compose.sim.yml | ||
| docker-compose.yml | ||
| package.json | ||
| playwright.config.js | ||
| README.en.md | ||
| README.md | ||
| yarn.lock | ||
Acampatopia
A prototype designed for an in-person community technology and agroecology camp, organized as an unconference with coexistence, workshops, circles (rodas), and collaboration. It is also an exploratory project within a broader initiative called Fractopia.
Part of the guiding context:
- Rural setting,
- Unstable internet,
- Many things happening at once, with no pre-defined schedule,
- People wanting to meet and share interests,
- Knowledge emerging from conversations and activities at any moment,
- Too much richness to fit neatly into chat groups, or to stay isolated in individual notebooks and devices.
The pragmatic proposal is to be a shared space for scheduling, collective notes, and connecting people with common interests — without depending on external internet to function.
It is not an "event management system". It is closer to a collective notebook with just enough structure to amplify what is happening in person.
Above all, this repository is a usability/architecture experiment in a real-world use case, rather than a "ready-made tool" with any pretension of being maintained.
What the app tries to solve
In events like this, communication tends to spread across chat groups and become hard to recover later. The issue isn't just "chatting": it's also about facilitating encounters, organizing context, curation, and shared knowledge.
- "Who ran that morning workshop? I wanted to ask her something but left early..."
- "Who actually knows hardware?"
- "Where did that link/book/note they mentioned yesterday go?"
- "Let's propose a space for people to share fermentation recipes?"
This app tries to facilitate these connections, making it easy to keep these things in one place — with a simple structure that helps with both day-to-day coordination and building collective memory of what was experienced and learned.
It also plays a pedagogical role as a shared experience in a non-commercial, open network, made with care for a specific purpose: not to capture attention, extract data, or become an endless feed — but to support a real context of coexistence.
The idea (and the Fractopian vibe)
Acampatopia is part of the development of Fractopia. It is an exploratory prototype (proof of concept) to test, in a real case, a central idea: treating the system as a layer over data and relationships, where everything can be a node and anything can connect to anything.
This means leaving fewer things rigid upfront and opening space for part of the knowledge organization to emerge from community use. The same base can serve ephemeral experiences (like a few-day gathering) or more continuous contexts (like a neighborhood group), without losing the possibility of inter-community (and inter-system) communication.
The challenge is to make this simple and intuitive: closer to moving boxes, wiring things on a board, and rearranging relationships than to "programming a system". Using this flexibility pragmatically, accessible without limiting the user.
How this shows up in the architecture (summary)
There are two central choices in the project:
- Offline-first
The app needs to remain useful without internet. Each device maintains a local database (SQLite in the browser) and syncs when it finds the camp's local network.
- Graph model (
items+edges)
Instead of creating a different table for each type of thing and relationship, the project uses a more flexible structure:
items= nodes (person, activity, post, message, circle, space...)edges= typed links between nodes (interested_in,member_of,located_at, etc.)ops= operation history used for offline-first sync
This helps connect content without locking the model too early. Example: a post can connect to an activity, which connects to a circle (roda), allowing information to be reorganized without copying/pasting.
Project status
Actively in development.
Already working:
- passphrase authentication (2 words),
- schedule with filters (day, space, "my agenda") and highlight of activities happening now,
- activity detail with interests, participants, and linked notes,
- notes (caderno): collective notebook with day feed, composer with types and references,
- reply threads,
- personal notebook (private notes),
- people (gente): participant list with name and interest search,
- 1:1 chat,
- offline-first sync (local SQLite + ops, incremental push/pull, bootstrap),
- installable PWA,
- navigation with 5 tabs (Circles, Notebook, Schedule, People, Map).
Next steps are described in docs/etapas.md.
Where the project is headed
In the short term, the focus is pragmatic: work well at the event, with simple setup and no dependency on external internet.
In the medium term, the idea is to evolve:
- improve knowledge organization (circles, notes, links, connections)
- strengthen multi-device sync
- make the data model better documented and interoperable
There is also a broader conceptual direction (Fractopia / linked data / interoperability), but without rush: first the app needs to be genuinely useful on the ground at the event.
Stack (summary)
- Client: React + Vite + PWA (
sql.jsin the browser) - Server: Fastify +
better-sqlite3 - Data model: graph in SQL (
items+edges) - Sync: event sourcing with
opstable
Repository structure
.
├── client/ # React PWA app
├── server/ # Fastify API + SQLite
├── shared/ # shared types/constants
├── scripts/ # database, seed, and utility scripts
├── tools/ # scenario simulator (load testing)
├── tests/ # e2e tests (Playwright)
├── docs/ # project documentation
│ ├── etapas.md
│ ├── devlog.md
│ ├── modelo-dados.md
│ └── screenshots/
└── wireframes/ # React wireframes (visual reference)
Prerequisites
- Node.js 20+ (recommended)
- npm
Running locally
1) Install dependencies
npm install
2) Start the server once (to run migrations)
This creates the database and the main tables (items, edges, ops, etc.).
npm run dev:server
You can stop it after the server starts.
3) Seed the database (passphrases + data)
npm run db:init
This command:
- generates passphrases in the database (
passphrases), - exports
passphrases.csv, - creates test data (people, spaces, activities, interests).
4) Run client + server
npm run dev
Addresses:
- Client (Vite):
https://localhost:5173 - Server (API):
http://localhost:3000
Note: Vite uses a local certificate (@vitejs/plugin-basic-ssl), so the browser may show a warning on first access.
Test accounts (seed)
After running npm run db:init, you can log in with any of these passphrases:
ipê+tucano(Marina Silva)aroeira+sabiá(João Pedro)buriti+capivara(Ana Clara)jatobá+quati(Carlos Eduardo)mandacaru+arara(Gabi Santos)pequi+coruja(Dani Rocha)
Useful scripts
# Development
npm run dev # client + server
npm run dev:client # client only
npm run dev:server # server only
npm run dev:lan # client + server accessible on local network (no SSL)
npm run build # client build
npm run preview # build preview + server
# Database
npm run db:init # passphrases + seed (full setup)
npm run db:passphrases # passphrases only
npm run db:seed # data seed only
npm run db:reset:force # delete database and recreate from scratch
npm run access:materials -- --count=200 # generate event access QR codes + sticker sheets + manifest
# Tests
npm run e2e:install # install Chromium for Playwright
npm run e2e # e2e tests
npm run e2e:headed # e2e tests with visible browser
# Scenario simulation (load testing with ~200 participants)
npm run sim:scenario:dev:full # prepare full scenario + start dev
Event access batch generation
To generate an anonymous batch of event accesses with QR codes, printed words, and a printable sticker sheet:
npm run access:materials -- --count=200
Full parameter and printing documentation, including the Pimaco 8099F preset, is available in docs/guia-acessos-etiquetas.md.
How the data model works (brief summary)
The project uses a simple graph model in SQL:
items: anything (person, activity, post, message, circle, space...)edges: relationships between things (interested_in,member_of,located_at, etc.)ops: operation history for offline-first sync
This keeps the model flexible without depending on heavy infrastructure, and works well with SQLite on both the server and in the browser.
The sync uses a third table (ops) to record changes and synchronize between devices and the local server.
More details in docs/modelo-dados.md.
Key files for a quick understanding
docs/CLAUDE.MD: product vision, event context, and design principlesdocs/etapas.md: step-by-step roadmapdocs/devlog.md: decisions and fixes already madedocs/modelo-dados.md: full data model (types, relationships, architecture)docs/plano-sync.md: offline-first sync decisions
Practical notes
- The server database lives at
server/lablab.db. - The client app maintains a local SQLite in the browser (
sql.js) and syncs via API. - To "reset" the browser's local database, logging out already clears the client's local DB.
License
Not yet defined.